diff options
Diffstat (limited to 'gr-digital/python/digital/soft_dec_lut_gen.py')
-rw-r--r-- | gr-digital/python/digital/soft_dec_lut_gen.py | 96 |
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 |