summaryrefslogtreecommitdiff
path: root/gr-digital/python/digital/soft_dec_lut_gen.py
diff options
context:
space:
mode:
Diffstat (limited to 'gr-digital/python/digital/soft_dec_lut_gen.py')
-rw-r--r--gr-digital/python/digital/soft_dec_lut_gen.py96
1 files changed, 59 insertions, 37 deletions
diff --git a/gr-digital/python/digital/soft_dec_lut_gen.py b/gr-digital/python/digital/soft_dec_lut_gen.py
index 24d8bbdc2e..9c184d60cb 100644
--- a/gr-digital/python/digital/soft_dec_lut_gen.py
+++ b/gr-digital/python/digital/soft_dec_lut_gen.py
@@ -1,30 +1,29 @@
#!/usr/bin/env python
#
# Copyright 2013 Free Software Foundation, Inc.
-#
+#
# This file is part of GNU Radio
-#
+#
# GNU Radio is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
-#
+#
# GNU Radio is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License
# along with GNU Radio; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
-#
+#
import numpy
def soft_dec_table_generator(soft_dec_gen, prec, Es=1):
- '''
- Builds a LUT that is a list of tuples. The tuple represents the
+ '''Builds a LUT that is a list of tuples. The tuple represents the
soft decisions for the constellation/bit mapping at any given
point in the complex space, (x,y).
@@ -70,18 +69,19 @@ def soft_dec_table_generator(soft_dec_gen, prec, Es=1):
(1,1) into an index value in the table and returns the tuple of
soft decisions at that index.
- Es is the energy per symbol. This is passed to the function to
- provide the bounds when calling the generator function since they
- don't know how the constellation was normalized. Using the
- (maximum) energy per symbol for constellation allows us to provide
- any scaling of the constellation (normalized to sum to 1,
+ Es is the maximum energy per symbol. This is passed to the
+ function to provide the bounds when calling the generator function
+ since they don't know how the constellation was normalized. Using
+ the (maximum) energy per symbol for constellation allows us to
+ provide any scaling of the constellation (normalized to sum to 1,
normalized so the outside points sit on +/-1, etc.) but still
calculate the soft decisions as we would given the full
constellation.
+
'''
npts = 2.0**prec
- maxd = Es*numpy.sqrt(2)/2
+ maxd = Es*numpy.sqrt(2.0)/2.0
yrng = numpy.linspace(-maxd, maxd, npts)
xrng = numpy.linspace(-maxd, maxd, npts)
@@ -129,7 +129,7 @@ def soft_dec_table(constel, symbols, prec, npwr=1):
table.append(decs)
return table
-def calc_soft_dec_from_table(sample, table, prec, Es=1):
+def calc_soft_dec_from_table(sample, table, prec, Es=1.0):
'''
Takes in a complex sample and converts it from the coordinates
(-1,-1) to (1,1) into an index value. The index value points to a
@@ -152,25 +152,25 @@ def calc_soft_dec_from_table(sample, table, prec, Es=1):
calculate the soft decisions as we would given the full
constellation.
'''
- lut_scale = 2**prec
- maxd = Es*numpy.sqrt(2)/2
- step = 2*maxd / lut_scale
- scale = (lut_scale) / (2*maxd) - step
-
+ lut_scale = 2.0**prec
+ maxd = Es*numpy.sqrt(2.0)/2.0
+ scale = (lut_scale) / (2.0*maxd)
+
+ alpha = 0.99 # to keep index within bounds
xre = sample.real
xim = sample.imag
- xre = int((maxd + min(maxd, max(-maxd, xre))) * scale)
- xim = int((maxd + min(maxd, max(-maxd, xim))) * scale)
- index = int(xre + lut_scale*xim)
+ xre = ((maxd + min(alpha*maxd, max(-alpha*maxd, xre))) * scale)
+ xim = ((maxd + min(alpha*maxd, max(-alpha*maxd, xim))) * scale)
+ index = int(xre) + lut_scale*int(xim)
max_index = lut_scale**2
- if(index > max_index):
- return table[0];
- if(index < 0):
- raise RuntimeError("calc_from_table: input sample out of range.")
+ while(index >= max_index):
+ index -= lut_scale;
+ while(index < 0):
+ index += lut_scale;
- return table[index]
+ return table[int(index)]
def calc_soft_dec(sample, constel, symbols, npwr=1):
'''
@@ -192,25 +192,21 @@ def calc_soft_dec(sample, constel, symbols, npwr=1):
than 0 are more likely to indicate a '0' bit and decisions greater
than 0 are more likely to indicate a '1' bit.
'''
-
+
M = len(constel)
k = int(numpy.log2(M))
tmp = 2*k*[0,]
s = k*[0,]
- # Find a scaling factor for the constellation, however it was normalized.
- constel = numpy.array(constel)
- scale = min(min(abs(constel.real)), min(abs(constel.imag)))
-
for i in range(M):
# Calculate the distance between the sample and the current
# constellation point.
- dist = abs(sample - constel[i])**2
+ dist = abs(sample - constel[i])
# Calculate the probability factor from the distance and the
# scaled noise power.
- d = numpy.exp(-dist/(2*npwr*scale**2))
-
+ d = numpy.exp(-dist/npwr)
+
for j in range(k):
# Get the bit at the jth index
mask = 1<<j
@@ -222,11 +218,37 @@ def calc_soft_dec(sample, constel, symbols, npwr=1):
# 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 i in range(k):
- s[k-1-i] = (numpy.log(tmp[2*i+1]) - numpy.log(tmp[2*i+0])) * scale**2
+ s[k-1-i] = (numpy.log(tmp[2*i+1]) - numpy.log(tmp[2*i+0]))
return s
+
+
+def show_table(table):
+ prec = int(numpy.sqrt(len(table)))
+ nbits = len(table[0])
+ pp = ""
+ subi = 1
+ subj = 0
+ for i in reversed(xrange(prec+1)):
+ if(i == prec//2):
+ pp += "-----" + prec*((nbits*8)+3)*"-" + "\n"
+ subi = 0
+ continue
+ for j in xrange(prec+1):
+ if(j == prec//2):
+ pp += "| "
+ subj = 1
+ else:
+ item = table[prec*(i-subi) + (j-subj)]
+ pp += "( "
+ for t in xrange(nbits-1, -1, -1):
+ pp += "{0: .4f} ".format(item[t])
+ pp += ") "
+ pp += "\n"
+ subj = 0
+ print pp