summaryrefslogtreecommitdiff
path: root/gr-digital/lib/constellation.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gr-digital/lib/constellation.cc')
-rw-r--r--gr-digital/lib/constellation.cc153
1 files changed, 150 insertions, 3 deletions
diff --git a/gr-digital/lib/constellation.cc b/gr-digital/lib/constellation.cc
index 2c70bb0944..ff86531f0f 100644
--- a/gr-digital/lib/constellation.cc
+++ b/gr-digital/lib/constellation.cc
@@ -33,6 +33,7 @@
#include <stdlib.h>
#include <float.h>
#include <stdexcept>
+#include <boost/format.hpp>
namespace gr {
namespace digital {
@@ -48,7 +49,9 @@ namespace gr {
d_constellation(constell),
d_pre_diff_code(pre_diff_code),
d_rotational_symmetry(rotational_symmetry),
- d_dimensionality(dimensionality)
+ d_dimensionality(dimensionality),
+ d_lut_precision(0),
+ d_lut_scale(0)
{
// Scale constellation points so that average magnitude is 1.
float summed_mag = 0;
@@ -59,7 +62,7 @@ namespace gr {
}
d_scalefactor = constsize/summed_mag;
for (unsigned int i=0; i<constsize; i++) {
- d_constellation[i] = d_constellation[i]*d_scalefactor;
+ d_constellation[i] = d_constellation[i]*d_scalefactor;
}
if(pre_diff_code.size() == 0)
d_apply_pre_diff_code = false;
@@ -233,10 +236,154 @@ namespace gr {
}
+ void
+ constellation::gen_soft_dec_lut(int precision, float npwr)
+ {
+ max_min_axes();
+ d_lut_scale = powf(2.0, static_cast<float>(precision));
+ float xstep = (d_re_max - d_re_min) / (d_lut_scale-1);
+ float ystep = (d_im_max - d_im_min) / (d_lut_scale-1);
+ d_soft_dec_lut.clear();
+
+ float y = d_im_min;
+ while(y < d_im_max) {
+ float x = d_re_min;
+ while(x < d_re_max) {
+ gr_complex pt = gr_complex(x, y);
+ d_soft_dec_lut.push_back(calc_soft_dec(pt, npwr));
+ x += xstep;
+ }
+ y += ystep;
+ }
+
+ d_lut_precision = precision;
+ }
+
+ std::vector<float>
+ constellation::calc_soft_dec(gr_complex sample, float npwr)
+ {
+ int M = static_cast<int>(d_constellation.size());
+ int k = static_cast<int>(log10f(static_cast<float>(M))/log10f(2.0));
+ std::vector<float> tmp(2*k, 0);
+ std::vector<float> s(k, 0);
+
+ float scale = d_scalefactor*d_scalefactor;
+
+ for(int i = 0; i < M; i++) {
+ // Calculate the distance between the sample and the current
+ // constellation point.
+ float dist = powf(std::abs(sample - d_constellation[i]), 2.0f);
+
+ // Calculate the probability factor from the distance and
+ // the scaled noise power.
+ float d = expf(-dist / (2.0*npwr*scale));
+
+ for(int j = 0; j < k; j++) {
+ // Get the bit at the jth index
+ int mask = 1 << j;
+ int bit = (d_pre_diff_code[i] & mask) >> j;
+
+ // If the bit is a 0, add to the probability of a zero
+ if(bit == 0)
+ tmp[2*j+0] += d;
+ // else, add to the probability of a one
+ else
+ tmp[2*j+1] += d;
+ }
+ }
+
+ // Calculate the log-likelihood ratio for all bits based on the
+ // probability of ones (tmp[2*i+1]) over the probability of a zero
+ // (tmp[2*i+0]).
+ for(int i = 0; i < k; i++) {
+ s[k-1-i] = (logf(tmp[2*i+1]) - logf(tmp[2*i+0])) * scale;
+ }
+
+ return s;
+ }
+
+ void
+ constellation::set_soft_dec_lut(const std::vector< std::vector<float> > &soft_dec_lut,
+ int precision)
+ {
+ max_min_axes();
+
+ d_soft_dec_lut = soft_dec_lut;
+ d_lut_precision = precision;
+ d_lut_scale = powf(2.0, static_cast<float>(precision));
+ }
+
+ bool
+ constellation::has_soft_dec_lut()
+ {
+ return d_soft_dec_lut.size() > 0;
+ }
+
+ std::vector<float>
+ constellation::soft_decision_maker(gr_complex sample)
+ {
+ if(has_soft_dec_lut()) {
+ float xre = sample.real();
+ float xim = sample.imag();
+
+ float xstep = (d_re_max-d_re_min) / d_lut_scale;
+ float ystep = (d_im_max-d_im_min) / d_lut_scale;
+
+ float xscale = (d_lut_scale / (d_re_max-d_re_min)) - xstep;
+ float yscale = (d_lut_scale / (d_im_max-d_im_min)) - ystep;
+
+ xre = floorf((-d_re_min + std::min(d_re_max, std::max(d_re_min, xre))) * xscale);
+ xim = floorf((-d_im_min + std::min(d_im_max, std::max(d_im_min, xim))) * yscale);
+ int index = static_cast<int>(d_lut_scale*xim + xre);
+
+ int max_index = d_lut_scale*d_lut_scale;
+ if(index > max_index) {
+ return d_soft_dec_lut[max_index-1];
+ }
+
+ if(index < 0)
+ throw std::runtime_error("constellation::soft_decision_maker: input sample out of range.");
+
+ return d_soft_dec_lut[index];
+ }
+ else {
+ return calc_soft_dec(sample);
+ }
+ }
+
+ void
+ constellation::max_min_axes()
+ {
+ // Find min/max of constellation for both real and imag axes.
+ d_re_min = 1e20;
+ d_im_min = 1e20;
+ d_re_max = -1e20;
+ d_im_max = -1e20;
+ for(size_t i = 0; i < d_constellation.size(); i++) {
+ if(d_constellation[i].real() > d_re_max)
+ d_re_max = d_constellation[i].real();
+ if(d_constellation[i].imag() > d_im_max)
+ d_im_max = d_constellation[i].imag();
+
+ if(d_constellation[i].real() < d_re_min)
+ d_re_min = d_constellation[i].real();
+ if(d_constellation[i].imag() < d_im_min)
+ d_im_min = d_constellation[i].imag();
+ }
+ if(d_im_min == 0)
+ d_im_min = d_re_min;
+ if(d_im_max == 0)
+ d_im_max = d_re_max;
+ if(d_re_min == 0)
+ d_re_min = d_im_min;
+ if(d_re_max == 0)
+ d_re_max = d_im_max;
+ }
+
/********************************************************************/
- constellation_calcdist::sptr
+ constellation_calcdist::sptr
constellation_calcdist::make(std::vector<gr_complex> constell,
std::vector<int> pre_diff_code,
unsigned int rotational_symmetry,