diff options
Diffstat (limited to 'gr-digital/python/digital/qa_constellation.py')
-rw-r--r-- | gr-digital/python/digital/qa_constellation.py | 107 |
1 files changed, 78 insertions, 29 deletions
diff --git a/gr-digital/python/digital/qa_constellation.py b/gr-digital/python/digital/qa_constellation.py index 00248f4f09..42e49bb059 100644 --- a/gr-digital/python/digital/qa_constellation.py +++ b/gr-digital/python/digital/qa_constellation.py @@ -1,26 +1,26 @@ #!/usr/bin/env python # # Copyright 2011,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 random +import random, math from cmath import exp, pi, log, sqrt from gnuradio import gr, gr_unittest, digital, blocks @@ -40,7 +40,7 @@ tested_mod_codes = (mod_codes.NO_CODE, mod_codes.GRAY_CODE) def twod_constell(): """ - + """ points = ((1+0j), (0+1j), (-1+0j), (0-1j)) @@ -76,12 +76,12 @@ easy_constellation_info = ( False, None), (qam.qam_constellation, {'constellation_points': (4,), - 'mod_code': tested_mod_codes, + 'mod_code': tested_mod_codes, 'large_ampls_to_corners': [False],}, True, None), (qam.qam_constellation, {'constellation_points': (4, 16, 64), - 'mod_code': tested_mod_codes, + 'mod_code': tested_mod_codes, 'differential': (False,)}, False, None), (digital.constellation_bpsk, {}, True, None), @@ -101,7 +101,7 @@ medium_constellation_info = ( True, None), (qam.qam_constellation, {'constellation_points': (16 ,), - 'mod_code': tested_mod_codes, + 'mod_code': tested_mod_codes, 'large_ampls_to_corners': [False, True],}, True, None), (qamlike.qam32_holeinside_constellation, @@ -113,11 +113,20 @@ medium_constellation_info = ( difficult_constellation_info = ( (qam.qam_constellation, {'constellation_points': (64,), - 'mod_code': tested_mod_codes, + 'mod_code': tested_mod_codes, 'large_ampls_to_corners': [False, True],}, - True, None), + True, None), ) +def slicer(x): + ret = [] + for xi in x: + if(xi < 0): + ret.append(0.0) + else: + ret.append(1.0) + return ret + def tested_constellations(easy=True, medium=True, difficult=True): """ Generator to produce (constellation, differential) tuples for testing purposes. @@ -153,7 +162,7 @@ def tested_constellations(easy=True, medium=True, difficult=True): this_poss_arg[2] = 0 if sum([argindex for argname, argvalues, argindex in poss_args]) == 0: break - + class test_constellation(gr_unittest.TestCase): @@ -170,7 +179,7 @@ class test_constellation(gr_unittest.TestCase): for constellation, differential in tested_constellations(): if differential: rs = constellation.rotational_symmetry() - rotations = [exp(i*2*pi*(0+1j)/rs) for i in range(0, rs)] + rotations = [exp(i*2*pi*(0+1j)/rs) for i in range(0, rs)] else: rotations = [None] for rotation in rotations: @@ -216,17 +225,17 @@ class test_constellation(gr_unittest.TestCase): y_cpp_raw_calc = [] y_cpp_table = [] for sample in samples: - y_python_raw_calc += digital.calc_soft_dec(sample, constel, code) - y_python_gen_calc += digital.sd_psk_4_0(sample, Es) - y_python_table += digital.calc_soft_dec_from_table(sample, table, prec, Es) + y_python_raw_calc += slicer(digital.calc_soft_dec(sample, constel, code)) + y_python_gen_calc += slicer(digital.sd_psk_4_0(sample, Es)) + y_python_table += slicer(digital.calc_soft_dec_from_table(sample, table, prec, Es)) y_cpp_raw_calc += c.calc_soft_dec(sample) y_cpp_table += c.soft_decision_maker(sample) - self.assertFloatTuplesAlmostEqual(y_python_raw_calc, y_python_gen_calc, 4) - self.assertFloatTuplesAlmostEqual(y_python_raw_calc, y_python_table, 2) - self.assertFloatTuplesAlmostEqual(y_cpp_raw_calc, y_cpp_table, 4) - + self.assertFloatTuplesAlmostEqual(y_python_raw_calc, y_python_gen_calc, 0) + self.assertFloatTuplesAlmostEqual(y_python_gen_calc, y_python_table, 0) + self.assertFloatTuplesAlmostEqual(y_cpp_raw_calc, y_cpp_table, 0) + def test_soft_qpsk_calc(self): prec = 8 constel, code = digital.psk_4_0() @@ -257,14 +266,54 @@ class test_constellation(gr_unittest.TestCase): y_cpp_raw_calc = [] y_cpp_table = [] for sample in samples: - y_python_raw_calc += digital.calc_soft_dec(sample, constel, code) - y_python_table += digital.calc_soft_dec_from_table(sample, table, prec, Es) + y_python_raw_calc += slicer(digital.calc_soft_dec(sample, constel, code)) + y_python_table += slicer(digital.calc_soft_dec_from_table(sample, table, prec, Es)) - y_cpp_raw_calc += c.calc_soft_dec(sample) - y_cpp_table += c.soft_decision_maker(sample) + y_cpp_raw_calc += slicer(c.calc_soft_dec(sample)) + y_cpp_table += slicer(c.soft_decision_maker(sample)) + + self.assertEqual(y_python_raw_calc, y_python_table) + self.assertEqual(y_cpp_raw_calc, y_cpp_table) + + + def test_soft_qam16_calc(self): + prec = 8 + constel, code = digital.qam_16_0() - self.assertFloatTuplesAlmostEqual(y_python_raw_calc, y_python_table, 4) - self.assertFloatTuplesAlmostEqual(y_cpp_raw_calc, y_cpp_table, 4) + rot_sym = 1 + side = 2 + width = 2 + c = digital.constellation_rect(constel, code, rot_sym, + side, side, width, width) + + # Get max energy/symbol in constellation + constel = c.points() + Es = max([abs(constel_i) for constel_i in constel]) + + table = digital.soft_dec_table(constel, code, prec) + c.gen_soft_dec_lut(prec) + + x = sqrt(2.0)/2.0 + step = (x.real+x.real) / (2**prec - 1) + samples = [ -x-x*1j, -x+x*1j, + x+x*1j, x-x*1j, + (-x+128*step)+(-x+128*step)*1j, + (-x+64*step) +(-x+64*step)*1j, (-x+64*step) +(-x+192*step)*1j, + (-x+192*step)+(-x+192*step)*1j, (-x+192*step)+(-x+64*step)*1j,] + + y_python_raw_calc = [] + y_python_table = [] + y_cpp_raw_calc = [] + y_cpp_table = [] + for sample in samples: + y_python_raw_calc += slicer(digital.calc_soft_dec(sample, constel, code)) + y_python_table += slicer(digital.calc_soft_dec_from_table(sample, table, prec, Es)) + + y_cpp_raw_calc += slicer(c.calc_soft_dec(sample)) + y_cpp_table += slicer(c.soft_decision_maker(sample)) + + self.assertFloatTuplesAlmostEqual(y_python_raw_calc, y_python_table, 0) + self.assertFloatTuplesAlmostEqual(y_cpp_raw_calc, y_cpp_table, 0) class mod_demod(gr.hier_block2): def __init__(self, constellation, differential, rotation): @@ -317,7 +366,7 @@ class mod_demod(gr.hier_block2): if self.constellation.apply_pre_diff_code(): self.blocks.append(digital.map_bb( mod_codes.invert_code(self.constellation.pre_diff_code()))) - # unpack the k bit vector into a stream of bits + # unpack the k bit vector into a stream of bits self.blocks.append(blocks.unpack_k_bits_bb( self.constellation.bits_per_symbol())) # connect to block output @@ -326,6 +375,6 @@ class mod_demod(gr.hier_block2): self.blocks.append(weakref.proxy(self)) self.connect(*self.blocks) - + if __name__ == '__main__': gr_unittest.run(test_constellation, "test_constellation.xml") |