diff options
author | mormj <mormjb@gmail.com> | 2020-10-30 10:59:50 -0400 |
---|---|---|
committer | Marcus Müller <marcus@hostalia.de> | 2020-10-30 17:52:53 +0100 |
commit | 7a0948ba85758fba1cc3858ef99bfa600dcc7416 (patch) | |
tree | 610d7f9d773a193562def6df2d4b50f1bb3b3f86 /gr-digital/python/digital | |
parent | 12192ee7d58de95ddca35a3e93bfc172bdb5c820 (diff) |
qa: run autopep8 formatting on qa python files
find ./ -iname qa*.py | xargs autopep8 --in-place -a -a
mostly formats whitespace and gets rid of trailing semicolons
Diffstat (limited to 'gr-digital/python/digital')
50 files changed, 2229 insertions, 1254 deletions
diff --git a/gr-digital/python/digital/qa_binary_slicer_fb.py b/gr-digital/python/digital/qa_binary_slicer_fb.py index eccaeab6f5..2ad40d1e02 100644 --- a/gr-digital/python/digital/qa_binary_slicer_fb.py +++ b/gr-digital/python/digital/qa_binary_slicer_fb.py @@ -13,6 +13,7 @@ import random from gnuradio import gr, gr_unittest, digital, blocks + class test_binary_slicer_fb(gr_unittest.TestCase): def setUp(self): @@ -23,9 +24,10 @@ class test_binary_slicer_fb(gr_unittest.TestCase): self.tb = None def test_binary_slicer_fb(self): - expected_result = ( 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1) - src_data = (-1, 1, -1, -1, 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1) - src_data = [s + (1 - random.random()) for s in src_data] # add some noise + expected_result = (0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1) + src_data = (-1, 1, -1, -1, 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1) + src_data = [s + (1 - random.random()) + for s in src_data] # add some noise src = blocks.vector_source_f(src_data) op = digital.binary_slicer_fb() dst = blocks.vector_sink_b() @@ -35,8 +37,8 @@ class test_binary_slicer_fb(gr_unittest.TestCase): self.tb.run() # run the graph and wait for it to finish actual_result = dst.data() # fetch the contents of the sink - #print "actual result", actual_result - #print "expected result", expected_result + # print "actual result", actual_result + # print "expected result", expected_result self.assertFloatTuplesAlmostEqual(expected_result, actual_result) diff --git a/gr-digital/python/digital/qa_burst_shaper.py b/gr-digital/python/digital/qa_burst_shaper.py index 3fd47195fa..2846617fd7 100644 --- a/gr-digital/python/digital/qa_burst_shaper.py +++ b/gr-digital/python/digital/qa_burst_shaper.py @@ -1,13 +1,13 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# +# # Copyright 2015 Free Software Foundation, Inc. -# +# # This file is part of GNU Radio -# +# # SPDX-License-Identifier: GPL-3.0-or-later # -# +# from gnuradio import gr, gr_unittest @@ -16,31 +16,35 @@ import pmt import numpy as np import sys + def make_length_tag(offset, length): - return gr.python_to_tag({'offset' : offset, - 'key' : pmt.intern('packet_len'), - 'value' : pmt.from_long(length), - 'srcid' : pmt.intern('qa_burst_shaper')}) + return gr.python_to_tag({'offset': offset, + 'key': pmt.intern('packet_len'), + 'value': pmt.from_long(length), + 'srcid': pmt.intern('qa_burst_shaper')}) + def make_tag(offset, key, value): - return gr.python_to_tag({'offset' : offset, - 'key' : pmt.intern(key), - 'value' : value, - 'srcid' : pmt.intern('qa_burst_shaper')}) + return gr.python_to_tag({'offset': offset, + 'key': pmt.intern(key), + 'value': value, + 'srcid': pmt.intern('qa_burst_shaper')}) + def compare_tags(a, b): return a.offset == b.offset and pmt.equal(a.key, b.key) and \ - pmt.equal(a.value, b.value) + pmt.equal(a.value, b.value) + class qa_burst_shaper (gr_unittest.TestCase): - def setUp (self): - self.tb = gr.top_block () + def setUp(self): + self.tb = gr.top_block() - def tearDown (self): + def tearDown(self): self.tb = None - def test_ff (self): + def test_ff(self): ''' test_ff: test with float values, even length window, zero padding, and no phasing @@ -49,7 +53,7 @@ class qa_burst_shaper (gr_unittest.TestCase): postpad = 10 length = 20 data = np.ones(length) - window = np.concatenate((-2.0*np.ones(5), -4.0*np.ones(5))) + window = np.concatenate((-2.0 * np.ones(5), -4.0 * np.ones(5))) tags = (make_length_tag(0, length),) expected = np.concatenate((np.zeros(prepad), window[0:5], np.ones(length - len(window)), window[5:10], @@ -62,13 +66,13 @@ class qa_burst_shaper (gr_unittest.TestCase): post_padding=postpad) sink = blocks.vector_sink_f() self.tb.connect(source, shaper, sink) - self.tb.run () + self.tb.run() # checks self.assertFloatTuplesAlmostEqual(sink.data(), expected, 6) self.assertTrue(compare_tags(sink.tags()[0], etag)) - def test_cc (self): + def test_cc(self): ''' test_cc: test with complex values, even length window, zero padding, and no phasing @@ -77,13 +81,13 @@ class qa_burst_shaper (gr_unittest.TestCase): postpad = 10 length = 20 data = np.ones(length, dtype=complex) - window = np.concatenate((-2.0*np.ones(5, dtype=complex), - -4.0*np.ones(5, dtype=complex))) + window = np.concatenate((-2.0 * np.ones(5, dtype=complex), + -4.0 * np.ones(5, dtype=complex))) tags = (make_length_tag(0, length),) expected = np.concatenate((np.zeros(prepad, dtype=complex), window[0:5], np.ones(length - len(window), dtype=complex), window[5:10], np.zeros(postpad, - dtype=complex))) + dtype=complex))) etag = make_length_tag(0, length + prepad + postpad) # flowgraph @@ -92,13 +96,13 @@ class qa_burst_shaper (gr_unittest.TestCase): post_padding=postpad) sink = blocks.vector_sink_c() self.tb.connect(source, shaper, sink) - self.tb.run () + self.tb.run() # checks self.assertComplexTuplesAlmostEqual(sink.data(), expected, 6) self.assertTrue(compare_tags(sink.tags()[0], etag)) - def test_ff_with_phasing (self): + def test_ff_with_phasing(self): ''' test_ff_with_phasing: test with float values, even length window, zero padding, and phasing @@ -107,13 +111,13 @@ class qa_burst_shaper (gr_unittest.TestCase): postpad = 10 length = 20 data = np.ones(length) - window = np.concatenate((-2.0*np.ones(5), -4.0*np.ones(5))) + window = np.concatenate((-2.0 * np.ones(5), -4.0 * np.ones(5))) tags = (make_length_tag(0, length),) phasing = np.zeros(5) for i in range(5): phasing[i] = ((-1.0)**i) - expected = np.concatenate((np.zeros(prepad), phasing*window[0:5], - np.ones(length), phasing*window[5:10], + expected = np.concatenate((np.zeros(prepad), phasing * window[0:5], + np.ones(length), phasing * window[5:10], np.zeros(postpad))) etag = make_length_tag(0, length + prepad + postpad + len(window)) @@ -124,13 +128,13 @@ class qa_burst_shaper (gr_unittest.TestCase): insert_phasing=True) sink = blocks.vector_sink_f() self.tb.connect(source, shaper, sink) - self.tb.run () + self.tb.run() # checks self.assertFloatTuplesAlmostEqual(sink.data(), expected, 6) self.assertTrue(compare_tags(sink.tags()[0], etag)) - def test_cc_with_phasing (self): + def test_cc_with_phasing(self): ''' test_cc_with_phasing: test with complex values, even length window, zero padding, and phasing @@ -139,16 +143,16 @@ class qa_burst_shaper (gr_unittest.TestCase): postpad = 10 length = 20 data = np.ones(length, dtype=complex) - window = np.concatenate((-2.0*np.ones(5, dtype=complex), - -4.0*np.ones(5, dtype=complex))) + window = np.concatenate((-2.0 * np.ones(5, dtype=complex), + -4.0 * np.ones(5, dtype=complex))) tags = (make_length_tag(0, length),) phasing = np.zeros(5, dtype=complex) for i in range(5): phasing[i] = complex((-1.0)**i) expected = np.concatenate((np.zeros(prepad, dtype=complex), - phasing*window[0:5], + phasing * window[0:5], np.ones(length, dtype=complex), - phasing*window[5:10], + phasing * window[5:10], np.zeros(postpad, dtype=complex))) etag = make_length_tag(0, length + prepad + postpad + len(window)) @@ -159,13 +163,13 @@ class qa_burst_shaper (gr_unittest.TestCase): insert_phasing=True) sink = blocks.vector_sink_c() self.tb.connect(source, shaper, sink) - self.tb.run () + self.tb.run() # checks self.assertComplexTuplesAlmostEqual(sink.data(), expected, 6) self.assertTrue(compare_tags(sink.tags()[0], etag)) - def test_odd_window (self): + def test_odd_window(self): ''' test_odd_window: test with odd length window; center sample should be applied at end of up flank and beginning of down flank @@ -174,8 +178,8 @@ class qa_burst_shaper (gr_unittest.TestCase): postpad = 10 length = 20 data = np.ones(length) - window = np.concatenate((-2.0*np.ones(5), -3.0*np.ones(1), - -4.0*np.ones(5))) + window = np.concatenate((-2.0 * np.ones(5), -3.0 * np.ones(1), + -4.0 * np.ones(5))) tags = (make_length_tag(0, length),) expected = np.concatenate((np.zeros(prepad), window[0:6], np.ones(length - len(window) - 1), @@ -188,13 +192,13 @@ class qa_burst_shaper (gr_unittest.TestCase): post_padding=postpad) sink = blocks.vector_sink_f() self.tb.connect(source, shaper, sink) - self.tb.run () + self.tb.run() # checks self.assertFloatTuplesAlmostEqual(sink.data(), expected, 6) self.assertTrue(compare_tags(sink.tags()[0], etag)) - def test_short_burst (self): + def test_short_burst(self): ''' test_short_burst: test with burst length shorter than window length; clips the window up and down flanks to FLOOR(length/2) samples @@ -216,13 +220,13 @@ class qa_burst_shaper (gr_unittest.TestCase): post_padding=postpad) sink = blocks.vector_sink_f() self.tb.connect(source, shaper, sink) - self.tb.run () + self.tb.run() # checks self.assertFloatTuplesAlmostEqual(sink.data(), expected, 6) self.assertTrue(compare_tags(sink.tags()[0], etag)) - def test_consecutive_bursts (self): + def test_consecutive_bursts(self): ''' test_consecutive_bursts: test with consecutive bursts of different lengths @@ -231,14 +235,14 @@ class qa_burst_shaper (gr_unittest.TestCase): postpad = 10 length1 = 15 length2 = 25 - data = np.concatenate((np.ones(length1), -1.0*np.ones(length2))) - window = np.concatenate((-2.0*np.ones(5), -4.0*np.ones(5))) + data = np.concatenate((np.ones(length1), -1.0 * np.ones(length2))) + window = np.concatenate((-2.0 * np.ones(5), -4.0 * np.ones(5))) tags = (make_length_tag(0, length1), make_length_tag(length1, length2)) expected = np.concatenate((np.zeros(prepad), window[0:5], np.ones(length1 - len(window)), window[5:10], - np.zeros(postpad + prepad), -1.0*window[0:5], - -1.0*np.ones(length2 - len(window)), - -1.0*window[5:10], np.zeros(postpad))) + np.zeros(postpad + prepad), -1.0 * window[0:5], + -1.0 * np.ones(length2 - len(window)), + -1.0 * window[5:10], np.zeros(postpad))) etags = (make_length_tag(0, length1 + prepad + postpad), make_length_tag(length1 + prepad + postpad, length2 + prepad + postpad)) @@ -249,14 +253,14 @@ class qa_burst_shaper (gr_unittest.TestCase): post_padding=postpad) sink = blocks.vector_sink_f() self.tb.connect(source, shaper, sink) - self.tb.run () + self.tb.run() # checks self.assertFloatTuplesAlmostEqual(sink.data(), expected, 6) for i in range(len(etags)): self.assertTrue(compare_tags(sink.tags()[i], etags[i])) - def test_tag_gap (self): + def test_tag_gap(self): ''' test_tag_gap: test with gap between tags; should drop samples that are between proper tagged streams @@ -265,18 +269,26 @@ class qa_burst_shaper (gr_unittest.TestCase): postpad = 10 length = 20 gap_len = 5 - data = np.arange(2*length + gap_len, dtype=float) - window = np.concatenate((-2.0*np.ones(5), -4.0*np.ones(5))) - ewindow = window * np.array([1,-1,1,-1,1,1,-1,1,-1,1],dtype=float) + data = np.arange(2 * length + gap_len, dtype=float) + window = np.concatenate((-2.0 * np.ones(5), -4.0 * np.ones(5))) + ewindow = window * \ + np.array([1, -1, 1, -1, 1, 1, -1, 1, -1, 1], dtype=float) tags = (make_length_tag(0, length), make_length_tag(length + gap_len, length)) - expected = np.concatenate((np.zeros(prepad), ewindow[0:5], - np.arange(0, length, dtype=float), - ewindow[5:10], np.zeros(postpad), - np.zeros(prepad), ewindow[0:5], + expected = np.concatenate((np.zeros(prepad), + ewindow[0:5], + np.arange(0, + length, + dtype=float), + ewindow[5:10], + np.zeros(postpad), + np.zeros(prepad), + ewindow[0:5], np.arange(length + gap_len, - 2*length + gap_len, dtype=float), - ewindow[5:10], np.zeros(postpad))) + 2 * length + gap_len, + dtype=float), + ewindow[5:10], + np.zeros(postpad))) burst_len = length + len(window) + prepad + postpad etags = (make_length_tag(0, burst_len), make_length_tag(burst_len, burst_len)) @@ -288,14 +300,14 @@ class qa_burst_shaper (gr_unittest.TestCase): insert_phasing=True) sink = blocks.vector_sink_f() self.tb.connect(source, shaper, sink) - self.tb.run () + self.tb.run() # checks self.assertFloatTuplesAlmostEqual(sink.data(), expected, 6) for i in range(len(etags)): self.assertTrue(compare_tags(sink.tags()[i], etags[i])) - def test_tag_propagation (self): + def test_tag_propagation(self): ''' test_tag_propagation: test that non length tags are handled correctly ''' @@ -310,11 +322,11 @@ class qa_burst_shaper (gr_unittest.TestCase): tag2_offset = length1 + gap_len # accompanies second length tag tag3_offset = 2 # in ramp-up state tag4_offset = length1 + 2 # in gap; tag will be dropped - tag5_offset = length1 + gap_len + 7 # in copy state + tag5_offset = length1 + gap_len + 7 # in copy state data = np.concatenate((np.ones(length1), np.zeros(gap_len), - -1.0*np.ones(length2))) - window = np.concatenate((-2.0*np.ones(5), -4.0*np.ones(5))) + -1.0 * np.ones(length2))) + window = np.concatenate((-2.0 * np.ones(5), -4.0 * np.ones(5))) tags = (make_length_tag(lentag1_offset, length1), make_length_tag(lentag2_offset, length2), make_tag(tag1_offset, 'head', pmt.intern('tag1')), @@ -324,15 +336,15 @@ class qa_burst_shaper (gr_unittest.TestCase): make_tag(tag5_offset, 'body', pmt.intern('tag5'))) expected = np.concatenate((np.zeros(prepad), window[0:5], np.ones(length1 - len(window)), window[5:10], - np.zeros(postpad + prepad), -1.0*window[0:5], - -1.0*np.ones(length2 - len(window)), - -1.0*window[5:10], np.zeros(postpad))) + np.zeros(postpad + prepad), -1.0 * window[0:5], + -1.0 * np.ones(length2 - len(window)), + -1.0 * window[5:10], np.zeros(postpad))) elentag1_offset = 0 elentag2_offset = length1 + prepad + postpad etag1_offset = 0 etag2_offset = elentag2_offset etag3_offset = prepad + tag3_offset - etag5_offset = 2*prepad + postpad + tag5_offset - gap_len + etag5_offset = 2 * prepad + postpad + tag5_offset - gap_len etags = (make_length_tag(elentag1_offset, length1 + prepad + postpad), make_length_tag(elentag2_offset, length2 + prepad + postpad), make_tag(etag1_offset, 'head', pmt.intern('tag1')), @@ -346,7 +358,7 @@ class qa_burst_shaper (gr_unittest.TestCase): post_padding=postpad) sink = blocks.vector_sink_f() self.tb.connect(source, shaper, sink) - self.tb.run () + self.tb.run() # checks self.assertFloatTuplesAlmostEqual(sink.data(), expected, 6) diff --git a/gr-digital/python/digital/qa_chunks_to_symbols.py b/gr-digital/python/digital/qa_chunks_to_symbols.py index e2d8801571..1616f29e08 100644 --- a/gr-digital/python/digital/qa_chunks_to_symbols.py +++ b/gr-digital/python/digital/qa_chunks_to_symbols.py @@ -12,6 +12,7 @@ import pmt from gnuradio import gr, gr_unittest, digital, blocks + class test_chunks_to_symbols(gr_unittest.TestCase): def setUp(self): @@ -21,11 +22,11 @@ class test_chunks_to_symbols(gr_unittest.TestCase): self.tb = None def test_bc_001(self): - const = [ 1+0j, 0+1j, - -1+0j, 0-1j] + const = [1 + 0j, 0 + 1j, + -1 + 0j, 0 - 1j] src_data = (0, 1, 2, 3, 3, 2, 1, 0) - expected_result = [1+0j, 0+1j, -1+0j, 0-1j, - 0-1j, -1+0j, 0+1j, 1+0j] + expected_result = [1 + 0j, 0 + 1j, -1 + 0j, 0 - 1j, + 0 - 1j, -1 + 0j, 0 + 1j, 1 + 0j] src = blocks.vector_source_b(src_data) op = digital.chunks_to_symbols_bc(const) @@ -42,7 +43,7 @@ class test_chunks_to_symbols(gr_unittest.TestCase): const = [-3, -1, 1, 3] src_data = (0, 1, 2, 3, 3, 2, 1, 0) expected_result = [-3, -1, 1, 3, - 3, 1, -1, -3] + 3, 1, -1, -3] src = blocks.vector_source_b(src_data) op = digital.chunks_to_symbols_bf(const) @@ -56,11 +57,11 @@ class test_chunks_to_symbols(gr_unittest.TestCase): self.assertEqual(expected_result, actual_result) def test_ic_003(self): - const = [ 1+0j, 0+1j, - -1+0j, 0-1j] + const = [1 + 0j, 0 + 1j, + -1 + 0j, 0 - 1j] src_data = (0, 1, 2, 3, 3, 2, 1, 0) - expected_result = [1+0j, 0+1j, -1+0j, 0-1j, - 0-1j, -1+0j, 0+1j, 1+0j] + expected_result = [1 + 0j, 0 + 1j, -1 + 0j, 0 - 1j, + 0 - 1j, -1 + 0j, 0 + 1j, 1 + 0j] src = blocks.vector_source_i(src_data) op = digital.chunks_to_symbols_ic(const) @@ -77,7 +78,7 @@ class test_chunks_to_symbols(gr_unittest.TestCase): const = [-3, -1, 1, 3] src_data = (0, 1, 2, 3, 3, 2, 1, 0) expected_result = [-3, -1, 1, 3, - 3, 1, -1, -3] + 3, 1, -1, -3] src = blocks.vector_source_i(src_data) op = digital.chunks_to_symbols_if(const) @@ -91,11 +92,11 @@ class test_chunks_to_symbols(gr_unittest.TestCase): self.assertEqual(expected_result, actual_result) def test_sc_005(self): - const = [ 1+0j, 0+1j, - -1+0j, 0-1j] + const = [1 + 0j, 0 + 1j, + -1 + 0j, 0 - 1j] src_data = (0, 1, 2, 3, 3, 2, 1, 0) - expected_result = [1+0j, 0+1j, -1+0j, 0-1j, - 0-1j, -1+0j, 0+1j, 1+0j] + expected_result = [1 + 0j, 0 + 1j, -1 + 0j, 0 - 1j, + 0 - 1j, -1 + 0j, 0 + 1j, 1 + 0j] src = blocks.vector_source_s(src_data) op = digital.chunks_to_symbols_sc(const) @@ -112,7 +113,7 @@ class test_chunks_to_symbols(gr_unittest.TestCase): const = [-3, -1, 1, 3] src_data = (0, 1, 2, 3, 3, 2, 1, 0) expected_result = [-3, -1, 1, 3, - 3, 1, -1, -3] + 3, 1, -1, -3] src = blocks.vector_source_s(src_data) op = digital.chunks_to_symbols_sf(const) @@ -125,12 +126,11 @@ class test_chunks_to_symbols(gr_unittest.TestCase): actual_result = dst.data() self.assertEqual(expected_result, actual_result) - def test_sf_callback(self): constA = [-3, -1, 1, 3] constB = [12, -12, 6, -6] src_data = [0, 1, 2, 3, 3, 2, 1, 0] - expected_result=[12, -12, 6, -6, -6, 6, -12, 12] + expected_result = [12, -12, 6, -6, -6, 6, -12, 12] src = blocks.vector_source_s(src_data, False, 1, []) op = digital.chunks_to_symbols_sf(constA) @@ -143,10 +143,11 @@ class test_chunks_to_symbols(gr_unittest.TestCase): self.assertEqual(expected_result, actual_result) def test_sc_callback(self): - constA = [-3.0+1j, -1.0-1j, 1.0+1j, 3-1j] - constB = [12.0+1j, -12.0-1j, 6.0+1j, -6-1j] + constA = [-3.0 + 1j, -1.0 - 1j, 1.0 + 1j, 3 - 1j] + constB = [12.0 + 1j, -12.0 - 1j, 6.0 + 1j, -6 - 1j] src_data = [0, 1, 2, 3, 3, 2, 1, 0] - expected_result=[12.0+1j, -12.0-1j, 6.0+1j, -6-1j, -6-1j, 6+1j, -12-1j, 12+1j] + expected_result = [12.0 + 1j, -12.0 - 1j, 6.0 + + 1j, -6 - 1j, -6 - 1j, 6 + 1j, -12 - 1j, 12 + 1j] src = blocks.vector_source_s(src_data, False, 1, []) op = digital.chunks_to_symbols_sc(constA) @@ -163,7 +164,7 @@ class test_chunks_to_symbols(gr_unittest.TestCase): constB = [12.0, -12.0, 6.0, -6] src_data = (0, 1, 2, 3, 3, 2, 1, 0) expected_result = [-3, -1, 1, 3, - -6, 6, -12, 12] + -6, 6, -12, 12] first_tag = gr.tag_t() first_tag.key = pmt.intern("set_symbol_table") first_tag.value = pmt.init_f32vector(len(constA), constA) @@ -173,7 +174,9 @@ class test_chunks_to_symbols(gr_unittest.TestCase): second_tag.value = pmt.init_f32vector(len(constB), constB) second_tag.offset = 4 - src = blocks.vector_source_s(src_data, False, 1, [first_tag, second_tag]) + src = blocks.vector_source_s( + src_data, False, 1, [ + first_tag, second_tag]) op = digital.chunks_to_symbols_sf(constB) dst = blocks.vector_sink_f() @@ -185,11 +188,11 @@ class test_chunks_to_symbols(gr_unittest.TestCase): self.assertEqual(expected_result, actual_result) def test_sc_tag(self): - constA = [-3.0+1j, -1.0-1j, 1.0+1j, 3-1j] - constB = [12.0+1j, -12.0-1j, 6.0+1j, -6-1j] + constA = [-3.0 + 1j, -1.0 - 1j, 1.0 + 1j, 3 - 1j] + constB = [12.0 + 1j, -12.0 - 1j, 6.0 + 1j, -6 - 1j] src_data = (0, 1, 2, 3, 3, 2, 1, 0) - expected_result = [-3+1j, -1-1j, 1+1j, 3-1j, - -6-1j, 6+1j, -12-1j, 12+1j] + expected_result = [-3 + 1j, -1 - 1j, 1 + 1j, 3 - 1j, + -6 - 1j, 6 + 1j, -12 - 1j, 12 + 1j] first_tag = gr.tag_t() first_tag.key = pmt.intern("set_symbol_table") first_tag.value = pmt.init_c32vector(len(constA), constA) @@ -199,7 +202,9 @@ class test_chunks_to_symbols(gr_unittest.TestCase): second_tag.value = pmt.init_c32vector(len(constB), constB) second_tag.offset = 4 - src = blocks.vector_source_s(src_data, False, 1, [first_tag, second_tag]) + src = blocks.vector_source_s( + src_data, False, 1, [ + first_tag, second_tag]) op = digital.chunks_to_symbols_sc(constB) dst = blocks.vector_sink_c() @@ -210,5 +215,6 @@ class test_chunks_to_symbols(gr_unittest.TestCase): actual_result = dst.data() self.assertEqual(expected_result, actual_result) + if __name__ == '__main__': gr_unittest.run(test_chunks_to_symbols) diff --git a/gr-digital/python/digital/qa_clock_recovery_mm.py b/gr-digital/python/digital/qa_clock_recovery_mm.py index 782d9e6bae..1475eacf15 100644 --- a/gr-digital/python/digital/qa_clock_recovery_mm.py +++ b/gr-digital/python/digital/qa_clock_recovery_mm.py @@ -14,6 +14,7 @@ import cmath from gnuradio import gr, gr_unittest, digital, blocks + class test_clock_recovery_mm(gr_unittest.TestCase): def setUp(self): @@ -35,14 +36,15 @@ class test_clock_recovery_mm(gr_unittest.TestCase): mu, gain_mu, omega_rel_lim) - data = 100*[complex(1, 1),] + data = 100 * [complex(1, 1), ] self.src = blocks.vector_source_c(data, False) self.snk = blocks.vector_sink_c() self.tb.connect(self.src, self.test, self.snk) self.tb.run() - expected_result = 100*[complex(0.99972, 0.99972)] # doesn't quite get to 1.0 + # doesn't quite get to 1.0 + expected_result = 100 * [complex(0.99972, 0.99972)] dst_data = self.snk.data() # Only compare last Ncmp samples @@ -52,12 +54,11 @@ class test_clock_recovery_mm(gr_unittest.TestCase): expected_result = expected_result[len_e - Ncmp:] dst_data = dst_data[len_d - Ncmp:] - #print expected_result - #print dst_data + # print expected_result + # print dst_data self.assertComplexTuplesAlmostEqual(expected_result, dst_data, 5) - def test02(self): # Test float/float version omega = 2 @@ -70,14 +71,14 @@ class test_clock_recovery_mm(gr_unittest.TestCase): mu, gain_mu, omega_rel_lim) - data = 100*[1,] + data = 100 * [1, ] self.src = blocks.vector_source_f(data, False) self.snk = blocks.vector_sink_f() self.tb.connect(self.src, self.test, self.snk) self.tb.run() - expected_result = 100*[0.9997, ] # doesn't quite get to 1.0 + expected_result = 100 * [0.9997, ] # doesn't quite get to 1.0 dst_data = self.snk.data() # Only compare last Ncmp samples @@ -87,12 +88,11 @@ class test_clock_recovery_mm(gr_unittest.TestCase): expected_result = expected_result[len_e - Ncmp:] dst_data = dst_data[len_d - Ncmp:] - #print expected_result - #print dst_data + # print expected_result + # print dst_data self.assertFloatTuplesAlmostEqual(expected_result, dst_data, 4) - def test03(self): # Test complex/complex version with varying input omega = 2 @@ -105,14 +105,15 @@ class test_clock_recovery_mm(gr_unittest.TestCase): mu, gain_mu, omega_rel_lim) - data = 1000*[complex(1, 1), complex(1, 1), complex(-1, -1), complex(-1, -1)] + data = 1000 * [complex(1, 1), complex(1, 1), + complex(-1, -1), complex(-1, -1)] self.src = blocks.vector_source_c(data, False) self.snk = blocks.vector_sink_c() self.tb.connect(self.src, self.test, self.snk) self.tb.run() - expected_result = 1000*[complex(-1.2, -1.2), complex(1.2, 1.2)] + expected_result = 1000 * [complex(-1.2, -1.2), complex(1.2, 1.2)] dst_data = self.snk.data() # Only compare last Ncmp samples @@ -122,12 +123,11 @@ class test_clock_recovery_mm(gr_unittest.TestCase): expected_result = expected_result[len_e - Ncmp:] dst_data = dst_data[len_d - Ncmp:] - #print expected_result - #print dst_data + # print expected_result + # print dst_data self.assertComplexTuplesAlmostEqual(expected_result, dst_data, 1) - def test04(self): # Test float/float version omega = 2 @@ -140,14 +140,14 @@ class test_clock_recovery_mm(gr_unittest.TestCase): mu, gain_mu, omega_rel_lim) - data = 1000*[1, 1, -1, -1] + data = 1000 * [1, 1, -1, -1] self.src = blocks.vector_source_f(data, False) self.snk = blocks.vector_sink_f() self.tb.connect(self.src, self.test, self.snk) self.tb.run() - expected_result = 1000*[-1.2, 1.2] + expected_result = 1000 * [-1.2, 1.2] dst_data = self.snk.data() # Only compare last Ncmp samples @@ -157,8 +157,8 @@ class test_clock_recovery_mm(gr_unittest.TestCase): expected_result = expected_result[len_e - Ncmp:] dst_data = dst_data[len_d - Ncmp:] - #print expected_result - #print dst_data + # print expected_result + # print dst_data self.assertFloatTuplesAlmostEqual(expected_result, dst_data, 1) diff --git a/gr-digital/python/digital/qa_cma_equalizer.py b/gr-digital/python/digital/qa_cma_equalizer.py index 39b868f8d1..f6da3d1b70 100644 --- a/gr-digital/python/digital/qa_cma_equalizer.py +++ b/gr-digital/python/digital/qa_cma_equalizer.py @@ -11,6 +11,7 @@ from gnuradio import gr, gr_unittest, digital, blocks + class test_cma_equalizer_fir(gr_unittest.TestCase): def setUp(self): @@ -29,12 +30,13 @@ class test_cma_equalizer_fir(gr_unittest.TestCase): def test_001_identity(self): # Constant modulus signal so no adjustments - src_data = (1+0j, 0+1j, -1+0j, 0-1j)*1000 + src_data = (1 + 0j, 0 + 1j, -1 + 0j, 0 - 1j) * 1000 expected_data = src_data result = self.transform(src_data) N = -500 self.assertComplexTuplesAlmostEqual(expected_data[N:], result[N:]) + if __name__ == "__main__": gr_unittest.run(test_cma_equalizer_fir) diff --git a/gr-digital/python/digital/qa_constellation.py b/gr-digital/python/digital/qa_constellation.py index 050b507a2b..0e3460a142 100644 --- a/gr-digital/python/digital/qa_constellation.py +++ b/gr-digital/python/digital/qa_constellation.py @@ -9,7 +9,8 @@ # -import random, math +import random +import math from cmath import exp, pi, log, sqrt from gnuradio import gr, gr_unittest, digital, blocks @@ -27,18 +28,20 @@ tested_mod_codes = (mod_codes.NO_CODE, mod_codes.GRAY_CODE) # Fourth item is the name of the argument to constructor that specifies # whether differential encoding is used. + def twod_constell(): """ """ - points = ((1+0j), (0+1j), - (-1+0j), (0-1j)) + points = ((1 + 0j), (0 + 1j), + (-1 + 0j), (0 - 1j)) rot_sym = 2 dim = 2 return digital.constellation_calcdist(points, [], rot_sym, dim) + def threed_constell(): - oned_points = ((1+0j), (0+1j), (-1+0j), (0-1j)) + oned_points = ((1 + 0j), (0 + 1j), (-1 + 0j), (0 - 1j)) points = [] r4 = list(range(0, 4)) for ia in r4: @@ -52,6 +55,7 @@ def threed_constell(): # A list of tuples for constellation testing. The contents of the # tuples are (constructor, poss_args, differential, diff_argname). + # These constellations should lock on well. easy_constellation_info = ( (psk.psk_constellation, @@ -66,7 +70,7 @@ easy_constellation_info = ( (qam.qam_constellation, {'constellation_points': (4,), 'mod_code': tested_mod_codes, - 'large_ampls_to_corners': [False],}, + 'large_ampls_to_corners': [False], }, True, None), (qam.qam_constellation, {'constellation_points': (4, 16, 64), @@ -79,7 +83,7 @@ easy_constellation_info = ( (digital.constellation_8psk, {}, False, None), (twod_constell, {}, True, None), (threed_constell, {}, True, None), - ) +) # These constellations don't work nicely. # We have a lower required error rate. @@ -89,9 +93,9 @@ medium_constellation_info = ( 'mod_code': tested_mod_codes, }, True, None), (qam.qam_constellation, - {'constellation_points': (16 ,), + {'constellation_points': (16,), 'mod_code': tested_mod_codes, - 'large_ampls_to_corners': [False, True],}, + 'large_ampls_to_corners': [False, True], }, True, None), (qamlike.qam32_holeinside_constellation, {'large_ampls_to_corners': [True]}, @@ -103,10 +107,11 @@ difficult_constellation_info = ( (qam.qam_constellation, {'constellation_points': (64,), 'mod_code': tested_mod_codes, - 'large_ampls_to_corners': [False, True],}, + 'large_ampls_to_corners': [False, True], }, True, None), ) + def slicer(x): ret = [] for xi in x: @@ -116,6 +121,7 @@ def slicer(x): ret.append(1.0) return ret + def tested_constellations(easy=True, medium=True, difficult=True): """ Generator to produce (constellation, differential) tuples for testing purposes. @@ -132,9 +138,11 @@ def tested_constellations(easy=True, medium=True, difficult=True): diff_poss = (True, False) else: diff_poss = (False,) - poss_args = [[argname, argvalues, 0] for argname, argvalues in list(poss_args.items())] + poss_args = [[argname, argvalues, 0] + for argname, argvalues in list(poss_args.items())] for current_diff in diff_poss: - # Add an index into args to keep track of current position in argvalues + # Add an index into args to keep track of current position in + # argvalues while True: current_args = dict([(argname, argvalues[argindex]) for argname, argvalues, argindex in poss_args]) @@ -149,7 +157,8 @@ def tested_constellations(easy=True, medium=True, difficult=True): break else: this_poss_arg[2] = 0 - if sum([argindex for argname, argvalues, argindex in poss_args]) == 0: + if sum([argindex for argname, argvalues, + argindex in poss_args]) == 0: break @@ -160,7 +169,10 @@ class test_constellation(gr_unittest.TestCase): def setUp(self): random.seed(0) # Generate a list of random bits. - self.src_data = [random.randint(0,1) for i in range(0, self.src_length)] + self.src_data = [ + random.randint( + 0, 1) for i in range( + 0, self.src_length)] def tearDown(self): pass @@ -169,7 +181,8 @@ 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: @@ -202,12 +215,17 @@ class test_constellation(gr_unittest.TestCase): c.set_soft_dec_lut(table, 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,] + 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_gen_calc = [] @@ -215,14 +233,19 @@ class test_constellation(gr_unittest.TestCase): 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_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_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, 0) + 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) @@ -244,20 +267,29 @@ class test_constellation(gr_unittest.TestCase): 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,] + 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_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)) @@ -265,7 +297,6 @@ class test_constellation(gr_unittest.TestCase): 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() @@ -284,20 +315,29 @@ class test_constellation(gr_unittest.TestCase): 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,] + 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_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)) @@ -305,15 +345,18 @@ class test_constellation(gr_unittest.TestCase): 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): if constellation.arity() > 256: # If this becomes limiting some of the blocks should be generalised so # that they can work with shorts and ints as well as chars. - raise ValueError("Constellation cannot contain more than 256 points.") + raise ValueError( + "Constellation cannot contain more than 256 points.") gr.hier_block2.__init__(self, "mod_demod", - gr.io_signature(1, 1, gr.sizeof_char), # Input signature + gr.io_signature( + 1, 1, gr.sizeof_char), # Input signature gr.io_signature(1, 1, gr.sizeof_char)) # Output signature arity = constellation.arity() @@ -334,13 +377,17 @@ class mod_demod(gr.hier_block2): # Apply any pre-differential coding # Gray-coding is done here if we're also using differential coding. if self.constellation.apply_pre_diff_code(): - self.blocks.append(digital.map_bb(self.constellation.pre_diff_code())) + self.blocks.append( + digital.map_bb( + self.constellation.pre_diff_code())) # Differential encoding. if self.differential: self.blocks.append(digital.diff_encoder_bb(arity)) # Convert to constellation symbols. - self.blocks.append(digital.chunks_to_symbols_bc(self.constellation.points(), - self.constellation.dimensionality())) + self.blocks.append( + digital.chunks_to_symbols_bc( + self.constellation.points(), + self.constellation.dimensionality())) # CHANNEL # Channel just consists of a rotation to check differential coding. if rotation is not None: @@ -348,7 +395,9 @@ class mod_demod(gr.hier_block2): # RX # Convert the constellation symbols back to binary values. - self.blocks.append(digital.constellation_decoder_cb(self.constellation.base())) + self.blocks.append( + digital.constellation_decoder_cb( + self.constellation.base())) # Differential decoding. if self.differential: self.blocks.append(digital.diff_decoder_bb(arity)) @@ -358,7 +407,7 @@ class mod_demod(gr.hier_block2): mod_codes.invert_code(self.constellation.pre_diff_code()))) # unpack the k bit vector into a stream of bits self.blocks.append(blocks.unpack_k_bits_bb( - self.constellation.bits_per_symbol())) + self.constellation.bits_per_symbol())) # connect to block output check_index = len(self.blocks) self.blocks = self.blocks[:check_index] @@ -366,5 +415,6 @@ class mod_demod(gr.hier_block2): self.connect(*self.blocks) + if __name__ == '__main__': gr_unittest.run(test_constellation) diff --git a/gr-digital/python/digital/qa_constellation_decoder_cb.py b/gr-digital/python/digital/qa_constellation_decoder_cb.py index 8e67531cd8..288c8fe5d7 100644 --- a/gr-digital/python/digital/qa_constellation_decoder_cb.py +++ b/gr-digital/python/digital/qa_constellation_decoder_cb.py @@ -11,6 +11,7 @@ from gnuradio import gr, gr_unittest, digital, blocks + class test_constellation_decoder(gr_unittest.TestCase): def setUp(self): @@ -21,10 +22,10 @@ class test_constellation_decoder(gr_unittest.TestCase): def test_constellation_decoder_cb_bpsk(self): cnst = digital.constellation_bpsk() - src_data = (0.5 + 0.5j, 0.1 - 1.2j, -0.8 - 0.1j, -0.45 + 0.8j, - 0.8 + 1.0j, -0.5 + 0.1j, 0.1 - 1.2j) - expected_result = ( 1, 1, 0, 0, - 1, 0, 1) + src_data = (0.5 + 0.5j, 0.1 - 1.2j, -0.8 - 0.1j, -0.45 + 0.8j, + 0.8 + 1.0j, -0.5 + 0.1j, 0.1 - 1.2j) + expected_result = (1, 1, 0, 0, + 1, 0, 1) src = blocks.vector_source_c(src_data) op = digital.constellation_decoder_cb(cnst.base()) dst = blocks.vector_sink_b() @@ -34,16 +35,16 @@ class test_constellation_decoder(gr_unittest.TestCase): self.tb.run() # run the graph and wait for it to finish actual_result = dst.data() # fetch the contents of the sink - #print "actual result", actual_result - #print "expected result", expected_result + # print "actual result", actual_result + # print "expected result", expected_result self.assertFloatTuplesAlmostEqual(expected_result, actual_result) def _test_constellation_decoder_cb_qpsk(self): cnst = digital.constellation_qpsk() - src_data = (0.5 + 0.5j, 0.1 - 1.2j, -0.8 - 0.1j, -0.45 + 0.8j, - 0.8 + 1.0j, -0.5 + 0.1j, 0.1 - 1.2j) - expected_result = ( 3, 1, 0, 2, - 3, 2, 1) + src_data = (0.5 + 0.5j, 0.1 - 1.2j, -0.8 - 0.1j, -0.45 + 0.8j, + 0.8 + 1.0j, -0.5 + 0.1j, 0.1 - 1.2j) + expected_result = (3, 1, 0, 2, + 3, 2, 1) src = blocks.vector_source_c(src_data) op = digital.constellation_decoder_cb(cnst.base()) dst = blocks.vector_sink_b() @@ -53,8 +54,8 @@ class test_constellation_decoder(gr_unittest.TestCase): self.tb.run() # run the graph and wait for it to finish actual_result = dst.data() # fetch the contents of the sink - #print "actual result", actual_result - #print "expected result", expected_result + # print "actual result", actual_result + # print "expected result", expected_result self.assertFloatTuplesAlmostEqual(expected_result, actual_result) diff --git a/gr-digital/python/digital/qa_constellation_receiver.py b/gr-digital/python/digital/qa_constellation_receiver.py index 8c22ebc68e..507fdd45b5 100644 --- a/gr-digital/python/digital/qa_constellation_receiver.py +++ b/gr-digital/python/digital/qa_constellation_receiver.py @@ -9,7 +9,6 @@ # - import random import math @@ -40,8 +39,8 @@ FREQUENCY_OFFSET = 0.01 TIMING_OFFSET = 1.0 # RECEIVER PARAMETERS -FREQ_BW = 2*math.pi/100.0 -PHASE_BW = 2*math.pi/100.0 +FREQ_BW = 2 * math.pi / 100.0 +PHASE_BW = 2 * math.pi / 100.0 class channel_model(gr.hier_block2): @@ -50,20 +49,19 @@ class channel_model(gr.hier_block2): gr.io_signature(1, 1, gr.sizeof_gr_complex), gr.io_signature(1, 1, gr.sizeof_gr_complex)) - timing_offset = filter.mmse_resampler_cc(0, timing) noise_adder = blocks.add_cc() noise = analog.noise_source_c(analog.GR_GAUSSIAN, noise_voltage, 0) freq_offset = analog.sig_source_c(1, analog.GR_SIN_WAVE, freq, 1.0, 0.0) - mixer_offset = blocks.multiply_cc(); + mixer_offset = blocks.multiply_cc() self.connect(self, timing_offset) - self.connect(timing_offset, (mixer_offset,0)) - self.connect(freq_offset, (mixer_offset,1)) - self.connect(mixer_offset, (noise_adder,1)) - self.connect(noise, (noise_adder,0)) + self.connect(timing_offset, (mixer_offset, 0)) + self.connect(freq_offset, (mixer_offset, 1)) + self.connect(mixer_offset, (noise_adder, 1)) + self.connect(noise, (noise_adder, 0)) self.connect(noise_adder, self) @@ -91,16 +89,24 @@ class test_constellation_receiver(gr_unittest.TestCase): # Assumes not more than 64 points in a constellation # Generates some random input data to use. self.src_data = tuple( - [rndm.randint(0,1) for i in range(0, self.max_data_length)]) + [rndm.randint(0, 1) for i in range(0, self.max_data_length)]) # Generates some random indices to use for comparing input and # output data (a full comparison is too slow in python). self.indices = alignment.random_sample( self.max_data_length, self.max_num_samples, SEED) requirements = ( - (EASY_REQ_CORRECT, tested_constellations(easy=True, medium=False, difficult=False)), - (MEDIUM_REQ_CORRECT, tested_constellations(easy=False, medium=True, difficult=False)), - ) + (EASY_REQ_CORRECT, + tested_constellations( + easy=True, + medium=False, + difficult=False)), + (MEDIUM_REQ_CORRECT, + tested_constellations( + easy=False, + medium=True, + difficult=False)), + ) for req_correct, tcs in requirements: for constellation, differential in tcs: # The constellation_receiver doesn't work for constellations @@ -116,19 +122,20 @@ class test_constellation_receiver(gr_unittest.TestCase): src_data=self.src_data[:data_length]) tb.run() data = tb.dst.data() - d1 = tb.src_data[:int(len(tb.src_data)*self.ignore_fraction)] - d2 = data[:int(len(data)*self.ignore_fraction)] + d1 = tb.src_data[:int(len(tb.src_data) * self.ignore_fraction)] + d2 = data[:int(len(data) * self.ignore_fraction)] correct, overlap, offset, indices = alignment.align_sequences( d1, d2, indices=self.indices) if correct <= req_correct: - print("Constellation is {0}. Differential is {1}. Required correct is {2}. Correct is {3}. FAIL.". - format(constellation, differential, req_correct, correct)) + print( + "Constellation is {0}. Differential is {1}. Required correct is {2}. Correct is {3}. FAIL.". format( + constellation, differential, req_correct, correct)) self.assertTrue(correct > req_correct) def test_tag(self): # Send data through bpsk receiver # followed by qpsk receiver - data = [0.9+0j, 0.1+0.9j, -1-0.1j, -0.1-0.6j]*2 + data = [0.9 + 0j, 0.1 + 0.9j, -1 - 0.1j, -0.1 - 0.6j] * 2 bpsk_data = [1, 1, 0, 0] qpsk_data = [1, 3, 0, 0] first_tag = gr.tag_t() @@ -146,13 +153,15 @@ class test_constellation_receiver(gr_unittest.TestCase): tb = gr.top_block() tb.connect(src, decoder, snk) tb.run() - self.assertEqual(list(snk.data()), bpsk_data+qpsk_data) + self.assertEqual(list(snk.data()), bpsk_data + qpsk_data) + class rec_test_tb(gr.top_block): """ Takes a constellation an runs a generic modulation, channel, and generic demodulation. """ + def __init__(self, constellation, differential, data_length=None, src_data=None, freq_offset=True): """ @@ -166,7 +175,8 @@ class rec_test_tb(gr.top_block): super(rec_test_tb, self).__init__() # Transmission Blocks if src_data is None: - self.src_data = tuple([random.randint(0,1) for i in range(0, data_length)]) + self.src_data = tuple([random.randint(0, 1) + for i in range(0, data_length)]) else: self.src_data = src_data packer = blocks.unpacked_to_packed_bb(1, gr.GR_MSB_FIRST) @@ -174,7 +184,8 @@ class rec_test_tb(gr.top_block): mod = generic_mod(constellation, differential=differential) # Channel if freq_offset: - channel = channel_model(NOISE_VOLTAGE, FREQUENCY_OFFSET, TIMING_OFFSET) + channel = channel_model( + NOISE_VOLTAGE, FREQUENCY_OFFSET, TIMING_OFFSET) else: channel = channel_model(NOISE_VOLTAGE, 0, TIMING_OFFSET) # Receiver Blocks @@ -188,5 +199,6 @@ class rec_test_tb(gr.top_block): self.dst = blocks.vector_sink_b() self.connect(src, packer, mod, channel, demod, self.dst) + if __name__ == '__main__': gr_unittest.run(test_constellation_receiver) diff --git a/gr-digital/python/digital/qa_constellation_soft_decoder_cf.py b/gr-digital/python/digital/qa_constellation_soft_decoder_cf.py index 034c455081..ca162f4ade 100644 --- a/gr-digital/python/digital/qa_constellation_soft_decoder_cf.py +++ b/gr-digital/python/digital/qa_constellation_soft_decoder_cf.py @@ -13,6 +13,7 @@ from gnuradio import gr, gr_unittest, digital, blocks from math import sqrt from numpy import random, vectorize + class test_constellation_soft_decoder(gr_unittest.TestCase): def setUp(self): @@ -42,8 +43,8 @@ class test_constellation_soft_decoder(gr_unittest.TestCase): self.tb.run() actual_result = dst.data() # fetch the contents of the sink - #print "actual result", actual_result - #print "expected result", expected_result + # print "actual result", actual_result + # print "expected result", expected_result self.assertFloatTuplesAlmostEqual(expected_result, actual_result, 5) def helper_no_lut(self, prec, src_data, const_gen, const_sd_gen): @@ -63,8 +64,8 @@ class test_constellation_soft_decoder(gr_unittest.TestCase): self.tb.run() actual_result = dst.data() # fetch the contents of the sink - #print "actual result", actual_result - #print "expected result", expected_result + # print "actual result", actual_result + # print "expected result", expected_result # Double vs. float precision issues between Python and C++, so # use only 4 decimals in comparisons. @@ -72,88 +73,141 @@ class test_constellation_soft_decoder(gr_unittest.TestCase): def test_constellation_soft_decoder_cf_bpsk_3(self): prec = 3 - src_data = (-1.0 - 1.0j, 1.0 - 1.0j, -1.0 + 1.0j, 1.0 + 1.0j, - -2.0 - 2.0j, 2.0 - 2.0j, -2.0 + 2.0j, 2.0 + 2.0j, - -0.2 - 0.2j, 0.2 - 0.2j, -0.2 + 0.2j, 0.2 + 0.2j, - 0.3 + 0.4j, 0.1 - 1.2j, -0.8 - 0.1j, -0.4 + 0.8j, - 0.8 + 1.0j, -0.5 + 0.1j, 0.1 + 1.2j, -1.7 - 0.9j) - self.helper_with_lut(prec, src_data, digital.psk_2_0x0, digital.sd_psk_2_0x0) + src_data = (-1.0 - 1.0j, 1.0 - 1.0j, -1.0 + 1.0j, 1.0 + 1.0j, + -2.0 - 2.0j, 2.0 - 2.0j, -2.0 + 2.0j, 2.0 + 2.0j, + -0.2 - 0.2j, 0.2 - 0.2j, -0.2 + 0.2j, 0.2 + 0.2j, + 0.3 + 0.4j, 0.1 - 1.2j, -0.8 - 0.1j, -0.4 + 0.8j, + 0.8 + 1.0j, -0.5 + 0.1j, 0.1 + 1.2j, -1.7 - 0.9j) + self.helper_with_lut( + prec, + src_data, + digital.psk_2_0x0, + digital.sd_psk_2_0x0) def test_constellation_soft_decoder_cf_bpsk_8(self): prec = 8 - src_data = (-1.0 - 1.0j, 1.0 - 1.0j, -1.0 + 1.0j, 1.0 + 1.0j, - -2.0 - 2.0j, 2.0 - 2.0j, -2.0 + 2.0j, 2.0 + 2.0j, - -0.2 - 0.2j, 0.2 - 0.2j, -0.2 + 0.2j, 0.2 + 0.2j, - 0.3 + 0.4j, 0.1 - 1.2j, -0.8 - 0.1j, -0.4 + 0.8j, - 0.8 + 1.0j, -0.5 + 0.1j, 0.1 + 1.2j, -1.7 - 0.9j) - self.helper_with_lut(prec, src_data, digital.psk_2_0x0, digital.sd_psk_2_0x0) + src_data = (-1.0 - 1.0j, 1.0 - 1.0j, -1.0 + 1.0j, 1.0 + 1.0j, + -2.0 - 2.0j, 2.0 - 2.0j, -2.0 + 2.0j, 2.0 + 2.0j, + -0.2 - 0.2j, 0.2 - 0.2j, -0.2 + 0.2j, 0.2 + 0.2j, + 0.3 + 0.4j, 0.1 - 1.2j, -0.8 - 0.1j, -0.4 + 0.8j, + 0.8 + 1.0j, -0.5 + 0.1j, 0.1 + 1.2j, -1.7 - 0.9j) + self.helper_with_lut( + prec, + src_data, + digital.psk_2_0x0, + digital.sd_psk_2_0x0) def test_constellation_soft_decoder_cf_bpsk_8_rand(self): prec = 8 - src_data = vectorize(complex)(2*random.randn(100), 2*random.randn(100)) - self.helper_with_lut(prec, src_data, digital.psk_2_0x0, digital.sd_psk_2_0x0) + src_data = vectorize(complex)( + 2 * random.randn(100), 2 * random.randn(100)) + self.helper_with_lut( + prec, + src_data, + digital.psk_2_0x0, + digital.sd_psk_2_0x0) def test_constellation_soft_decoder_cf_bpsk_8_rand2(self): prec = 8 - src_data = vectorize(complex)(2*random.randn(100), 2*random.randn(100)) - self.helper_no_lut(prec, src_data, digital.psk_2_0x0, digital.sd_psk_2_0x0) + src_data = vectorize(complex)( + 2 * random.randn(100), 2 * random.randn(100)) + self.helper_no_lut( + prec, + src_data, + digital.psk_2_0x0, + digital.sd_psk_2_0x0) def test_constellation_soft_decoder_cf_qpsk_3(self): prec = 3 - src_data = (-1.0 - 1.0j, 1.0 - 1.0j, -1.0 + 1.0j, 1.0 + 1.0j, - -2.0 - 2.0j, 2.0 - 2.0j, -2.0 + 2.0j, 2.0 + 2.0j, - -0.2 - 0.2j, 0.2 - 0.2j, -0.2 + 0.2j, 0.2 + 0.2j, - 0.3 + 0.4j, 0.1 - 1.2j, -0.8 - 0.1j, -0.4 + 0.8j, - 0.8 + 1.0j, -0.5 + 0.1j, 0.1 + 1.2j, -1.7 - 0.9j) - self.helper_with_lut(prec, src_data, digital.psk_4_0x0_0_1, digital.sd_psk_4_0x0_0_1) + src_data = (-1.0 - 1.0j, 1.0 - 1.0j, -1.0 + 1.0j, 1.0 + 1.0j, + -2.0 - 2.0j, 2.0 - 2.0j, -2.0 + 2.0j, 2.0 + 2.0j, + -0.2 - 0.2j, 0.2 - 0.2j, -0.2 + 0.2j, 0.2 + 0.2j, + 0.3 + 0.4j, 0.1 - 1.2j, -0.8 - 0.1j, -0.4 + 0.8j, + 0.8 + 1.0j, -0.5 + 0.1j, 0.1 + 1.2j, -1.7 - 0.9j) + self.helper_with_lut( + prec, + src_data, + digital.psk_4_0x0_0_1, + digital.sd_psk_4_0x0_0_1) def test_constellation_soft_decoder_cf_qpsk_8(self): prec = 8 - src_data = (-1.0 - 1.0j, 1.0 - 1.0j, -1.0 + 1.0j, 1.0 + 1.0j, - -2.0 - 2.0j, 2.0 - 2.0j, -2.0 + 2.0j, 2.0 + 2.0j, - -0.2 - 0.2j, 0.2 - 0.2j, -0.2 + 0.2j, 0.2 + 0.2j, - 0.3 + 0.4j, 0.1 - 1.2j, -0.8 - 0.1j, -0.4 + 0.8j, - 0.8 + 1.0j, -0.5 + 0.1j, 0.1 + 1.2j, -1.7 - 0.9j) - self.helper_with_lut(prec, src_data, digital.psk_4_0x0_0_1, digital.sd_psk_4_0x0_0_1) + src_data = (-1.0 - 1.0j, 1.0 - 1.0j, -1.0 + 1.0j, 1.0 + 1.0j, + -2.0 - 2.0j, 2.0 - 2.0j, -2.0 + 2.0j, 2.0 + 2.0j, + -0.2 - 0.2j, 0.2 - 0.2j, -0.2 + 0.2j, 0.2 + 0.2j, + 0.3 + 0.4j, 0.1 - 1.2j, -0.8 - 0.1j, -0.4 + 0.8j, + 0.8 + 1.0j, -0.5 + 0.1j, 0.1 + 1.2j, -1.7 - 0.9j) + self.helper_with_lut( + prec, + src_data, + digital.psk_4_0x0_0_1, + digital.sd_psk_4_0x0_0_1) def test_constellation_soft_decoder_cf_qpsk_8_rand(self): prec = 8 - src_data = vectorize(complex)(2*random.randn(100), 2*random.randn(100)) - self.helper_with_lut(prec, src_data, digital.psk_4_0x0_0_1, digital.sd_psk_4_0x0_0_1) + src_data = vectorize(complex)( + 2 * random.randn(100), 2 * random.randn(100)) + self.helper_with_lut( + prec, + src_data, + digital.psk_4_0x0_0_1, + digital.sd_psk_4_0x0_0_1) def test_constellation_soft_decoder_cf_qpsk_8_rand2(self): prec = 8 - src_data = vectorize(complex)(2*random.randn(100), 2*random.randn(100)) - self.helper_no_lut(prec, src_data, digital.psk_4_0x0_0_1, digital.sd_psk_4_0x0_0_1) + src_data = vectorize(complex)( + 2 * random.randn(100), 2 * random.randn(100)) + self.helper_no_lut( + prec, + src_data, + digital.psk_4_0x0_0_1, + digital.sd_psk_4_0x0_0_1) def test_constellation_soft_decoder_cf_qam16_3(self): prec = 3 - src_data = (-1.0 - 1.0j, 1.0 - 1.0j, -1.0 + 1.0j, 1.0 + 1.0j, - -2.0 - 2.0j, 2.0 - 2.0j, -2.0 + 2.0j, 2.0 + 2.0j, - -0.2 - 0.2j, 0.2 - 0.2j, -0.2 + 0.2j, 0.2 + 0.2j, - 0.3 + 0.4j, 0.1 - 1.2j, -0.8 - 0.1j, -0.4 + 0.8j, - 0.8 + 1.0j, -0.5 + 0.1j, 0.1 + 1.2j, -1.7 - 0.9j) - self.helper_with_lut(prec, src_data, digital.qam_16_0x0_0_1_2_3, digital.sd_qam_16_0x0_0_1_2_3) + src_data = (-1.0 - 1.0j, 1.0 - 1.0j, -1.0 + 1.0j, 1.0 + 1.0j, + -2.0 - 2.0j, 2.0 - 2.0j, -2.0 + 2.0j, 2.0 + 2.0j, + -0.2 - 0.2j, 0.2 - 0.2j, -0.2 + 0.2j, 0.2 + 0.2j, + 0.3 + 0.4j, 0.1 - 1.2j, -0.8 - 0.1j, -0.4 + 0.8j, + 0.8 + 1.0j, -0.5 + 0.1j, 0.1 + 1.2j, -1.7 - 0.9j) + self.helper_with_lut( + prec, + src_data, + digital.qam_16_0x0_0_1_2_3, + digital.sd_qam_16_0x0_0_1_2_3) def test_constellation_soft_decoder_cf_qam16_8(self): prec = 8 - src_data = (-1.0 - 1.0j, 1.0 - 1.0j, -1.0 + 1.0j, 1.0 + 1.0j, - -2.0 - 2.0j, 2.0 - 2.0j, -2.0 + 2.0j, 2.0 + 2.0j, - -0.2 - 0.2j, 0.2 - 0.2j, -0.2 + 0.2j, 0.2 + 0.2j, - 0.3 + 0.4j, 0.1 - 1.2j, -0.8 - 0.1j, -0.4 + 0.8j, - 0.8 + 1.0j, -0.5 + 0.1j, 0.1 + 1.2j, -1.7 - 0.9j) - self.helper_with_lut(prec, src_data, digital.qam_16_0x0_0_1_2_3, digital.sd_qam_16_0x0_0_1_2_3) + src_data = (-1.0 - 1.0j, 1.0 - 1.0j, -1.0 + 1.0j, 1.0 + 1.0j, + -2.0 - 2.0j, 2.0 - 2.0j, -2.0 + 2.0j, 2.0 + 2.0j, + -0.2 - 0.2j, 0.2 - 0.2j, -0.2 + 0.2j, 0.2 + 0.2j, + 0.3 + 0.4j, 0.1 - 1.2j, -0.8 - 0.1j, -0.4 + 0.8j, + 0.8 + 1.0j, -0.5 + 0.1j, 0.1 + 1.2j, -1.7 - 0.9j) + self.helper_with_lut( + prec, + src_data, + digital.qam_16_0x0_0_1_2_3, + digital.sd_qam_16_0x0_0_1_2_3) def test_constellation_soft_decoder_cf_qam16_8_rand(self): prec = 8 - src_data = vectorize(complex)(2*random.randn(100), 2*random.randn(100)) - self.helper_with_lut(prec, src_data, digital.qam_16_0x0_0_1_2_3, digital.sd_qam_16_0x0_0_1_2_3) + src_data = vectorize(complex)( + 2 * random.randn(100), 2 * random.randn(100)) + self.helper_with_lut( + prec, + src_data, + digital.qam_16_0x0_0_1_2_3, + digital.sd_qam_16_0x0_0_1_2_3) def test_constellation_soft_decoder_cf_qam16_8_rand2(self): prec = 8 #src_data = vectorize(complex)(2*random.randn(100), 2*random.randn(100)) - src_data = vectorize(complex)(2*random.randn(2), 2*random.randn(2)) - self.helper_no_lut(prec, src_data, digital.qam_16_0x0_0_1_2_3, digital.sd_qam_16_0x0_0_1_2_3) + src_data = vectorize(complex)(2 * random.randn(2), 2 * random.randn(2)) + self.helper_no_lut( + prec, + src_data, + digital.qam_16_0x0_0_1_2_3, + digital.sd_qam_16_0x0_0_1_2_3) if __name__ == '__main__': diff --git a/gr-digital/python/digital/qa_correlate_access_code.py b/gr-digital/python/digital/qa_correlate_access_code.py index 0fb7f64d61..51b7c4dd4f 100644 --- a/gr-digital/python/digital/qa_correlate_access_code.py +++ b/gr-digital/python/digital/qa_correlate_access_code.py @@ -13,6 +13,7 @@ from gnuradio import gr, gr_unittest, digital, blocks default_access_code = '\xAC\xDD\xA4\xE2\xF2\x8C\x20\xFC' + def string_to_1_0_list(s): r = [] for ch in s: @@ -23,9 +24,11 @@ def string_to_1_0_list(s): return r + def to_1_0_string(L): return ''.join([chr(x + ord('0')) for x in L]) + class test_correlate_access_code(gr_unittest.TestCase): def setUp(self): @@ -35,10 +38,10 @@ class test_correlate_access_code(gr_unittest.TestCase): self.tb = None def test_001(self): - pad = [0,] * 64 + pad = [0, ] * 64 # 0 0 0 1 0 0 0 1 - src_data = [1, 0, 1, 1, 1, 1, 0, 1, 1] + pad + [0,] * 7 - expected_result = pad + [1, 0, 1, 1, 3, 1, 0, 1, 1, 2] + [0,] * 6 + src_data = [1, 0, 1, 1, 1, 1, 0, 1, 1] + pad + [0, ] * 7 + expected_result = pad + [1, 0, 1, 1, 3, 1, 0, 1, 1, 2] + [0, ] * 6 src = blocks.vector_source_b(src_data) op = digital.correlate_access_code_bb("1011", 0) dst = blocks.vector_sink_b() @@ -47,13 +50,12 @@ class test_correlate_access_code(gr_unittest.TestCase): result_data = dst.data() self.assertEqual(expected_result, result_data) - def test_002(self): code = list(string_to_1_0_list(default_access_code)) access_code = to_1_0_string(code) - pad = [0,] * 64 - #print code - #print access_code + pad = [0, ] * 64 + # print code + # print access_code src_data = code + [1, 0, 1, 1] + pad expected_result = pad + code + [3, 0, 1, 1] src = blocks.vector_source_b(src_data) @@ -67,9 +69,9 @@ class test_correlate_access_code(gr_unittest.TestCase): def test_003(self): code = list(string_to_1_0_list(default_access_code)) access_code = to_1_0_string(code) - pad = [0,] * 64 - #print code - #print access_code + pad = [0, ] * 64 + # print code + # print access_code src_data = code + [1, 0, 1, 1] + pad expected_result = code + [1, 0, 1, 1] + pad src = blocks.vector_source_b(src_data) @@ -83,13 +85,13 @@ class test_correlate_access_code(gr_unittest.TestCase): def test_004(self): code = list(string_to_1_0_list(default_access_code)) access_code = to_1_0_string(code) - pad = [0,] * 64 - #print code - #print access_code + pad = [0, ] * 64 + # print code + # print access_code src_bits = code + [1, 0, 1, 1] + pad - src_data = [2.0*x - 1.0 for x in src_bits] + src_data = [2.0 * x - 1.0 for x in src_bits] expected_result_bits = code + [1, 0, 1, 1] + pad - expected_result = [2.0*x - 1.0 for x in expected_result_bits] + expected_result = [2.0 * x - 1.0 for x in expected_result_bits] src = blocks.vector_source_f(src_data) op = digital.correlate_access_code_tag_ff(access_code, 0, "test") dst = blocks.vector_sink_f() @@ -98,6 +100,6 @@ class test_correlate_access_code(gr_unittest.TestCase): result_data = dst.data() self.assertFloatTuplesAlmostEqual(expected_result, result_data, 5) + if __name__ == '__main__': gr_unittest.run(test_correlate_access_code) - diff --git a/gr-digital/python/digital/qa_correlate_access_code_XX_ts.py b/gr-digital/python/digital/qa_correlate_access_code_XX_ts.py index f3780d36ec..5681d6bbef 100644 --- a/gr-digital/python/digital/qa_correlate_access_code_XX_ts.py +++ b/gr-digital/python/digital/qa_correlate_access_code_XX_ts.py @@ -14,6 +14,7 @@ import pmt default_access_code = '\xAC\xDD\xA4\xE2\xF2\x8C\x20\xFC' + def string_to_1_0_list(s): r = [] for ch in s: @@ -23,9 +24,11 @@ def string_to_1_0_list(s): r.append(t) return r + def to_1_0_string(L): return ''.join([chr(x + ord('0')) for x in L]) + class test_correlate_access_code_XX_ts(gr_unittest.TestCase): def setUp(self): @@ -36,11 +39,13 @@ class test_correlate_access_code_XX_ts(gr_unittest.TestCase): def test_001(self): payload = "test packet" # payload length is 11 bytes - header = "\x00\xd0\x00\xd0" # header contains packet length, twice (bit-swapped) + # header contains packet length, twice (bit-swapped) + header = "\x00\xd0\x00\xd0" packet = header + payload pad = (0,) * 64 - src_data = (0, 0, 1, 1, 1, 1, 0, 1, 1) + tuple(string_to_1_0_list(packet)) + pad - expected = list(map(int, src_data[9+32:-len(pad)])) + src_data = (0, 0, 1, 1, 1, 1, 0, 1, 1) + \ + tuple(string_to_1_0_list(packet)) + pad + expected = list(map(int, src_data[9 + 32:-len(pad)])) src = blocks.vector_source_b(src_data) op = digital.correlate_access_code_bb_ts("1011", 0, "sync") dst = blocks.vector_sink_b() @@ -48,18 +53,20 @@ class test_correlate_access_code_XX_ts(gr_unittest.TestCase): self.tb.run() result_data = dst.data() result_tags = dst.tags() - self.assertEqual(len(result_data), len(payload)*8) + self.assertEqual(len(result_data), len(payload) * 8) self.assertEqual(result_tags[0].offset, 0) - self.assertEqual(pmt.to_long(result_tags[0].value), len(payload)*8) + self.assertEqual(pmt.to_long(result_tags[0].value), len(payload) * 8) self.assertEqual(result_data, expected) def test_bb_prefix(self): payload = "test packet" # payload length is 11 bytes - header = "\x00\xd0\x00\xd0" # header contains packet length, twice (bit-swapped) + # header contains packet length, twice (bit-swapped) + header = "\x00\xd0\x00\xd0" packet = header + payload pad = (0,) * 64 - src_data = (0, 1, 1, 1, 0, 0, 0, 1, 1) + tuple(string_to_1_0_list(packet)) + pad - expected = list(map(int, src_data[9+32:-len(pad)])) + src_data = (0, 1, 1, 1, 0, 0, 0, 1, 1) + \ + tuple(string_to_1_0_list(packet)) + pad + expected = list(map(int, src_data[9 + 32:-len(pad)])) src = blocks.vector_source_b(src_data) op = digital.correlate_access_code_bb_ts("0011", 0, "sync") dst = blocks.vector_sink_b() @@ -67,19 +74,20 @@ class test_correlate_access_code_XX_ts(gr_unittest.TestCase): self.tb.run() result_data = dst.data() result_tags = dst.tags() - self.assertEqual(len(result_data), len(payload)*8) + self.assertEqual(len(result_data), len(payload) * 8) self.assertEqual(result_tags[0].offset, 0) - self.assertEqual(pmt.to_long(result_tags[0].value), len(payload)*8) + self.assertEqual(pmt.to_long(result_tags[0].value), len(payload) * 8) self.assertEqual(result_data, expected) def test_bb_immediate(self): """Test that packets at start of stream match""" payload = "test packet" # payload length is 11 bytes - header = "\x00\xd0\x00\xd0" # header contains packet length, twice (bit-swapped) + # header contains packet length, twice (bit-swapped) + header = "\x00\xd0\x00\xd0" packet = header + payload pad = (0,) * 64 src_data = (0, 0, 1, 1) + tuple(string_to_1_0_list(packet)) + pad - expected = list(map(int, src_data[4+32:-len(pad)])) + expected = list(map(int, src_data[4 + 32:-len(pad)])) src = blocks.vector_source_b(src_data) op = digital.correlate_access_code_bb_ts("0011", 0, "sync") dst = blocks.vector_sink_b() @@ -94,12 +102,15 @@ class test_correlate_access_code_XX_ts(gr_unittest.TestCase): def test_002(self): payload = "test packet" # payload length is 11 bytes - header = "\x00\xd0\x00\xd0" # header contains packet length, twice (bit-swapped) + # header contains packet length, twice (bit-swapped) + header = "\x00\xd0\x00\xd0" packet = header + payload pad = (0,) * 64 - src_data = (0, 0, 1, 1, 1, 1, 0, 1, 1) + tuple(string_to_1_0_list(packet)) + pad - src_floats = tuple(2*b-1 for b in src_data) # convert to binary antipodal symbols (-1,1) - expected = src_floats[9+32:-len(pad)] + src_data = (0, 0, 1, 1, 1, 1, 0, 1, 1) + \ + tuple(string_to_1_0_list(packet)) + pad + # convert to binary antipodal symbols (-1,1) + src_floats = tuple(2 * b - 1 for b in src_data) + expected = src_floats[9 + 32:-len(pad)] src = blocks.vector_source_f(src_floats) op = digital.correlate_access_code_ff_ts("1011", 0, "sync") dst = blocks.vector_sink_f() @@ -107,19 +118,22 @@ class test_correlate_access_code_XX_ts(gr_unittest.TestCase): self.tb.run() result_data = dst.data() result_tags = dst.tags() - self.assertEqual(len(result_data), len(payload)*8) + self.assertEqual(len(result_data), len(payload) * 8) self.assertEqual(result_tags[0].offset, 0) - self.assertEqual(pmt.to_long(result_tags[0].value), len(payload)*8) + self.assertEqual(pmt.to_long(result_tags[0].value), len(payload) * 8) self.assertFloatTuplesAlmostEqual(result_data, expected, 5) def test_ff_prefix(self): payload = "test packet" # payload length is 11 bytes - header = "\x00\xd0\x00\xd0" # header contains packet length, twice (bit-swapped) + # header contains packet length, twice (bit-swapped) + header = "\x00\xd0\x00\xd0" packet = header + payload pad = (0,) * 64 - src_data = (0, 1, 1, 1, 1, 0, 0, 1, 1) + tuple(string_to_1_0_list(packet)) + pad - src_floats = tuple(2*b-1 for b in src_data) # convert to binary antipodal symbols (-1,1) - expected = src_floats[9+32:-len(pad)] + src_data = (0, 1, 1, 1, 1, 0, 0, 1, 1) + \ + tuple(string_to_1_0_list(packet)) + pad + # convert to binary antipodal symbols (-1,1) + src_floats = tuple(2 * b - 1 for b in src_data) + expected = src_floats[9 + 32:-len(pad)] src = blocks.vector_source_f(src_floats) op = digital.correlate_access_code_ff_ts("0011", 0, "sync") dst = blocks.vector_sink_f() @@ -127,20 +141,22 @@ class test_correlate_access_code_XX_ts(gr_unittest.TestCase): self.tb.run() result_data = dst.data() result_tags = dst.tags() - self.assertEqual(len(result_data), len(payload)*8) + self.assertEqual(len(result_data), len(payload) * 8) self.assertEqual(result_tags[0].offset, 0) - self.assertEqual(pmt.to_long(result_tags[0].value), len(payload)*8) + self.assertEqual(pmt.to_long(result_tags[0].value), len(payload) * 8) self.assertFloatTuplesAlmostEqual(result_data, expected, 5) def test_ff_immediate(self): """Test that packets at start of stream match""" payload = "test packet" # payload length is 11 bytes - header = "\x00\xd0\x00\xd0" # header contains packet length, twice (bit-swapped) + # header contains packet length, twice (bit-swapped) + header = "\x00\xd0\x00\xd0" packet = header + payload pad = (0,) * 64 src_data = (0, 0, 1, 1) + tuple(string_to_1_0_list(packet)) + pad - src_floats = tuple(2*b-1 for b in src_data) # convert to binary antipodal symbols (-1,1) - expected = src_floats[4+32:-len(pad)] + # convert to binary antipodal symbols (-1,1) + src_floats = tuple(2 * b - 1 for b in src_data) + expected = src_floats[4 + 32:-len(pad)] src = blocks.vector_source_f(src_floats) op = digital.correlate_access_code_ff_ts("0011", 0, "sync") dst = blocks.vector_sink_f() @@ -148,9 +164,9 @@ class test_correlate_access_code_XX_ts(gr_unittest.TestCase): self.tb.run() result_data = dst.data() result_tags = dst.tags() - self.assertEqual(len(result_data), len(payload)*8) + self.assertEqual(len(result_data), len(payload) * 8) self.assertEqual(result_tags[0].offset, 0) - self.assertEqual(pmt.to_long(result_tags[0].value), len(payload)*8) + self.assertEqual(pmt.to_long(result_tags[0].value), len(payload) * 8) self.assertFloatTuplesAlmostEqual(result_data, expected, 5) diff --git a/gr-digital/python/digital/qa_correlate_access_code_tag.py b/gr-digital/python/digital/qa_correlate_access_code_tag.py index e35205a8b0..31b18c71a7 100644 --- a/gr-digital/python/digital/qa_correlate_access_code_tag.py +++ b/gr-digital/python/digital/qa_correlate_access_code_tag.py @@ -13,6 +13,7 @@ from gnuradio import gr, gr_unittest, digital, blocks default_access_code = '\xAC\xDD\xA4\xE2\xF2\x8C\x20\xFC' + def string_to_1_0_list(s): r = [] for ch in s: @@ -23,9 +24,11 @@ def string_to_1_0_list(s): return r + def to_1_0_string(L): return ''.join([chr(x + ord('0')) for x in L]) + class test_correlate_access_code(gr_unittest.TestCase): def setUp(self): @@ -76,8 +79,8 @@ class test_correlate_access_code(gr_unittest.TestCase): code = tuple(string_to_1_0_list(default_access_code)) access_code = to_1_0_string(code) pad = (0,) * 64 - #print code - #print access_code + # print code + # print access_code src_data = code + (1, 0, 1, 1) + pad src = blocks.vector_source_b(src_data) op = digital.correlate_access_code_tag_bb(access_code, 0, "sync") @@ -91,7 +94,7 @@ class test_correlate_access_code(gr_unittest.TestCase): def test_ff(self): pad = (0,) * 64 src_bits = (1, 0, 1, 1, 1, 1, 0, 1, 1) + pad + (0,) * 7 - src_data = [2.0*x - 1.0 for x in src_bits] + src_data = [2.0 * x - 1.0 for x in src_bits] src = blocks.vector_source_f(src_data) op = digital.correlate_access_code_tag_ff("1011", 0, "sync") dst = blocks.tag_debug(gr.sizeof_float, "sync") @@ -105,7 +108,7 @@ class test_correlate_access_code(gr_unittest.TestCase): def test_ff_skip_prefix(self): pad = (0,) * 64 src_bits = (0, 1, 1, 1, 1, 0, 0, 1, 1) + pad + (0,) * 7 - src_data = [2.0*x - 1.0 for x in src_bits] + src_data = [2.0 * x - 1.0 for x in src_bits] src = blocks.vector_source_f(src_data) op = digital.correlate_access_code_tag_ff("0011", 0, "sync") dst = blocks.tag_debug(gr.sizeof_float, "sync") @@ -119,7 +122,7 @@ class test_correlate_access_code(gr_unittest.TestCase): """Test that packets at start of stream match""" pad = (0,) * 64 src_bits = (0, 0, 1, 1) + pad + (0,) * 7 - src_data = [2.0*x - 1.0 for x in src_bits] + src_data = [2.0 * x - 1.0 for x in src_bits] src = blocks.vector_source_f(src_data) op = digital.correlate_access_code_tag_ff("0011", 0, "sync") dst = blocks.tag_debug(gr.sizeof_float, "sync") @@ -133,10 +136,10 @@ class test_correlate_access_code(gr_unittest.TestCase): code = tuple(string_to_1_0_list(default_access_code)) access_code = to_1_0_string(code) pad = (0,) * 64 - #print code - #print access_code + # print code + # print access_code src_bits = code + (1, 0, 1, 1) + pad - src_data = [2.0*x - 1.0 for x in src_bits] + src_data = [2.0 * x - 1.0 for x in src_bits] src = blocks.vector_source_f(src_data) op = digital.correlate_access_code_tag_ff(access_code, 0, "sync") dst = blocks.tag_debug(gr.sizeof_float, "sync") @@ -146,5 +149,6 @@ class test_correlate_access_code(gr_unittest.TestCase): self.assertEqual(len(result_data), 1) self.assertEqual(result_data[0].offset, len(code)) + if __name__ == '__main__': gr_unittest.run(test_correlate_access_code) diff --git a/gr-digital/python/digital/qa_costas_loop_cc.py b/gr-digital/python/digital/qa_costas_loop_cc.py index a71e3f4596..6c82992917 100644 --- a/gr-digital/python/digital/qa_costas_loop_cc.py +++ b/gr-digital/python/digital/qa_costas_loop_cc.py @@ -15,6 +15,7 @@ import cmath from gnuradio import gr, gr_unittest, digital, blocks from gnuradio.digital import psk + class test_costas_loop_cc(gr_unittest.TestCase): def setUp(self): @@ -30,7 +31,7 @@ class test_costas_loop_cc(gr_unittest.TestCase): order = 2 self.test = digital.costas_loop_cc(natfreq, order) - data = 100*[complex(1,0),] + data = 100 * [complex(1, 0), ] self.src = blocks.vector_source_c(data, False) self.snk = blocks.vector_sink_c() @@ -47,7 +48,7 @@ class test_costas_loop_cc(gr_unittest.TestCase): order = 2 self.test = digital.costas_loop_cc(natfreq, order) - data = [complex(2*random.randint(0,1)-1, 0) for i in range(100)] + data = [complex(2 * random.randint(0, 1) - 1, 0) for i in range(100)] self.src = blocks.vector_source_c(data, False) self.snk = blocks.vector_sink_c() @@ -65,12 +66,12 @@ class test_costas_loop_cc(gr_unittest.TestCase): order = 2 self.test = digital.costas_loop_cc(natfreq, order) - rot = cmath.exp(0.2j) # some small rotation - data = [complex(2*random.randint(0,1)-1, 0) for i in range(100)] + rot = cmath.exp(0.2j) # some small rotation + data = [complex(2 * random.randint(0, 1) - 1, 0) for i in range(100)] - N = 40 # settling time + N = 40 # settling time expected_result = data[N:] - data = [rot*d for d in data] + data = [rot * d for d in data] self.src = blocks.vector_source_c(data, False) self.snk = blocks.vector_sink_c() @@ -90,13 +91,23 @@ class test_costas_loop_cc(gr_unittest.TestCase): order = 4 self.test = digital.costas_loop_cc(natfreq, order) - rot = cmath.exp(0.2j) # some small rotation - data = [complex(2*random.randint(0,1)-1, 2*random.randint(0,1)-1) - for i in range(100)] - - N = 40 # settling time + rot = cmath.exp(0.2j) # some small rotation + data = [ + complex( + 2 * + random.randint( + 0, + 1) - + 1, + 2 * + random.randint( + 0, + 1) - + 1) for i in range(100)] + + N = 40 # settling time expected_result = data[N:] - data = [rot*d for d in data] + data = [rot * d for d in data] self.src = blocks.vector_source_c(data, False) self.snk = blocks.vector_sink_c() @@ -116,16 +127,16 @@ class test_costas_loop_cc(gr_unittest.TestCase): order = 8 self.test = digital.costas_loop_cc(natfreq, order) - rot = cmath.exp(-cmath.pi / 8.0j) # rotate to match Costas rotation + rot = cmath.exp(-cmath.pi / 8.0j) # rotate to match Costas rotation const = psk.psk_constellation(order) - data = [random.randint(0,7) for i in range(100)] - data = [2*rot*const.points()[d] for d in data] + data = [random.randint(0, 7) for i in range(100)] + data = [2 * rot * const.points()[d] for d in data] - N = 40 # settling time + N = 40 # settling time expected_result = data[N:] - rot = cmath.exp(0.1j) # some small rotation - data = [rot*d for d in data] + rot = cmath.exp(0.1j) # some small rotation + data = [rot * d for d in data] self.src = blocks.vector_source_c(data, False) self.snk = blocks.vector_sink_c() @@ -135,9 +146,10 @@ class test_costas_loop_cc(gr_unittest.TestCase): dst_data = self.snk.data()[N:] - # generously compare results; the loop will converge near to, but + # generously compare results; the loop will converge near to, but # not exactly on, the target data self.assertComplexTuplesAlmostEqual(expected_result, dst_data, 2) + if __name__ == '__main__': gr_unittest.run(test_costas_loop_cc) diff --git a/gr-digital/python/digital/qa_cpm.py b/gr-digital/python/digital/qa_cpm.py index 420b78d10b..e41e7e8f35 100644 --- a/gr-digital/python/digital/qa_cpm.py +++ b/gr-digital/python/digital/qa_cpm.py @@ -1,18 +1,19 @@ #!/usr/bin/env python # # Copyright 2010,2013 Free Software Foundation, Inc. -# +# # This file is part of GNU Radio -# +# # SPDX-License-Identifier: GPL-3.0-or-later # -# +# import numpy from gnuradio import gr, gr_unittest, digital, analog, blocks + class test_cpm(gr_unittest.TestCase): def setUp(self): @@ -33,11 +34,18 @@ class test_cpm(gr_unittest.TestCase): self.tb.connect(src, cpm, arg, sink) self.tb.run() - symbol_phases = numpy.array(sink.data()[sps*L-1::sps]) + symbol_phases = numpy.array(sink.data()[sps * L - 1::sps]) phase_diff = numpy.mod(numpy.subtract(symbol_phases[1:], symbol_phases[:-1]), - (2*numpy.pi,) * (len(symbol_phases)-1)) - self.assertFloatTuplesAlmostEqual(tuple(phase_diff), (0.5 * numpy.pi,) * len(phase_diff), 5, - msg="Phase shift was not correct for CPM method " + name) + (2 * numpy.pi,) * (len(symbol_phases) - 1)) + self.assertFloatTuplesAlmostEqual( + tuple(phase_diff), + (0.5 * + numpy.pi, + ) * + len(phase_diff), + 5, + msg="Phase shift was not correct for CPM method " + + name) def test_001_lrec(self): self.do_check_phase_shift(analog.cpm.LRC, 'LREC') @@ -64,11 +72,15 @@ class test_cpm(gr_unittest.TestCase): self.tb.connect(src, gmsk, arg, sink) self.tb.run() - symbol_phases = numpy.array(sink.data()[sps*L-1::sps]) + symbol_phases = numpy.array(sink.data()[sps * L - 1::sps]) phase_diff = numpy.mod(numpy.subtract(symbol_phases[1:], symbol_phases[:-1]), - (2*numpy.pi,) * (len(symbol_phases)-1)) - self.assertFloatTuplesAlmostEqual(tuple(phase_diff), (0.5 * numpy.pi,) * len(phase_diff), 5, - msg="Phase shift was not correct for GMSK") + (2 * numpy.pi,) * (len(symbol_phases) - 1)) + self.assertFloatTuplesAlmostEqual( + tuple(phase_diff), + (0.5 * numpy.pi, + ) * len(phase_diff), + 5, + msg="Phase shift was not correct for GMSK") def test_phase_response(self): phase_response = analog.cpm.phase_response(analog.cpm.LREC, 2, 4) @@ -77,4 +89,3 @@ class test_cpm(gr_unittest.TestCase): if __name__ == '__main__': gr_unittest.run(test_cpm) - diff --git a/gr-digital/python/digital/qa_crc32.py b/gr-digital/python/digital/qa_crc32.py index f5340082be..8207a34e73 100644 --- a/gr-digital/python/digital/qa_crc32.py +++ b/gr-digital/python/digital/qa_crc32.py @@ -1,18 +1,19 @@ #!/usr/bin/env python # # Copyright 2011 Free Software Foundation, Inc. -# +# # This file is part of GNU Radio -# +# # SPDX-License-Identifier: GPL-3.0-or-later # -# +# import cmath from gnuradio import gr, gr_unittest, digital + class test_crc32(gr_unittest.TestCase): def setUp(self): @@ -22,28 +23,29 @@ class test_crc32(gr_unittest.TestCase): self.tb = None def test01(self): - data = 100*"0" + data = 100 * "0" expected_result = 2943744955 result = digital.crc32(data) - #print hex(result) - + # print hex(result) + self.assertEqual(expected_result, result) def test02(self): - data = 100*"1" + data = 100 * "1" expected_result = 2326594156 result = digital.crc32(data) - #print hex(result) - + # print hex(result) + self.assertEqual(expected_result, result) def test03(self): - data = 10*"0123456789" + data = 10 * "0123456789" expected_result = 3774345973 result = digital.crc32(data) - #print hex(result) + # print hex(result) self.assertEqual(expected_result, result) + if __name__ == '__main__': gr_unittest.run(test_crc32) diff --git a/gr-digital/python/digital/qa_crc32_bb.py b/gr-digital/python/digital/qa_crc32_bb.py index ba498aeec1..b83372ebdc 100644 --- a/gr-digital/python/digital/qa_crc32_bb.py +++ b/gr-digital/python/digital/qa_crc32_bb.py @@ -31,7 +31,8 @@ class qa_crc32_bb(gr_unittest.TestCase): blocks.stream_to_tagged_stream(gr.sizeof_char, 1, len(data), self.tsb_key), crc, sink) self.tb.run() - # Check that the packets before crc_check are 4 bytes longer that the input. + # Check that the packets before crc_check are 4 bytes longer that the + # input. self.assertEqual(len(data) + 4, len(sink.data()[0])) def test_002_crc_equal(self): @@ -53,7 +54,7 @@ class qa_crc32_bb(gr_unittest.TestCase): def test_003_crc_correct_lentag(self): tag_name = "length" pack_len = 8 - packets = list(range(pack_len*2)) + packets = list(range(pack_len * 2)) tag1 = gr.tag_t() tag1.offset = 0 tag1.key = pmt.string_to_symbol(tag_name) @@ -132,7 +133,8 @@ class qa_crc32_bb(gr_unittest.TestCase): if pmt.symbol_to_string(tag.key) == 'tag1' ]) - # NOTE: What follows are the same tests as before but with the packed flag set to False + # NOTE: What follows are the same tests as before but with the packed flag + # set to False def test_006_crc_len(self): """ Make sure the output of a CRC set is 32 (unpacked) bytes longer than the input. """ @@ -145,7 +147,8 @@ class qa_crc32_bb(gr_unittest.TestCase): blocks.stream_to_tagged_stream(gr.sizeof_char, 1, len(data), self.tsb_key), crc, sink) self.tb.run() - # Check that the packets before crc_check are 4 bytes longer that the input. + # Check that the packets before crc_check are 4 bytes longer that the + # input. self.assertEqual(len(data) + 32, len(sink.data()[0])) def test_007_crc_equal(self): @@ -164,13 +167,15 @@ class qa_crc32_bb(gr_unittest.TestCase): # Check that the packets after crc_check are the same as input. self.assertEqual(data, sink.data()[0]) - def test_002_crc_equal_unpacked (self): + def test_002_crc_equal_unpacked(self): """ Test unpacked operation with packed operation """ data = [0, 1, 2, 3, 4, 5, 6, 7, 8] src = blocks.vector_source_b(data) - unpack1 = blocks.repack_bits_bb(8, 1, self.tsb_key, False, gr.GR_LSB_FIRST) - unpack2 = blocks.repack_bits_bb(8, 1, self.tsb_key, False, gr.GR_LSB_FIRST) + unpack1 = blocks.repack_bits_bb( + 8, 1, self.tsb_key, False, gr.GR_LSB_FIRST) + unpack2 = blocks.repack_bits_bb( + 8, 1, self.tsb_key, False, gr.GR_LSB_FIRST) crc_unpacked = digital.crc32_bb(False, self.tsb_key, False) crc_packed = digital.crc32_bb(False, self.tsb_key, True) sink1 = blocks.tsb_vector_sink_b(tsb_key=self.tsb_key) @@ -212,10 +217,10 @@ class qa_crc32_bb(gr_unittest.TestCase): self.tb.run() self.assertEqual(sink1.data(), sink2.data()) - def test_008_crc_correct_lentag (self): + def test_008_crc_correct_lentag(self): tag_name = "length" pack_len = 8 - packets = list(range(pack_len*2)) + packets = list(range(pack_len * 2)) tag1 = gr.tag_t() tag1.offset = 0 tag1.key = pmt.string_to_symbol(tag_name) diff --git a/gr-digital/python/digital/qa_decision_feedback_equalizer.py b/gr-digital/python/digital/qa_decision_feedback_equalizer.py index 1a9d3abe79..1249df46a1 100755 --- a/gr-digital/python/digital/qa_decision_feedback_equalizer.py +++ b/gr-digital/python/digital/qa_decision_feedback_equalizer.py @@ -1,76 +1,113 @@ #!/usr/bin/env python # # Copyright 2020 Free Software Foundation, Inc. -# +# # This file is part of GNU Radio -# +# # SPDX-License-Identifier: GPL-3.0-or-later # -# +# from gnuradio import gr, gr_unittest -import random, numpy +import random +import numpy from gnuradio import digital, blocks, channels + class qa_linear_equalizer(gr_unittest.TestCase): - def unpack_values(self, values_in, bits_per_value, bits_per_symbol): - # verify that 8 is divisible by bits_per_symbol + def unpack_values(self, values_in, bits_per_value, bits_per_symbol): + # verify that 8 is divisible by bits_per_symbol m = bits_per_value / bits_per_symbol # print(m) - mask = 2**(bits_per_symbol)-1 - - if bits_per_value != m*bits_per_symbol: - print("error - bits per symbols must fit nicely into bits_per_value bit values") + mask = 2**(bits_per_symbol) - 1 + + if bits_per_value != m * bits_per_symbol: + print( + "error - bits per symbols must fit nicely into bits_per_value bit values") return [] - + num_values = len(values_in) - num_symbols = int(num_values*( m) ) - + num_symbols = int(num_values * (m)) + cur_byte = 0 cur_bit = 0 out = [] for i in range(num_symbols): - s = (values_in[cur_byte] >> (bits_per_value-bits_per_symbol-cur_bit)) & mask + s = ( + values_in[cur_byte] >> ( + bits_per_value - + bits_per_symbol - + cur_bit)) & mask out.append(s) cur_bit += bits_per_symbol - + if cur_bit >= bits_per_value: cur_bit = 0 cur_byte += 1 - + return out def map_symbols_to_constellation(self, symbols, cons): l = list(map(lambda x: cons.points()[x], symbols)) return l - def setUp(self): random.seed(987654) self.tb = gr.top_block() self.num_data = num_data = 10000 self.snr = snr = 10 - self.noise_voltage = pow(10.0,(-snr/20.0)) - + self.noise_voltage = pow(10.0, (-snr / 20.0)) + self.sps = sps = 4 self.eb = eb = 0.35 - self.preamble = preamble = [0x27,0x2F,0x18,0x5D,0x5B,0x2A,0x3F,0x71,0x63,0x3C,0x17,0x0C,0x0A,0x41,0xD6,0x1F,0x4C,0x23,0x65,0x68,0xED,0x1C,0x77,0xA7,0x0E,0x0A,0x9E,0x47,0x82,0xA4,0x57,0x24,] - - self.payload_size = payload_size = 300 # bytes - self.data = data = [0]*4+[random.getrandbits(8) for i in range(payload_size)] + self.preamble = preamble = [ + 0x27, + 0x2F, + 0x18, + 0x5D, + 0x5B, + 0x2A, + 0x3F, + 0x71, + 0x63, + 0x3C, + 0x17, + 0x0C, + 0x0A, + 0x41, + 0xD6, + 0x1F, + 0x4C, + 0x23, + 0x65, + 0x68, + 0xED, + 0x1C, + 0x77, + 0xA7, + 0x0E, + 0x0A, + 0x9E, + 0x47, + 0x82, + 0xA4, + 0x57, + 0x24, + ] + + self.payload_size = payload_size = 300 # bytes + self.data = data = [0] * 4 + \ + [random.getrandbits(8) for i in range(payload_size)] self.gain = gain = .001 # LMS gain self.corr_thresh = corr_thresh = 3e6 - self.num_taps = num_taps = 16 - - + self.num_taps = num_taps = 16 def tearDown(self): self.tb = None - def transform(self, src_data, gain, const): SRC = blocks.vector_source_c(src_data, False) EQU = digital.lms_dd_equalizer_cc(4, gain, 1, const.base()) @@ -82,9 +119,9 @@ class qa_linear_equalizer(gr_unittest.TestCase): def test_001_identity(self): # Constant modulus signal so no adjustments const = digital.constellation_qpsk() - src_data = const.points()*1000 + src_data = const.points() * 1000 - N = 100 # settling time + N = 100 # settling time expected_data = src_data[N:] result = self.transform(src_data, 0.1, const)[N:] @@ -97,18 +134,37 @@ class qa_linear_equalizer(gr_unittest.TestCase): num_taps_fwd = 13 num_taps_rev = 3 num_test = 1000 - cons = digital.constellation_qpsk().base() - rxmod = digital.generic_mod(cons, False, self.sps, True, self.eb, False, False) - modulated_sync_word_pre = digital.modulate_vector_bc(rxmod.to_basic_block(), self.preamble+self.preamble, [1]) - modulated_sync_word = modulated_sync_word_pre[86:(512+86)] # compensate for the RRC filter delay - corr_max = numpy.abs(numpy.dot(modulated_sync_word,numpy.conj(modulated_sync_word))) - corr_calc = self.corr_thresh/(corr_max*corr_max) - preamble_symbols = self.map_symbols_to_constellation(self.unpack_values(self.preamble, 8, 2), cons) + cons = digital.constellation_qpsk().base() + rxmod = digital.generic_mod( + cons, False, self.sps, True, self.eb, False, False) + modulated_sync_word_pre = digital.modulate_vector_bc( + rxmod.to_basic_block(), self.preamble + self.preamble, [1]) + # compensate for the RRC filter delay + modulated_sync_word = modulated_sync_word_pre[86:(512 + 86)] + corr_max = numpy.abs( + numpy.dot( + modulated_sync_word, + numpy.conj(modulated_sync_word))) + corr_calc = self.corr_thresh / (corr_max * corr_max) + preamble_symbols = self.map_symbols_to_constellation( + self.unpack_values(self.preamble, 8, 2), cons) alg = digital.adaptive_algorithm_lms(cons, gain).base() evm = digital.meas_evm_cc(cons, digital.evm_measurement_t.EVM_PERCENT) - dfe = digital.decision_feedback_equalizer(num_taps_fwd, num_taps_rev, self.sps, alg, True, preamble_symbols, 'corr_est') - correst = digital.corr_est_cc(modulated_sync_word, self.sps, 12, corr_calc, digital.THRESHOLD_ABSOLUTE) + dfe = digital.decision_feedback_equalizer( + num_taps_fwd, + num_taps_rev, + self.sps, + alg, + True, + preamble_symbols, + 'corr_est') + correst = digital.corr_est_cc( + modulated_sync_word, + self.sps, + 12, + corr_calc, + digital.THRESHOLD_ABSOLUTE) constmod = digital.generic_mod( constellation=cons, differential=False, @@ -121,21 +177,45 @@ class qa_linear_equalizer(gr_unittest.TestCase): noise_voltage=self.noise_voltage, frequency_offset=0.0, epsilon=1.0, - taps=(2.0,-0.459489+-0.156287j,0.185799+0.022878j,0.060229+0.002171j,-0.023041+-0.016539j,-0.004507+0.011984j,-0.002597+0.002675j,0.002320+0.000621j,-0.001420+-0.000126j,-0.000118+-0.000520j,-0.000029+-0.000201j,0.000060+-0.000002j,0.169089+-0.500778j,0.419112+0.042402j,-0.139208+0.030027j,-0.080077+0.036473j,0.026689+0.000837j,-0.002449+0.002320j,-0.000567+-0.002068j,0.001528+0.002867j,0.000944+-0.000166j,0.000218+0.000007j,0.000214+-0.000150j,0.000004+0.000008j), + taps=( + 2.0, + -0.459489 + -0.156287j, + 0.185799 + 0.022878j, + 0.060229 + 0.002171j, + -0.023041 + -0.016539j, + -0.004507 + 0.011984j, + -0.002597 + 0.002675j, + 0.002320 + 0.000621j, + -0.001420 + -0.000126j, + -0.000118 + -0.000520j, + -0.000029 + -0.000201j, + 0.000060 + -0.000002j, + 0.169089 + -0.500778j, + 0.419112 + 0.042402j, + -0.139208 + 0.030027j, + -0.080077 + 0.036473j, + 0.026689 + 0.000837j, + -0.002449 + 0.002320j, + -0.000567 + -0.002068j, + 0.001528 + 0.002867j, + 0.000944 + -0.000166j, + 0.000218 + 0.000007j, + 0.000214 + -0.000150j, + 0.000004 + 0.000008j), noise_seed=-44982235, block_tags=False) - - repeating_data = self.preamble+self.data * 200 + + repeating_data = self.preamble + self.data * 200 vso = blocks.vector_source_b(repeating_data, False, 1, []) - head = blocks.head(gr.sizeof_char*1, 500) + head = blocks.head(gr.sizeof_char * 1, 500) vsi = blocks.vector_sink_f() self.tb.connect(vso, head, constmod, chan, correst, dfe, evm, vsi) self.tb.run() # look at the last 1000 samples, should converge quickly, below 5% EVM - upper_bound = list(20.0*numpy.ones((num_test,))) - lower_bound = list(0.0*numpy.zeros((num_test,))) + upper_bound = list(20.0 * numpy.ones((num_test,))) + lower_bound = list(0.0 * numpy.zeros((num_test,))) output_data = vsi.data() output_data = output_data[-num_test:] self.assertLess(output_data, upper_bound) diff --git a/gr-digital/python/digital/qa_diff_encoder.py b/gr-digital/python/digital/qa_diff_encoder.py index 15d80e5281..7ffc331b47 100644 --- a/gr-digital/python/digital/qa_diff_encoder.py +++ b/gr-digital/python/digital/qa_diff_encoder.py @@ -13,6 +13,7 @@ import random from gnuradio import gr, gr_unittest, digital, blocks + def make_random_int_list(L, min, max): result = [] for x in range(L): @@ -32,7 +33,7 @@ class test_diff_encoder(gr_unittest.TestCase): def test_diff_encdec_000(self): random.seed(0) modulus = 2 - src_data = make_random_int_list(1000, 0, modulus-1) + src_data = make_random_int_list(1000, 0, modulus - 1) expected_result = src_data src = blocks.vector_source_b(src_data) enc = digital.diff_encoder_bb(modulus) @@ -46,7 +47,7 @@ class test_diff_encoder(gr_unittest.TestCase): def test_diff_encdec_001(self): random.seed(0) modulus = 4 - src_data = make_random_int_list(1000, 0, modulus-1) + src_data = make_random_int_list(1000, 0, modulus - 1) expected_result = src_data src = blocks.vector_source_b(src_data) enc = digital.diff_encoder_bb(modulus) @@ -60,7 +61,7 @@ class test_diff_encoder(gr_unittest.TestCase): def test_diff_encdec_002(self): random.seed(0) modulus = 8 - src_data = make_random_int_list(40000, 0, modulus-1) + src_data = make_random_int_list(40000, 0, modulus - 1) expected_result = src_data src = blocks.vector_source_b(src_data) enc = digital.diff_encoder_bb(modulus) @@ -71,6 +72,6 @@ class test_diff_encoder(gr_unittest.TestCase): actual_result = dst.data() # fetch the contents of the sink self.assertEqual(expected_result, actual_result) + if __name__ == '__main__': gr_unittest.run(test_diff_encoder) - diff --git a/gr-digital/python/digital/qa_diff_phasor_cc.py b/gr-digital/python/digital/qa_diff_phasor_cc.py index 4c018087e3..7a6ff569f8 100644 --- a/gr-digital/python/digital/qa_diff_phasor_cc.py +++ b/gr-digital/python/digital/qa_diff_phasor_cc.py @@ -11,6 +11,7 @@ from gnuradio import gr, gr_unittest, digital, blocks + class test_diff_phasor(gr_unittest.TestCase): def setUp(self): @@ -20,8 +21,9 @@ class test_diff_phasor(gr_unittest.TestCase): self.tb = None def test_diff_phasor_cc(self): - src_data = (0+0j, 1+0j, -1+0j, 3+4j, -3-4j, -3+4j) - expected_result = (0+0j, 0+0j, -1+0j, -3-4j, -25+0j, -7-24j) + src_data = (0 + 0j, 1 + 0j, -1 + 0j, 3 + 4j, -3 - 4j, -3 + 4j) + expected_result = (0 + 0j, 0 + 0j, -1 + 0j, - + 3 - 4j, -25 + 0j, -7 - 24j) src = blocks.vector_source_c(src_data) op = digital.diff_phasor_cc() dst = blocks.vector_sink_c() @@ -31,6 +33,6 @@ class test_diff_phasor(gr_unittest.TestCase): actual_result = dst.data() # fetch the contents of the sink self.assertComplexTuplesAlmostEqual(expected_result, actual_result) + if __name__ == '__main__': gr_unittest.run(test_diff_phasor) - diff --git a/gr-digital/python/digital/qa_digital.py b/gr-digital/python/digital/qa_digital.py index 2c4a7594e9..7acfdd518a 100644 --- a/gr-digital/python/digital/qa_digital.py +++ b/gr-digital/python/digital/qa_digital.py @@ -1,16 +1,17 @@ #!/usr/bin/env python # # Copyright 2011 Free Software Foundation, Inc. -# +# # This file is part of GNU Radio -# +# # SPDX-License-Identifier: GPL-3.0-or-later # -# +# from gnuradio import gr, gr_unittest, digital + class test_digital(gr_unittest.TestCase): def setUp(self): @@ -19,5 +20,6 @@ class test_digital(gr_unittest.TestCase): def tearDown(self): self.tb = None + if __name__ == '__main__': gr_unittest.run(test_digital) diff --git a/gr-digital/python/digital/qa_fll_band_edge.py b/gr-digital/python/digital/qa_fll_band_edge.py index 6d35d132b6..0d8d159ecb 100644 --- a/gr-digital/python/digital/qa_fll_band_edge.py +++ b/gr-digital/python/digital/qa_fll_band_edge.py @@ -1,12 +1,12 @@ #!/usr/bin/env python # # Copyright 2011-2013 Free Software Foundation, Inc. -# +# # This file is part of GNU Radio -# +# # SPDX-License-Identifier: GPL-3.0-or-later # -# +# import random @@ -14,6 +14,7 @@ import math from gnuradio import gr, gr_unittest, digital, filter, blocks, analog + class test_fll_band_edge_cc(gr_unittest.TestCase): def setUp(self): @@ -26,19 +27,19 @@ class test_fll_band_edge_cc(gr_unittest.TestCase): def test01(self): sps = 4 rolloff = 0.35 - bw = 2*math.pi/100.0 + bw = 2 * math.pi / 100.0 ntaps = 45 - + # Create pulse shape filter rrc_taps = filter.firdes.root_raised_cosine( sps, sps, 1.0, rolloff, ntaps) # The frequency offset to correct - foffset = 0.2 / (2.0*math.pi) + foffset = 0.2 / (2.0 * math.pi) # Create a set of 1's and -1's, pulse shape and interpolate to sps random.seed(0) - data = [2.0*random.randint(0, 2) - 1.0 for i in range(200)] + data = [2.0 * random.randint(0, 2) - 1.0 for i in range(200)] self.src = blocks.vector_source_c(data, False) self.rrc = filter.interp_fir_filter_ccf(sps, rrc_taps) @@ -55,21 +56,22 @@ class test_fll_band_edge_cc(gr_unittest.TestCase): self.nsnk_fll = blocks.null_sink(gr.sizeof_gr_complex) self.nsnk_phs = blocks.null_sink(gr.sizeof_float) self.nsnk_err = blocks.null_sink(gr.sizeof_float) - + # Connect the blocks - self.tb.connect(self.nco, (self.mix,1)) - self.tb.connect(self.src, self.rrc, (self.mix,0)) + self.tb.connect(self.nco, (self.mix, 1)) + self.tb.connect(self.src, self.rrc, (self.mix, 0)) self.tb.connect(self.mix, self.fll, self.nsnk_fll) - self.tb.connect((self.fll,1), self.vsnk_frq) - self.tb.connect((self.fll,2), self.nsnk_phs) - self.tb.connect((self.fll,3), self.nsnk_err) + self.tb.connect((self.fll, 1), self.vsnk_frq) + self.tb.connect((self.fll, 2), self.nsnk_phs) + self.tb.connect((self.fll, 3), self.nsnk_err) self.tb.run() - + N = 700 dst_data = self.vsnk_frq.data()[N:] - expected_result = len(dst_data)* [-0.20,] + expected_result = len(dst_data) * [-0.20, ] self.assertFloatTuplesAlmostEqual(expected_result, dst_data, 4) + if __name__ == '__main__': gr_unittest.run(test_fll_band_edge_cc) diff --git a/gr-digital/python/digital/qa_framer_sink.py b/gr-digital/python/digital/qa_framer_sink.py index 365829a9a1..e5bda1e63f 100644 --- a/gr-digital/python/digital/qa_framer_sink.py +++ b/gr-digital/python/digital/qa_framer_sink.py @@ -1,18 +1,19 @@ #!/usr/bin/env python # # Copyright 2012,2013 Free Software Foundation, Inc. -# +# # This file is part of GNU Radio -# +# # SPDX-License-Identifier: GPL-3.0-or-later # -# +# from gnuradio import gr, gr_unittest, digital, blocks default_access_code = '\xAC\xDD\xA4\xE2\xF2\x8C\x20\xFC' + def string_to_1_0_list(s): r = [] for ch in s: @@ -22,9 +23,11 @@ def string_to_1_0_list(s): r.append(t) return r + def to_1_0_string(L): return ''.join([chr(x + ord('0')) for x in L]) + class test_framker_sink(gr_unittest.TestCase): def setUp(self): @@ -37,9 +40,10 @@ class test_framker_sink(gr_unittest.TestCase): code = (1, 1, 0, 1) access_code = to_1_0_string(code) - header = tuple(2*[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1]) # len=1 + header = tuple(2 * [0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1]) # len=1 pad = (0,) * 100 - src_data = code + header + (0,1,0,0,0,0,0,1) + pad + src_data = code + header + (0, 1, 0, 0, 0, 0, 0, 1) + pad expected_data = b'A' rcvd_pktq = gr.msg_queue() @@ -61,9 +65,11 @@ class test_framker_sink(gr_unittest.TestCase): code = tuple(string_to_1_0_list(default_access_code)) access_code = to_1_0_string(code) - header = tuple(2*[0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0]) # len=2 + header = tuple(2 * [0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0]) # len=2 pad = (0,) * 100 - src_data = code + header + (0,1,0,0,1,0,0,0) + (0,1,0,0,1,0,0,1) + pad + src_data = code + header + \ + (0, 1, 0, 0, 1, 0, 0, 0) + (0, 1, 0, 0, 1, 0, 0, 1) + pad expected_data = b'HI' rcvd_pktq = gr.msg_queue() @@ -81,6 +87,6 @@ class test_framker_sink(gr_unittest.TestCase): result_data = result_data.to_string() self.assertEqual(expected_data, result_data) + if __name__ == '__main__': gr_unittest.run(test_framker_sink) - diff --git a/gr-digital/python/digital/qa_glfsr_source.py b/gr-digital/python/digital/qa_glfsr_source.py index 7505f5bdaa..dbe488399b 100644 --- a/gr-digital/python/digital/qa_glfsr_source.py +++ b/gr-digital/python/digital/qa_glfsr_source.py @@ -11,6 +11,7 @@ from gnuradio import gr, gr_unittest, digital, blocks + class test_glfsr_source(gr_unittest.TestCase): def setUp(self): @@ -22,7 +23,7 @@ class test_glfsr_source(gr_unittest.TestCase): def test_000_make_b(self): src = digital.glfsr_source_b(16) self.assertEqual(src.mask(), 0x8016) - self.assertEqual(src.period(), 2**16-1) + self.assertEqual(src.period(), 2**16 - 1) def test_001_degree_b(self): self.assertRaises(RuntimeError, @@ -31,53 +32,62 @@ class test_glfsr_source(gr_unittest.TestCase): lambda: digital.glfsr_source_b(33)) def test_002_correlation_b(self): - for degree in range(1,11): # Higher degrees take too long to correlate + for degree in range( + 1, 11): # Higher degrees take too long to correlate src = digital.glfsr_source_b(degree, False) - b2f = digital.chunks_to_symbols_bf((-1.0,1.0), 1) + b2f = digital.chunks_to_symbols_bf((-1.0, 1.0), 1) dst = blocks.vector_sink_f() - del self.tb # Discard existing top block + del self.tb # Discard existing top block self.tb = gr.top_block() self.tb.connect(src, b2f, dst) self.tb.run() self.tb.disconnect_all() actual_result = dst.data() R = auto_correlate(actual_result) - self.assertEqual(R[0], float(len(R))) # Auto-correlation peak at origin - for i in range(len(R)-1): - self.assertEqual(R[i+1], -1.0) # Auto-correlation minimum everywhere else + # Auto-correlation peak at origin + self.assertEqual(R[0], float(len(R))) + for i in range(len(R) - 1): + # Auto-correlation minimum everywhere else + self.assertEqual(R[i + 1], -1.0) def test_003_make_f(self): src = digital.glfsr_source_f(16) self.assertEqual(src.mask(), 0x8016) - self.assertEqual(src.period(), 2**16-1) + self.assertEqual(src.period(), 2**16 - 1) def test_004_degree_f(self): self.assertRaises(RuntimeError, lambda: digital.glfsr_source_f(0)) self.assertRaises(RuntimeError, lambda: digital.glfsr_source_f(33)) + def test_005_correlation_f(self): - for degree in range(1,11): # Higher degrees take too long to correlate + for degree in range( + 1, 11): # Higher degrees take too long to correlate src = digital.glfsr_source_f(degree, False) dst = blocks.vector_sink_f() - del self.tb # Discard existing top block + del self.tb # Discard existing top block self.tb = gr.top_block() self.tb.connect(src, dst) self.tb.run() actual_result = dst.data() R = auto_correlate(actual_result) - self.assertEqual(R[0], float(len(R))) # Auto-correlation peak at origin - for i in range(len(R)-1): - self.assertEqual(R[i+1], -1.0) # Auto-correlation minimum everywhere else + # Auto-correlation peak at origin + self.assertEqual(R[0], float(len(R))) + for i in range(len(R) - 1): + # Auto-correlation minimum everywhere else + self.assertEqual(R[i + 1], -1.0) + def auto_correlate(data): l = len(data) - R = [0,]*l + R = [0, ] * l for lag in range(l): for i in range(l): - R[lag] += data[i]*data[i-lag] + R[lag] += data[i] * data[i - lag] return R + if __name__ == '__main__': gr_unittest.run(test_glfsr_source) diff --git a/gr-digital/python/digital/qa_hdlc_framer.py b/gr-digital/python/digital/qa_hdlc_framer.py index a13f364eeb..b4d63b3d07 100644 --- a/gr-digital/python/digital/qa_hdlc_framer.py +++ b/gr-digital/python/digital/qa_hdlc_framer.py @@ -1,12 +1,12 @@ #!/usr/bin/env python # # Copyright 2006,2007,2010,2011,2013 Free Software Foundation, Inc. -# +# # This file is part of GNU Radio -# +# # SPDX-License-Identifier: GPL-3.0-or-later # -# +# from gnuradio import gr, gr_unittest, digital, blocks @@ -14,6 +14,7 @@ import pmt import numpy from time import sleep + class test_hdlc_framer(gr_unittest.TestCase): def setUp(self): self.tb = gr.top_block() @@ -22,18 +23,18 @@ class test_hdlc_framer(gr_unittest.TestCase): self.tb = None def test_001(self): - #test complementary operation of framer & deframer - #want to frame some random data that has enough consecutive bits to - #stuff at least a few bits + # test complementary operation of framer & deframer + # want to frame some random data that has enough consecutive bits to + # stuff at least a few bits npkts = 20 src_data = [0xFE, 0xDA, 0xAC, 0x29, 0x7F, 0xA2, 0x90, 0x0F, 0xF8] - frame = digital.hdlc_framer_pb("wat") + frame = digital.hdlc_framer_pb("wat") deframe = digital.hdlc_deframer_bp(8, 500) - debug = blocks.message_debug() + debug = blocks.message_debug() self.tb.connect(frame, deframe) self.tb.msg_connect(deframe, "out", debug, "store") self.tb.start() - msg = pmt.cons(pmt.PMT_NIL, pmt.init_u8vector(len(src_data),src_data)) + msg = pmt.cons(pmt.PMT_NIL, pmt.init_u8vector(len(src_data), src_data)) for i in range(npkts): frame.to_basic_block()._post(pmt.intern("in"), msg) sleep(0.2) @@ -49,4 +50,3 @@ class test_hdlc_framer(gr_unittest.TestCase): if __name__ == '__main__': gr_unittest.run(test_hdlc_framer) - diff --git a/gr-digital/python/digital/qa_header_payload_demux.py b/gr-digital/python/digital/qa_header_payload_demux.py index edee14c0c1..76be0905f0 100644 --- a/gr-digital/python/digital/qa_header_payload_demux.py +++ b/gr-digital/python/digital/qa_header_payload_demux.py @@ -33,6 +33,7 @@ class HeaderToMessageBlock(gr.sync_block): Helps with testing the HPD. Receives a header, stores it, posts a predetermined message. """ + def __init__(self, itemsize, header_len, messages): gr.sync_block.__init__( self, @@ -57,12 +58,12 @@ class HeaderToMessageBlock(gr.sync_block): class qa_header_payload_demux (gr_unittest.TestCase): - def setUp (self): + def setUp(self): """Runs before every test.""" - self.tb = gr.top_block () + self.tb = gr.top_block() random.seed(0) - def tearDown (self): + def tearDown(self): """Runs after every test.""" self.tb = None @@ -85,11 +86,17 @@ class qa_header_payload_demux (gr_unittest.TestCase): ) self.tb.connect((hpd, 1), payload_sink) - def run_tb(self, payload_sink, payload_len, header_sink, header_len, timeout=30): + def run_tb( + self, + payload_sink, + payload_len, + header_sink, + header_len, + timeout=30): """Execute self.tb""" stop_time = time.time() + timeout self.tb.start() - while (len(payload_sink.data()) < payload_len or \ + while (len(payload_sink.data()) < payload_len or len(header_sink.data()) < header_len) and \ time.time() < stop_time: time.sleep(.2) @@ -106,7 +113,7 @@ class qa_header_payload_demux (gr_unittest.TestCase): header = (1, 2, 3) payload = tuple(range(5, 20)) data_signal = (0,) * n_zeros + header + payload - trigger_signal = [0,] * len(data_signal) + trigger_signal = [0, ] * len(data_signal) trigger_signal[n_zeros] = 1 # This is dropped: testtag1 = make_tag('tag1', 0, 0) @@ -130,7 +137,8 @@ class qa_header_payload_demux (gr_unittest.TestCase): len(header), [len(payload)] ) - self.assertEqual(pmt.length(hpd.message_ports_in()), 2) #extra system port defined for you + # extra system port defined for you + self.assertEqual(pmt.length(hpd.message_ports_in()), 2) payload_sink = blocks.vector_sink_f() header_sink = blocks.vector_sink_f() self.connect_all_blocks( @@ -188,7 +196,8 @@ class qa_header_payload_demux (gr_unittest.TestCase): hpd = digital.header_payload_demux( len(header), 1, 0, "frame_len", "detect", False, gr.sizeof_float ) - self.assertEqual(pmt.length(hpd.message_ports_in()), 2) #extra system port defined for you + # extra system port defined for you + self.assertEqual(pmt.length(hpd.message_ports_in()), 2) header_sink = blocks.vector_sink_f() payload_sink = blocks.vector_sink_f() mock_header_demod = HeaderToMessageBlock( @@ -196,7 +205,13 @@ class qa_header_payload_demux (gr_unittest.TestCase): len(header), [len(payload)] ) - self.connect_all_blocks(data_src, None, hpd, mock_header_demod, payload_sink, header_sink) + self.connect_all_blocks( + data_src, + None, + hpd, + mock_header_demod, + payload_sink, + header_sink) self.run_tb(payload_sink, len(payload), header_sink, len(header)) # Check results self.assertEqual(header_sink.data(), list(header)) @@ -220,13 +235,13 @@ class qa_header_payload_demux (gr_unittest.TestCase): ] self.assertEqual(expected_tags_payload, ptags_payload) - def test_001_headerpadding (self): + def test_001_headerpadding(self): """ Like test 1, but with header padding. """ n_zeros = 3 header = [1, 2, 3] header_padding = 1 payload = list(range(5, 20)) - data_signal = [0,] * n_zeros + header + payload + data_signal = [0, ] * n_zeros + header + payload trigger_signal = [0] * len(data_signal) trigger_signal[n_zeros] = 1 # This is dropped: @@ -245,15 +260,15 @@ class qa_header_payload_demux (gr_unittest.TestCase): trigger_src = blocks.vector_source_b(trigger_signal, False) hpd = digital.header_payload_demux( len(header), - 1, # Items per symbol - 0, # Guard interval - "frame_len", # TSB tag key - "detect", # Trigger tag key - False, # No symbols please - gr.sizeof_float, # Item size - "", # Timing tag key - 1.0, # Samp rate - (), # No special tags + 1, # Items per symbol + 0, # Guard interval + "frame_len", # TSB tag key + "detect", # Trigger tag key + False, # No symbols please + gr.sizeof_float, # Item size + "", # Timing tag key + 1.0, # Samp rate + (), # No special tags header_padding ) mock_header_demod = HeaderToMessageBlock( @@ -263,11 +278,17 @@ class qa_header_payload_demux (gr_unittest.TestCase): ) header_sink = blocks.vector_sink_f() payload_sink = blocks.vector_sink_f() - self.connect_all_blocks(data_src, trigger_src, hpd, mock_header_demod, payload_sink, header_sink) - self.run_tb(payload_sink, len(payload), header_sink, len(header)+2) + self.connect_all_blocks( + data_src, + trigger_src, + hpd, + mock_header_demod, + payload_sink, + header_sink) + self.run_tb(payload_sink, len(payload), header_sink, len(header) + 2) # Check values # Header now is padded: - self.assertEqual(header_sink.data(), [0,] + header + [payload[0],]) + self.assertEqual(header_sink.data(), [0, ] + header + [payload[0], ]) self.assertEqual(payload_sink.data(), payload) ptags_header = [] for tag in header_sink.tags(): @@ -288,14 +309,14 @@ class qa_header_payload_demux (gr_unittest.TestCase): ] self.assertEqual(expected_tags_payload, ptags_payload) - def test_001_headerpadding_payload_offset (self): + def test_001_headerpadding_payload_offset(self): """ Like test 1, but with header padding + payload offset. """ n_zeros = 3 header = [1, 2, 3] header_padding = 1 payload_offset = -1 payload = list(range(5, 20)) - data_signal = [0,] * n_zeros + header + payload + [0,] * 100 + data_signal = [0, ] * n_zeros + header + payload + [0, ] * 100 trigger_signal = [0] * len(data_signal) trigger_signal[n_zeros] = 1 # This goes on output 1, item 3 + 1 (for payload offset) @@ -308,41 +329,38 @@ class qa_header_payload_demux (gr_unittest.TestCase): trigger_src = blocks.vector_source_b(trigger_signal, False) hpd = digital.header_payload_demux( len(header), - 1, # Items per symbol - 0, # Guard interval - "frame_len", # TSB tag key - "detect", # Trigger tag key - False, # No symbols please - gr.sizeof_float, # Item size - "", # Timing tag key - 1.0, # Samp rate - (), # No special tags + 1, # Items per symbol + 0, # Guard interval + "frame_len", # TSB tag key + "detect", # Trigger tag key + False, # No symbols please + gr.sizeof_float, # Item size + "", # Timing tag key + 1.0, # Samp rate + (), # No special tags header_padding ) - self.assertEqual(pmt.length(hpd.message_ports_in()), 2) #extra system port defined for you + # extra system port defined for you + self.assertEqual(pmt.length(hpd.message_ports_in()), 2) header_sink = blocks.vector_sink_f() payload_sink = blocks.vector_sink_f() - self.tb.connect(data_src, (hpd, 0)) + self.tb.connect(data_src, (hpd, 0)) self.tb.connect(trigger_src, (hpd, 1)) self.tb.connect((hpd, 0), header_sink) self.tb.connect((hpd, 1), payload_sink) self.tb.start() - time.sleep(.2) # Need this, otherwise, the next message is ignored - hpd.to_basic_block()._post( - pmt.intern('header_data'), - pmt.to_pmt({'frame_len': len(payload), 'payload_offset': payload_offset}) - ) + time.sleep(.2) # Need this, otherwise, the next message is ignored + hpd.to_basic_block()._post(pmt.intern('header_data'), pmt.to_pmt( + {'frame_len': len(payload), 'payload_offset': payload_offset})) while len(payload_sink.data()) < len(payload): time.sleep(.2) self.tb.stop() self.tb.wait() # Header is now padded: - self.assertEqual(header_sink.data(), [0,] + header + [payload[0],]) + self.assertEqual(header_sink.data(), [0, ] + header + [payload[0], ]) # Payload is now offset: - self.assertEqual( - payload_sink.data(), - data_signal[n_zeros + len(header) + payload_offset:n_zeros + len(header) + payload_offset + len(payload)] - ) + self.assertEqual(payload_sink.data(), data_signal[n_zeros + len( + header) + payload_offset:n_zeros + len(header) + payload_offset + len(payload)]) ptags_payload = {} for tag in payload_sink.tags(): ptag = gr.tag_to_python(tag) @@ -354,7 +372,6 @@ class qa_header_payload_demux (gr_unittest.TestCase): } self.assertEqual(expected_tags_payload, ptags_payload) - def test_002_symbols(self): """ Same as before, but operate on symbols @@ -365,8 +382,9 @@ class qa_header_payload_demux (gr_unittest.TestCase): n_symbols = 4 header = (1, 2, 3) payload = (1, 2, 3) - data_signal = (0,) * n_zeros + (0,) + header + ((0,) + payload) * n_symbols - trigger_signal = [0,] * len(data_signal) + data_signal = (0,) * n_zeros + (0,) + header + \ + ((0,) + payload) * n_symbols + trigger_signal = [0, ] * len(data_signal) trigger_signal[n_zeros] = 1 # This is dropped: testtag1 = make_tag('tag1', 0, 0) @@ -375,11 +393,14 @@ class qa_header_payload_demux (gr_unittest.TestCase): # This goes on output 0, item 0 (middle of the header symbol) testtag3 = make_tag('tag3', 42, n_zeros + gi + 1) # This goes on output 1, item 1 (middle of the first payload symbol) - testtag4 = make_tag('tag4', 314, n_zeros + (gi + items_per_symbol) * 2 + 1) - data_src = blocks.vector_source_f(data_signal, False, tags=(testtag1, testtag2, testtag3, testtag4)) + testtag4 = make_tag('tag4', 314, n_zeros + + (gi + items_per_symbol) * 2 + 1) + data_src = blocks.vector_source_f( + data_signal, False, tags=( + testtag1, testtag2, testtag3, testtag4)) trigger_src = blocks.vector_source_b(trigger_signal, False) hpd = digital.header_payload_demux( - len(header) // items_per_symbol, # Header length (in symbols) + len(header) // items_per_symbol, # Header length (in symbols) items_per_symbol, # Items per symbols gi, # Items per guard time "frame_len", # Frame length tag key @@ -387,15 +408,16 @@ class qa_header_payload_demux (gr_unittest.TestCase): True, # Output symbols (not items) gr.sizeof_float # Bytes per item ) - self.assertEqual(pmt.length(hpd.message_ports_in()), 2) #extra system port defined for you + # extra system port defined for you + self.assertEqual(pmt.length(hpd.message_ports_in()), 2) header_sink = blocks.vector_sink_f(items_per_symbol) payload_sink = blocks.vector_sink_f(items_per_symbol) - self.tb.connect(data_src, (hpd, 0)) + self.tb.connect(data_src, (hpd, 0)) self.tb.connect(trigger_src, (hpd, 1)) self.tb.connect((hpd, 0), header_sink) self.tb.connect((hpd, 1), payload_sink) self.tb.start() - time.sleep(.2) # Need this, otherwise, the next message is ignored + time.sleep(.2) # Need this, otherwise, the next message is ignored hpd.to_basic_block()._post( pmt.intern('header_data'), pmt.from_long(n_symbols) @@ -404,7 +426,7 @@ class qa_header_payload_demux (gr_unittest.TestCase): time.sleep(.2) self.tb.stop() self.tb.wait() - self.assertEqual(header_sink.data(), header) + self.assertEqual(header_sink.data(), header) self.assertEqual(payload_sink.data(), payload * n_symbols) ptags_header = [] for tag in header_sink.tags(): @@ -429,32 +451,32 @@ class qa_header_payload_demux (gr_unittest.TestCase): """ Like test 1, but twice, plus one fail """ - ### Tx Data + # Tx Data n_zeros = 5 header = [1, 2, 3] - header_fail = [-1, -2, -4] # Contents don't really matter + header_fail = [-1, -2, -4] # Contents don't really matter payload1 = list(range(5, 20)) - payload2 = [42,] + payload2 = [42, ] sampling_rate = 2 - data_signal = [0,] * n_zeros + header + payload1 - trigger_signal = [0,] * len(data_signal) * 2 + data_signal = [0, ] * n_zeros + header + payload1 + trigger_signal = [0, ] * len(data_signal) * 2 trigger_signal[n_zeros] = 1 trigger_signal[len(data_signal)] = 1 - trigger_signal[len(data_signal)+len(header_fail)+n_zeros] = 1 + trigger_signal[len(data_signal) + len(header_fail) + n_zeros] = 1 print("Triggers at: {0} {1} {2}".format( n_zeros, len(data_signal), - len(data_signal)+len(header_fail)+n_zeros)) + len(data_signal) + len(header_fail) + n_zeros)) tx_signal = data_signal + \ - header_fail + [0,] * n_zeros + \ - header + payload2 + [0,] * 1000 + header_fail + [0, ] * n_zeros + \ + header + payload2 + [0, ] * 1000 # Timing tag: This is preserved and updated: timing_tag = make_tag('rx_time', (0, 0), 0) # Rx freq tags: rx_freq_tag1 = make_tag('rx_freq', 1.0, 0) rx_freq_tag2 = make_tag('rx_freq', 1.5, 29) rx_freq_tag3 = make_tag('rx_freq', 2.0, 30) - ### Flow graph + # Flow graph data_src = blocks.vector_source_f( tx_signal, False, tags=(timing_tag, rx_freq_tag1, rx_freq_tag2, rx_freq_tag3) @@ -472,15 +494,16 @@ class qa_header_payload_demux (gr_unittest.TestCase): samp_rate=sampling_rate, special_tags=('rx_freq',), ) - self.assertEqual(pmt.length(hpd.message_ports_in()), 2) #extra system port defined for you + # extra system port defined for you + self.assertEqual(pmt.length(hpd.message_ports_in()), 2) header_sink = blocks.vector_sink_f() payload_sink = blocks.vector_sink_f() - self.tb.connect(data_src, (hpd, 0)) + self.tb.connect(data_src, (hpd, 0)) self.tb.connect(trigger_src, (hpd, 1)) self.tb.connect((hpd, 0), header_sink) self.tb.connect((hpd, 1), payload_sink) self.tb.start() - time.sleep(.2) # Need this, otherwise, the next message is ignored + time.sleep(.2) # Need this, otherwise, the next message is ignored hpd.to_basic_block()._post( pmt.intern('header_data'), pmt.from_long(len(payload1)) @@ -511,23 +534,29 @@ class qa_header_payload_demux (gr_unittest.TestCase): # 31: header 3 # 34: payload 2 (length 1) # 35: 1000 zeros - self.assertEqual(header_sink.data(), list(header + header_fail + header)) + self.assertEqual( + header_sink.data(), list( + header + header_fail + header)) self.assertEqual(payload_sink.data(), payload1 + payload2) tags_payload = [gr.tag_to_python(x) for x in payload_sink.tags()] - tags_payload = sorted([(x.offset, x.key, x.value) for x in tags_payload]) + tags_payload = sorted([(x.offset, x.key, x.value) + for x in tags_payload]) tags_expected_payload = [ - (0, 'frame_len', len(payload1)), + (0, 'frame_len', len(payload1)), (len(payload1), 'frame_len', len(payload2)), ] tags_header = [gr.tag_to_python(x) for x in header_sink.tags()] tags_header = sorted([(x.offset, x.key, x.value) for x in tags_header]) tags_expected_header = [ - (0, 'rx_freq', 1.0), - (0, 'rx_time', (2, 0.5)), # Hard coded time value :( Is n_zeros/sampling_rate - (len(header), 'rx_freq', 1.0), - (len(header), 'rx_time', (11, .5)), # Hard coded time value :(. See above. - (2*len(header), 'rx_freq', 2.0), - (2*len(header), 'rx_time', (15, .5)), # Hard coded time value :(. See above. + (0, 'rx_freq', 1.0), + # Hard coded time value :( Is n_zeros/sampling_rate + (0, 'rx_time', (2, 0.5)), + (len(header), 'rx_freq', 1.0), + # Hard coded time value :(. See above. + (len(header), 'rx_time', (11, .5)), + (2 * len(header), 'rx_freq', 2.0), + # Hard coded time value :(. See above. + (2 * len(header), 'rx_time', (15, .5)), ] self.assertEqual(tags_header, tags_expected_header) self.assertEqual(tags_payload, tags_expected_payload) @@ -561,6 +590,7 @@ class qa_header_payload_demux (gr_unittest.TestCase): signal += [2] * burst_size burst_sizes += [burst_size] return (signal, indexes, total_payload_len, burst_sizes) + def indexes_to_triggers(indexes, signal_len): """ Convert indexes to a mix of trigger signals and tags @@ -588,7 +618,8 @@ class qa_header_payload_demux (gr_unittest.TestCase): signal, indexes, total_payload_len, burst_sizes = create_signal( n_bursts, header_len, max_gap, max_burstsize, fail_rate ) - trigger_signal, trigger_tags = indexes_to_triggers(indexes, len(signal)) + trigger_signal, trigger_tags = indexes_to_triggers( + indexes, len(signal)) # Flow graph data_src = blocks.vector_source_f( signal, False, @@ -614,10 +645,22 @@ class qa_header_payload_demux (gr_unittest.TestCase): ) header_sink = blocks.vector_sink_f() payload_sink = blocks.vector_sink_f() - self.connect_all_blocks(data_src, trigger_src, hpd, mock_header_demod, payload_sink, header_sink) - self.run_tb(payload_sink, total_payload_len, header_sink, header_len*n_bursts) - self.assertEqual(header_sink.data(), list([1]*header_len*n_bursts)) - self.assertEqual(payload_sink.data(), list([2]*total_payload_len)) + self.connect_all_blocks( + data_src, + trigger_src, + hpd, + mock_header_demod, + payload_sink, + header_sink) + self.run_tb( + payload_sink, + total_payload_len, + header_sink, + header_len * + n_bursts) + self.assertEqual(header_sink.data(), list([1] * header_len * n_bursts)) + self.assertEqual(payload_sink.data(), list([2] * total_payload_len)) + if __name__ == '__main__': gr_unittest.run(qa_header_payload_demux) diff --git a/gr-digital/python/digital/qa_lfsr.py b/gr-digital/python/digital/qa_lfsr.py index ba03689634..0d7a2ccb94 100644 --- a/gr-digital/python/digital/qa_lfsr.py +++ b/gr-digital/python/digital/qa_lfsr.py @@ -13,6 +13,7 @@ import math from gnuradio import gr, gr_unittest, digital + class test_lfsr(gr_unittest.TestCase): def setUp(self): @@ -26,12 +27,12 @@ class test_lfsr(gr_unittest.TestCase): l = digital.lfsr(1, 1, reglen) result_data = [] - for i in range(4*(reglen+1)): + for i in range(4 * (reglen + 1)): result_data.append(l.next_bit()) - expected_result = 4*([1,] + reglen*[0,]) + expected_result = 4 * ([1, ] + reglen * [0, ]) self.assertFloatTuplesAlmostEqual(expected_result, result_data, 5) + if __name__ == '__main__': gr_unittest.run(test_lfsr) - diff --git a/gr-digital/python/digital/qa_linear_equalizer.py b/gr-digital/python/digital/qa_linear_equalizer.py index 522575db54..1ad3c3bece 100755 --- a/gr-digital/python/digital/qa_linear_equalizer.py +++ b/gr-digital/python/digital/qa_linear_equalizer.py @@ -1,74 +1,110 @@ #!/usr/bin/env python # # Copyright 2020 Free Software Foundation, Inc. -# +# # This file is part of GNU Radio -# +# # SPDX-License-Identifier: GPL-3.0-or-later # -# +# from gnuradio import gr, gr_unittest -import random, numpy +import random +import numpy from gnuradio import digital, blocks, channels + class qa_linear_equalizer(gr_unittest.TestCase): - def unpack_values(self, values_in, bits_per_value, bits_per_symbol): - # verify that 8 is divisible by bits_per_symbol + def unpack_values(self, values_in, bits_per_value, bits_per_symbol): + # verify that 8 is divisible by bits_per_symbol m = bits_per_value / bits_per_symbol # print(m) - mask = 2**(bits_per_symbol)-1 - - if bits_per_value != m*bits_per_symbol: - print("error - bits per symbols must fit nicely into bits_per_value bit values") + mask = 2**(bits_per_symbol) - 1 + + if bits_per_value != m * bits_per_symbol: + print( + "error - bits per symbols must fit nicely into bits_per_value bit values") return [] - + num_values = len(values_in) - num_symbols = int(num_values*( m) ) - + num_symbols = int(num_values * (m)) + cur_byte = 0 cur_bit = 0 out = [] for i in range(num_symbols): - s = (values_in[cur_byte] >> (bits_per_value-bits_per_symbol-cur_bit)) & mask + s = ( + values_in[cur_byte] >> ( + bits_per_value - + bits_per_symbol - + cur_bit)) & mask out.append(s) cur_bit += bits_per_symbol - + if cur_bit >= bits_per_value: cur_bit = 0 cur_byte += 1 - + return out def map_symbols_to_constellation(self, symbols, cons): l = list(map(lambda x: cons.points()[x], symbols)) return l - def setUp(self): random.seed(987654) self.tb = gr.top_block() self.num_data = num_data = 10000 - self.sps = sps = 4 self.eb = eb = 0.35 - self.preamble = preamble = [0x27,0x2F,0x18,0x5D,0x5B,0x2A,0x3F,0x71,0x63,0x3C,0x17,0x0C,0x0A,0x41,0xD6,0x1F,0x4C,0x23,0x65,0x68,0xED,0x1C,0x77,0xA7,0x0E,0x0A,0x9E,0x47,0x82,0xA4,0x57,0x24,] - - self.payload_size = payload_size = 300 # bytes - self.data = data = [0]*4+[random.getrandbits(8) for i in range(payload_size)] + self.preamble = preamble = [ + 0x27, + 0x2F, + 0x18, + 0x5D, + 0x5B, + 0x2A, + 0x3F, + 0x71, + 0x63, + 0x3C, + 0x17, + 0x0C, + 0x0A, + 0x41, + 0xD6, + 0x1F, + 0x4C, + 0x23, + 0x65, + 0x68, + 0xED, + 0x1C, + 0x77, + 0xA7, + 0x0E, + 0x0A, + 0x9E, + 0x47, + 0x82, + 0xA4, + 0x57, + 0x24, + ] + + self.payload_size = payload_size = 300 # bytes + self.data = data = [0] * 4 + \ + [random.getrandbits(8) for i in range(payload_size)] self.gain = gain = .001 # LMS gain self.corr_thresh = corr_thresh = 3e6 - self.num_taps = num_taps = 16 - - + self.num_taps = num_taps = 16 def tearDown(self): self.tb = None - def transform(self, src_data, gain, const): SRC = blocks.vector_source_c(src_data, False) EQU = digital.lms_dd_equalizer_cc(4, gain, 1, const.base()) @@ -80,9 +116,9 @@ class qa_linear_equalizer(gr_unittest.TestCase): def test_001_identity(self): # Constant modulus signal so no adjustments const = digital.constellation_qpsk() - src_data = const.points()*1000 + src_data = const.points() * 1000 - N = 100 # settling time + N = 100 # settling time expected_data = src_data[N:] result = self.transform(src_data, 0.1, const)[N:] @@ -95,18 +131,36 @@ class qa_linear_equalizer(gr_unittest.TestCase): num_taps = 16 num_samp = 2000 num_test = 500 - cons = digital.constellation_qpsk().base() - rxmod = digital.generic_mod(cons, False, self.sps, True, self.eb, False, False) - modulated_sync_word_pre = digital.modulate_vector_bc(rxmod.to_basic_block(), self.preamble+self.preamble, [1]) - modulated_sync_word = modulated_sync_word_pre[86:(512+86)] # compensate for the RRC filter delay - corr_max = numpy.abs(numpy.dot(modulated_sync_word,numpy.conj(modulated_sync_word))) - corr_calc = self.corr_thresh/(corr_max*corr_max) - preamble_symbols = self.map_symbols_to_constellation(self.unpack_values(self.preamble, 8, 2), cons) + cons = digital.constellation_qpsk().base() + rxmod = digital.generic_mod( + cons, False, self.sps, True, self.eb, False, False) + modulated_sync_word_pre = digital.modulate_vector_bc( + rxmod.to_basic_block(), self.preamble + self.preamble, [1]) + # compensate for the RRC filter delay + modulated_sync_word = modulated_sync_word_pre[86:(512 + 86)] + corr_max = numpy.abs( + numpy.dot( + modulated_sync_word, + numpy.conj(modulated_sync_word))) + corr_calc = self.corr_thresh / (corr_max * corr_max) + preamble_symbols = self.map_symbols_to_constellation( + self.unpack_values(self.preamble, 8, 2), cons) alg = digital.adaptive_algorithm_lms(cons, gain).base() evm = digital.meas_evm_cc(cons, digital.evm_measurement_t.EVM_PERCENT) - leq = digital.linear_equalizer(num_taps, self.sps, alg, False, preamble_symbols, 'corr_est') - correst = digital.corr_est_cc(modulated_sync_word, self.sps, 12, corr_calc, digital.THRESHOLD_ABSOLUTE) + leq = digital.linear_equalizer( + num_taps, + self.sps, + alg, + False, + preamble_symbols, + 'corr_est') + correst = digital.corr_est_cc( + modulated_sync_word, + self.sps, + 12, + corr_calc, + digital.THRESHOLD_ABSOLUTE) constmod = digital.generic_mod( constellation=cons, differential=False, @@ -119,19 +173,19 @@ class qa_linear_equalizer(gr_unittest.TestCase): noise_voltage=0.0, frequency_offset=0.0, epsilon=1.0, - taps=(1.0 + 1.0j, 0.63-.22j, -.1+.07j), + taps=(1.0 + 1.0j, 0.63 - .22j, -.1 + .07j), noise_seed=0, block_tags=False) - vso = blocks.vector_source_b(self.preamble+self.data, True, 1, []) - head = blocks.head(gr.sizeof_float*1, num_samp) + vso = blocks.vector_source_b(self.preamble + self.data, True, 1, []) + head = blocks.head(gr.sizeof_float * 1, num_samp) vsi = blocks.vector_sink_f() self.tb.connect(vso, constmod, chan, correst, leq, evm, head, vsi) self.tb.run() # look at the last 1000 samples, should converge quickly, below 5% EVM - upper_bound = list(20.0*numpy.ones((num_test,))) - lower_bound = list(0.0*numpy.zeros((num_test,))) + upper_bound = list(20.0 * numpy.ones((num_test,))) + lower_bound = list(0.0 * numpy.zeros((num_test,))) output_data = vsi.data() output_data = output_data[-num_test:] self.assertLess(output_data, upper_bound) diff --git a/gr-digital/python/digital/qa_lms_equalizer.py b/gr-digital/python/digital/qa_lms_equalizer.py index 12f6b26bcc..23e3c6f28f 100644 --- a/gr-digital/python/digital/qa_lms_equalizer.py +++ b/gr-digital/python/digital/qa_lms_equalizer.py @@ -11,6 +11,7 @@ from gnuradio import gr, gr_unittest, digital, blocks + class test_lms_dd_equalizer(gr_unittest.TestCase): def setUp(self): @@ -30,14 +31,15 @@ class test_lms_dd_equalizer(gr_unittest.TestCase): def test_001_identity(self): # Constant modulus signal so no adjustments const = digital.constellation_qpsk() - src_data = const.points()*1000 + src_data = const.points() * 1000 - N = 100 # settling time + N = 100 # settling time expected_data = src_data[N:] result = self.transform(src_data, 0.1, const)[N:] N = -500 self.assertComplexTuplesAlmostEqual(expected_data[N:], result[N:], 5) + if __name__ == "__main__": gr_unittest.run(test_lms_dd_equalizer) diff --git a/gr-digital/python/digital/qa_map.py b/gr-digital/python/digital/qa_map.py index 59d0ed1ee5..384636e595 100644 --- a/gr-digital/python/digital/qa_map.py +++ b/gr-digital/python/digital/qa_map.py @@ -1,16 +1,17 @@ #!/usr/bin/env python # # Copyright 2012,2013 Free Software Foundation, Inc. -# +# # This file is part of GNU Radio -# +# # SPDX-License-Identifier: GPL-3.0-or-later # -# +# from gnuradio import gr, gr_unittest, digital, blocks + class test_map(gr_unittest.TestCase): def setUp(self): @@ -34,15 +35,15 @@ class test_map(gr_unittest.TestCase): def test_001(self): symbols = [0, 0, 0, 0] self.helper(symbols) - + def test_002(self): symbols = [3, 2, 1, 0] self.helper(symbols) def test_003(self): - symbols = [8-1, 32-1, 128, 256-1] + symbols = [8 - 1, 32 - 1, 128, 256 - 1] self.helper(symbols) + if __name__ == '__main__': gr_unittest.run(test_map) - diff --git a/gr-digital/python/digital/qa_meas_evm_cc.py b/gr-digital/python/digital/qa_meas_evm_cc.py index 580d2acce5..3c0196b9d6 100755 --- a/gr-digital/python/digital/qa_meas_evm_cc.py +++ b/gr-digital/python/digital/qa_meas_evm_cc.py @@ -1,20 +1,22 @@ #!/usr/bin/env python # # Copyright 2020 Free Software Foundation, Inc. -# +# # This file is part of GNU Radio -# +# # SPDX-License-Identifier: GPL-3.0-or-later # -# +# from gnuradio import gr, gr_unittest from gnuradio import blocks -import random, numpy +import random +import numpy from gnuradio import digital from gnuradio import channels + class qa_meas_evm_cc(gr_unittest.TestCase): def setUp(self): @@ -30,8 +32,10 @@ class qa_meas_evm_cc(gr_unittest.TestCase): expected_result = list(numpy.zeros((self.num_data,))) self.cons = cons = digital.constellation_qpsk().base() - self.data = data = [random.randrange(len(cons.points())) for x in range(self.num_data)] - self.symbols = symbols = numpy.squeeze([cons.map_to_points_v(i) for i in data]) + self.data = data = [random.randrange( + len(cons.points())) for x in range(self.num_data)] + self.symbols = symbols = numpy.squeeze( + [cons.map_to_points_v(i) for i in data]) evm = digital.meas_evm_cc(cons, digital.evm_measurement_t.EVM_PERCENT) vso = blocks.vector_source_c(symbols, False, 1, []) @@ -50,12 +54,14 @@ class qa_meas_evm_cc(gr_unittest.TestCase): expected_result = list(numpy.zeros((self.num_data,))) self.cons = cons = digital.constellation_qpsk().base() - self.data = data = [random.randrange(len(cons.points())) for x in range(self.num_data)] - self.symbols = symbols = numpy.squeeze([cons.map_to_points_v(i) for i in data]) + self.data = data = [random.randrange( + len(cons.points())) for x in range(self.num_data)] + self.symbols = symbols = numpy.squeeze( + [cons.map_to_points_v(i) for i in data]) evm = digital.meas_evm_cc(cons, digital.evm_measurement_t.EVM_PERCENT) vso = blocks.vector_source_c(symbols, False, 1, []) - mc = blocks.multiply_const_cc(3.0+2.0j) + mc = blocks.multiply_const_cc(3.0 + 2.0j) vsi = blocks.vector_sink_f() self.tb.connect(vso, mc, evm, vsi) @@ -66,12 +72,14 @@ class qa_meas_evm_cc(gr_unittest.TestCase): self.assertNotEqual(expected_result, output_data) def test_qpsk_channel(self): - upper_bound = list(50.0*numpy.ones((self.num_data,))) - lower_bound = list(0.0*numpy.zeros((self.num_data,))) + upper_bound = list(50.0 * numpy.ones((self.num_data,))) + lower_bound = list(0.0 * numpy.zeros((self.num_data,))) self.cons = cons = digital.constellation_qpsk().base() - self.data = data = [random.randrange(len(cons.points())) for x in range(self.num_data)] - self.symbols = symbols = numpy.squeeze([cons.map_to_points_v(i) for i in data]) + self.data = data = [random.randrange( + len(cons.points())) for x in range(self.num_data)] + self.symbols = symbols = numpy.squeeze( + [cons.map_to_points_v(i) for i in data]) chan = channels.channel_model( noise_voltage=0.1, @@ -83,7 +91,7 @@ class qa_meas_evm_cc(gr_unittest.TestCase): evm = digital.meas_evm_cc(cons, digital.evm_measurement_t.EVM_PERCENT) vso = blocks.vector_source_c(symbols, False, 1, []) - mc = blocks.multiply_const_cc(3.0+2.0j) + mc = blocks.multiply_const_cc(3.0 + 2.0j) vsi = blocks.vector_sink_f() self.tb.connect(vso, chan, evm, vsi) @@ -95,12 +103,14 @@ class qa_meas_evm_cc(gr_unittest.TestCase): self.assertGreater(output_data, lower_bound) def test_qam16_channel(self): - upper_bound = list(50.0*numpy.ones((self.num_data,))) - lower_bound = list(0.0*numpy.zeros((self.num_data,))) + upper_bound = list(50.0 * numpy.ones((self.num_data,))) + lower_bound = list(0.0 * numpy.zeros((self.num_data,))) self.cons = cons = digital.constellation_16qam().base() - self.data = data = [random.randrange(len(cons.points())) for x in range(self.num_data)] - self.symbols = symbols = numpy.squeeze([cons.map_to_points_v(i) for i in data]) + self.data = data = [random.randrange( + len(cons.points())) for x in range(self.num_data)] + self.symbols = symbols = numpy.squeeze( + [cons.map_to_points_v(i) for i in data]) chan = channels.channel_model( noise_voltage=0.1, @@ -112,7 +122,7 @@ class qa_meas_evm_cc(gr_unittest.TestCase): evm = digital.meas_evm_cc(cons, digital.evm_measurement_t.EVM_PERCENT) vso = blocks.vector_source_c(symbols, False, 1, []) - mc = blocks.multiply_const_cc(3.0+2.0j) + mc = blocks.multiply_const_cc(3.0 + 2.0j) vsi = blocks.vector_sink_f() self.tb.connect(vso, chan, evm, vsi) @@ -123,5 +133,6 @@ class qa_meas_evm_cc(gr_unittest.TestCase): self.assertLess(output_data, upper_bound) self.assertGreater(output_data, lower_bound) + if __name__ == '__main__': gr_unittest.run(qa_meas_evm_cc) diff --git a/gr-digital/python/digital/qa_mpsk_snr_est.py b/gr-digital/python/digital/qa_mpsk_snr_est.py index 3834aecaf0..50d60103ef 100644 --- a/gr-digital/python/digital/qa_mpsk_snr_est.py +++ b/gr-digital/python/digital/qa_mpsk_snr_est.py @@ -13,21 +13,27 @@ import random from gnuradio import gr, gr_unittest, digital, blocks + def random_bit(): """Create random bits using random() rather than randint(). The latter changed for Python 3.2.""" return random.random() > .5 + + def get_cplx(): "Return a BPSK symbol (complex)" - return complex(2*random_bit() - 1, 0) + return complex(2 * random_bit() - 1, 0) + + def get_n_cplx(): "Return random, normal-distributed complex number" - return complex(random.random()-0.5, random.random()-0.5) + return complex(random.random() - 0.5, random.random() - 0.5) + class test_mpsk_snr_est(gr_unittest.TestCase): def setUp(self): self.tb = gr.top_block() - random.seed(0) # make repeatable + random.seed(0) # make repeatable N = 10000 self._noise = [get_n_cplx() for _ in range(N)] self._bits = [get_cplx() for _ in range(N)] @@ -38,13 +44,13 @@ class test_mpsk_snr_est(gr_unittest.TestCase): def mpsk_snr_est_setup(self, op): result = [] for i in range(1, 6): - src_data = [b+(i*n) for b,n in zip(self._bits, self._noise)] + src_data = [b + (i * n) for b, n in zip(self._bits, self._noise)] src = blocks.vector_source_c(src_data) dst = blocks.null_sink(gr.sizeof_gr_complex) tb = gr.top_block() tb.connect(src, op) tb.connect(op, dst) - tb.run() # run the graph and wait for it to finish + tb.run() # run the graph and wait for it to finish result.append(op.snr()) return result @@ -93,8 +99,8 @@ class test_mpsk_snr_est(gr_unittest.TestCase): expected_result = [8.01, 3.19, 1.97, 2.15, 2.65] actual_result = [] - for i in range(1,6): - src_data = [b+(i*n) for b,n in zip(self._bits, self._noise)] + for i in range(1, 6): + src_data = [b + (i * n) for b, n in zip(self._bits, self._noise)] src = blocks.vector_source_c(src_data) @@ -109,6 +115,7 @@ class test_mpsk_snr_est(gr_unittest.TestCase): actual_result.append(op.snr()) self.assertFloatTuplesAlmostEqual(expected_result, actual_result, 2) + if __name__ == '__main__': # Test various SNR estimators; we're not using a Gaussian # noise source, so these estimates have no real meaning; diff --git a/gr-digital/python/digital/qa_ofdm_carrier_allocator_cvc.py b/gr-digital/python/digital/qa_ofdm_carrier_allocator_cvc.py index ae06f8eaf2..0b1cddbaa6 100644 --- a/gr-digital/python/digital/qa_ofdm_carrier_allocator_cvc.py +++ b/gr-digital/python/digital/qa_ofdm_carrier_allocator_cvc.py @@ -10,16 +10,17 @@ from gnuradio import gr, gr_unittest, digital, blocks import pmt + class qa_digital_carrier_allocator_cvc (gr_unittest.TestCase): - def setUp (self): - self.tb = gr.top_block () + def setUp(self): + self.tb = gr.top_block() self.tsb_key = "ts_last" - def tearDown (self): + def tearDown(self): self.tb = None - def test_001_t (self): + def test_001_t(self): """ pretty simple (the carrier allocation here is not a practical OFDM configuration!) """ @@ -34,21 +35,24 @@ class qa_digital_carrier_allocator_cvc (gr_unittest.TestCase): # ^ DC carrier src = blocks.vector_source_c(tx_symbols, False, 1) alloc = digital.ofdm_carrier_allocator_cvc(fft_len, - occupied_carriers, - pilot_carriers, - pilot_symbols, sync_word, - self.tsb_key) + occupied_carriers, + pilot_carriers, + pilot_symbols, sync_word, + self.tsb_key) sink = blocks.tsb_vector_sink_c(vlen=fft_len, tsb_key=self.tsb_key) self.tb.connect( - src, - blocks.stream_to_tagged_stream(gr.sizeof_gr_complex, 1, len(tx_symbols), self.tsb_key), - alloc, - sink - ) + src, + blocks.stream_to_tagged_stream( + gr.sizeof_gr_complex, + 1, + len(tx_symbols), + self.tsb_key), + alloc, + sink) self.tb.run() self.assertEqual(sink.data()[0], expected_result) - def test_001_t2 (self): + def test_001_t2(self): """ pretty simple (same as before, but odd fft len) """ @@ -62,18 +66,26 @@ class qa_digital_carrier_allocator_cvc (gr_unittest.TestCase): # ^ DC carrier src = blocks.vector_source_c(tx_symbols, False, 1) alloc = digital.ofdm_carrier_allocator_cvc( - fft_len, - occupied_carriers, - pilot_carriers, - pilot_symbols, (), - self.tsb_key + fft_len, + occupied_carriers, + pilot_carriers, + pilot_symbols, (), + self.tsb_key ) sink = blocks.tsb_vector_sink_c(vlen=fft_len, tsb_key=self.tsb_key) - self.tb.connect(src, blocks.stream_to_tagged_stream(gr.sizeof_gr_complex, 1, len(tx_symbols), self.tsb_key), alloc, sink) - self.tb.run () + self.tb.connect( + src, + blocks.stream_to_tagged_stream( + gr.sizeof_gr_complex, + 1, + len(tx_symbols), + self.tsb_key), + alloc, + sink) + self.tb.run() self.assertEqual(sink.data()[0], expected_result) - def test_002_t (self): + def test_002_t(self): """ same, but using negative carrier indices """ @@ -85,21 +97,24 @@ class qa_digital_carrier_allocator_cvc (gr_unittest.TestCase): expected_result = [1j, 0, 1, 0, 2, 3] src = blocks.vector_source_c(tx_symbols, False, 1) alloc = digital.ofdm_carrier_allocator_cvc(fft_len, - occupied_carriers, - pilot_carriers, - pilot_symbols, (), - self.tsb_key) + occupied_carriers, + pilot_carriers, + pilot_symbols, (), + self.tsb_key) sink = blocks.tsb_vector_sink_c(fft_len) self.tb.connect( - src, - blocks.stream_to_tagged_stream(gr.sizeof_gr_complex, 1, len(tx_symbols), self.tsb_key), - alloc, - sink - ) - self.tb.run () + src, + blocks.stream_to_tagged_stream( + gr.sizeof_gr_complex, + 1, + len(tx_symbols), + self.tsb_key), + alloc, + sink) + self.tb.run() self.assertEqual(sink.data()[0], expected_result) - def test_002_tb (self): + def test_002_tb(self): """ once again, but this time add a sync word """ @@ -109,7 +124,8 @@ class qa_digital_carrier_allocator_cvc (gr_unittest.TestCase): pilot_symbols = ((1j,),) occupied_carriers = ((-1, 1, 2),) pilot_carriers = ((3,),) - expected_result = list(sync_word + (1j, 0, 1, 0, 2, 3) + (1j, 0, 4, 0, 5, 6)) + expected_result = list( + sync_word + (1j, 0, 1, 0, 2, 3) + (1j, 0, 4, 0, 5, 6)) special_tag1 = gr.tag_t() special_tag1.offset = 0 special_tag1.key = pmt.string_to_symbol("spam") @@ -131,18 +147,26 @@ class qa_digital_carrier_allocator_cvc (gr_unittest.TestCase): len_tag_key=self.tsb_key ) sink = blocks.tsb_vector_sink_c(fft_len) - self.tb.connect(src, blocks.stream_to_tagged_stream(gr.sizeof_gr_complex, 1, len(tx_symbols), self.tsb_key), alloc, sink) - self.tb.run () + self.tb.connect( + src, + blocks.stream_to_tagged_stream( + gr.sizeof_gr_complex, + 1, + len(tx_symbols), + self.tsb_key), + alloc, + sink) + self.tb.run() self.assertEqual(sink.data()[0], expected_result) tags = [gr.tag_to_python(x) for x in sink.tags()] tags = sorted([(x.offset, x.key, x.value) for x in tags]) tags_expected = [ - (0, 'spam', 23), - (2, 'eggs', 42), + (0, 'spam', 23), + (2, 'eggs', 42), ] self.assertEqual(tags, tags_expected) - def test_003_t (self): + def test_003_t(self): """ more advanced: - 6 symbols per carrier @@ -152,42 +176,102 @@ class qa_digital_carrier_allocator_cvc (gr_unittest.TestCase): - add some random tags - don't shift """ - tx_symbols = list(range(1, 16)); # 15 symbols + tx_symbols = list(range(1, 16)) # 15 symbols pilot_symbols = ((1j, 2j), (3j, 4j)) occupied_carriers = ((1, 3, 4, 11, 12, 14), (1, 2, 4, 11, 13, 14),) pilot_carriers = ((2, 13), (3, 12)) - expected_result = list((0, 1, 1j, 2, 3, 0, 0, 0, 0, 0, 0, 4, 5, 2j, 6, 0, - 0, 7, 8, 3j, 9, 0, 0, 0, 0, 0, 0, 10, 4j, 11, 12, 0, - 0, 13, 1j, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 2j, 0, 0)) + expected_result = list( + (0, + 1, + 1j, + 2, + 3, + 0, + 0, + 0, + 0, + 0, + 0, + 4, + 5, + 2j, + 6, + 0, + 0, + 7, + 8, + 3j, + 9, + 0, + 0, + 0, + 0, + 0, + 0, + 10, + 4j, + 11, + 12, + 0, + 0, + 13, + 1j, + 14, + 15, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2j, + 0, + 0)) fft_len = 16 testtag1 = gr.tag_t() testtag1.offset = 0 testtag1.key = pmt.string_to_symbol('tag1') testtag1.value = pmt.from_long(0) testtag2 = gr.tag_t() - testtag2.offset = 7 # On the 2nd OFDM symbol + testtag2.offset = 7 # On the 2nd OFDM symbol testtag2.key = pmt.string_to_symbol('tag2') testtag2.value = pmt.from_long(0) testtag3 = gr.tag_t() - testtag3.offset = len(tx_symbols)+1 # First OFDM symbol of packet 2 + testtag3.offset = len(tx_symbols) + 1 # First OFDM symbol of packet 2 testtag3.key = pmt.string_to_symbol('tag3') testtag3.value = pmt.from_long(0) testtag4 = gr.tag_t() - testtag4.offset = 2*len(tx_symbols)-1 # Last OFDM symbol of packet 2 + # Last OFDM symbol of packet 2 + testtag4.offset = 2 * len(tx_symbols) - 1 testtag4.key = pmt.string_to_symbol('tag4') testtag4.value = pmt.from_long(0) - src = blocks.vector_source_c(tx_symbols * 2, False, 1, (testtag1, testtag2, testtag3, testtag4)) + src = blocks.vector_source_c( + tx_symbols * 2, False, 1, (testtag1, testtag2, testtag3, testtag4)) alloc = digital.ofdm_carrier_allocator_cvc(fft_len, - occupied_carriers, - pilot_carriers, - pilot_symbols, (), - self.tsb_key, - False) + occupied_carriers, + pilot_carriers, + pilot_symbols, (), + self.tsb_key, + False) sink = blocks.tsb_vector_sink_c(fft_len) - self.tb.connect(src, blocks.stream_to_tagged_stream(gr.sizeof_gr_complex, 1, len(tx_symbols), self.tsb_key), alloc, sink) - self.tb.run () + self.tb.connect( + src, + blocks.stream_to_tagged_stream( + gr.sizeof_gr_complex, + 1, + len(tx_symbols), + self.tsb_key), + alloc, + sink) + self.tb.run() self.assertEqual(sink.data()[0], expected_result) - tags_found = {'tag1': False, 'tag2': False, 'tag3': False, 'tag4': False} + tags_found = { + 'tag1': False, + 'tag2': False, + 'tag3': False, + 'tag4': False} correct_offsets = {'tag1': 0, 'tag2': 1, 'tag3': 3, 'tag4': 5} for tag in sink.tags(): key = pmt.symbol_to_string(tag.key) @@ -196,49 +280,50 @@ class qa_digital_carrier_allocator_cvc (gr_unittest.TestCase): self.assertEqual(correct_offsets[key], tag.offset) self.assertTrue(all(tags_found.values())) - def test_004_t (self): + def test_004_t(self): """ Provoking TypeError exceptions providing wrong user input (earlier invisible SIGFPE). """ fft_len = 6 # Occupied carriers - #with self.assertRaises(TypeError) as oc: - #Pybind11 raises this as a ValueError + # with self.assertRaises(TypeError) as oc: + # Pybind11 raises this as a ValueError with self.assertRaises(ValueError) as oc: - alloc = digital.ofdm_carrier_allocator_cvc(fft_len, - [], - [[],], - [[],], - [], - self.tsb_key) + alloc = digital.ofdm_carrier_allocator_cvc(fft_len, + [], + [[], ], + [[], ], + [], + self.tsb_key) # Pilot carriers - #Pybind11 raises this as a ValueError + # Pybind11 raises this as a ValueError with self.assertRaises(ValueError) as pc: - alloc = digital.ofdm_carrier_allocator_cvc(fft_len, - [[],], - [], - [[],], - [], - self.tsb_key) + alloc = digital.ofdm_carrier_allocator_cvc(fft_len, + [[], ], + [], + [[], ], + [], + self.tsb_key) # Pilot carrier symbols - #Pybind11 raises this as a ValueError + # Pybind11 raises this as a ValueError with self.assertRaises(ValueError) as ps: - alloc = digital.ofdm_carrier_allocator_cvc(fft_len, - [[],], - [[],], - [], - [], - self.tsb_key) + alloc = digital.ofdm_carrier_allocator_cvc(fft_len, + [[], ], + [[], ], + [], + [], + self.tsb_key) - - self.assertEqual(str(oc.exception), "Occupied carriers must be of type vector of vector i.e. ((),).") - self.assertEqual(str(pc.exception), "Pilot carriers must be of type vector of vector i.e. ((),).") - self.assertEqual(str(ps.exception), "Pilot symbols must be of type vector of vector i.e. ((),).") + self.assertEqual(str( + oc.exception), "Occupied carriers must be of type vector of vector i.e. ((),).") + self.assertEqual(str(pc.exception), + "Pilot carriers must be of type vector of vector i.e. ((),).") + self.assertEqual(str(ps.exception), + "Pilot symbols must be of type vector of vector i.e. ((),).") if __name__ == '__main__': gr_unittest.run(qa_digital_carrier_allocator_cvc) - diff --git a/gr-digital/python/digital/qa_ofdm_chanest_vcvc.py b/gr-digital/python/digital/qa_ofdm_chanest_vcvc.py index c9222ec0dc..c69d2af984 100644 --- a/gr-digital/python/digital/qa_ofdm_chanest_vcvc.py +++ b/gr-digital/python/digital/qa_ofdm_chanest_vcvc.py @@ -1,11 +1,11 @@ #!/usr/bin/env python # Copyright 2012-2014 Free Software Foundation, Inc. -# +# # This file is part of GNU Radio -# +# # SPDX-License-Identifier: GPL-3.0-or-later # -# +# import sys @@ -16,6 +16,7 @@ import numpy from gnuradio import gr, gr_unittest, blocks, analog, digital import pmt + def shift_tuple(vec, N): """ Shifts a vector by N elements. Fills up with zeros. """ if N > 0: @@ -24,6 +25,7 @@ def shift_tuple(vec, N): N = -N return tuple(vec[N:]) + (0,) * N + def rand_range(min_val, max_val): """ Returns a random value (uniform) from the interval min_val, max_val """ return random.random() * (max_val - min_val) + min_val @@ -31,25 +33,25 @@ def rand_range(min_val, max_val): class qa_ofdm_chanest_vcvc (gr_unittest.TestCase): - def setUp (self): + def setUp(self): random.seed(0) - self.tb = gr.top_block () + self.tb = gr.top_block() - def tearDown (self): + def tearDown(self): self.tb = None - def test_001_offset_2sym (self): + def test_001_offset_2sym(self): """ Add a frequency offset, check if it's correctly detected. Also add some random tags and see if they come out at the correct position. """ fft_len = 16 carr_offset = -2 - sync_symbol1 = (0, 0, 0, 1, 0, 1, 0, -1, 0, 1, 0, -1, 0, 1, 0, 0) - sync_symbol2 = (0, 0, 0, 1, -1, 1, -1, 1, 0, 1, -1, -1, -1, 1, 0, 0) - data_symbol = (0, 0, 0, 1, -1, 1, -1, 1, 0, 1, -1, -1, -1, 1, 0, 0) + sync_symbol1 = (0, 0, 0, 1, 0, 1, 0, -1, 0, 1, 0, -1, 0, 1, 0, 0) + sync_symbol2 = (0, 0, 0, 1, -1, 1, -1, 1, 0, 1, -1, -1, -1, 1, 0, 0) + data_symbol = (0, 0, 0, 1, -1, 1, -1, 1, 0, 1, -1, -1, -1, 1, 0, 0) tx_data = shift_tuple(sync_symbol1, carr_offset) + \ - shift_tuple(sync_symbol2, carr_offset) + \ - shift_tuple(data_symbol, carr_offset) + shift_tuple(sync_symbol2, carr_offset) + \ + shift_tuple(data_symbol, carr_offset) tag1 = gr.tag_t() tag1.offset = 0 tag1.key = pmt.string_to_symbol("test_tag_1") @@ -72,25 +74,24 @@ class qa_ofdm_chanest_vcvc (gr_unittest.TestCase): if ptag.key == 'ofdm_sync_chan_taps': ptags[ptag.key] = (None, ptag.offset) expected_tags = { - 'ofdm_sync_carr_offset': (-2, 0), - 'ofdm_sync_chan_taps': (None, 0), - 'test_tag_1': (23, 0), - 'test_tag_2': (42, 0), + 'ofdm_sync_carr_offset': (-2, 0), + 'ofdm_sync_chan_taps': (None, 0), + 'test_tag_1': (23, 0), + 'test_tag_2': (42, 0), } self.assertEqual(ptags, expected_tags) - - def test_002_offset_1sym (self): + def test_002_offset_1sym(self): """ Add a frequency offset, check if it's correctly detected. Difference to previous test is, it only uses one synchronisation symbol. """ fft_len = 16 carr_offset = -2 # This will not correct for +2 because it thinks carrier 14 is used # (because of interpolation) - sync_symbol = (0, 0, 0, 1, 0, 1, 0, -1, 0, 1, 0, -1, 0, 1, 0, 0) - data_symbol = (0, 0, 0, 1, -1, 1, -1, 1, 0, 1, -1, -1, -1, 1, 0, 0) + sync_symbol = (0, 0, 0, 1, 0, 1, 0, -1, 0, 1, 0, -1, 0, 1, 0, 0) + data_symbol = (0, 0, 0, 1, -1, 1, -1, 1, 0, 1, -1, -1, -1, 1, 0, 0) tx_data = shift_tuple(sync_symbol, carr_offset) + \ - shift_tuple(data_symbol, carr_offset) + shift_tuple(data_symbol, carr_offset) src = blocks.vector_source_c(tx_data, False, fft_len) # 17 is out of bounds! chanest = digital.ofdm_chanest_vcvc(sync_symbol, (), 1, 0, 17) @@ -104,13 +105,14 @@ class qa_ofdm_chanest_vcvc (gr_unittest.TestCase): carr_offset_hat = pmt.to_long(tag.value) self.assertEqual(pmt.to_long(tag.value), carr_offset) - def test_003_channel_no_carroffset (self): + def test_003_channel_no_carroffset(self): """ Add a channel, check if it's correctly estimated """ fft_len = 16 carr_offset = 0 - sync_symbol1 = (0, 0, 0, 1, 0, 1, 0, -1, 0, 1, 0, -1, 0, 1, 0, 0) - sync_symbol2 = (0, 0, 0, 1j, -1, 1, -1j, 1j, 0, 1, -1j, -1, -1j, 1, 0, 0) - data_symbol = (0, 0, 0, 1, -1, 1, -1, 1, 0, 1, -1, -1, -1, 1, 0, 0) + sync_symbol1 = (0, 0, 0, 1, 0, 1, 0, -1, 0, 1, 0, -1, 0, 1, 0, 0) + sync_symbol2 = (0, 0, 0, 1j, -1, 1, -1j, 1j, + 0, 1, -1j, -1, -1j, 1, 0, 0) + data_symbol = (0, 0, 0, 1, -1, 1, -1, 1, 0, 1, -1, -1, -1, 1, 0, 0) tx_data = sync_symbol1 + sync_symbol2 + data_symbol channel = [0, 0, 0, 2, -2, 2, 3j, 2, 0, 2, 2, 2, 2, 3, 0, 0] src = blocks.vector_source_c(tx_data, False, fft_len) @@ -122,7 +124,8 @@ class qa_ofdm_chanest_vcvc (gr_unittest.TestCase): self.tb.connect((chanest, 1), sink_chanest) self.tb.run() tags = sink.tags() - self.assertEqual(shift_tuple(sink.data(), -carr_offset), tuple(numpy.multiply(data_symbol, channel))) + self.assertEqual(shift_tuple(sink.data(), -carr_offset), + tuple(numpy.multiply(data_symbol, channel))) for tag in tags: if pmt.symbol_to_string(tag.key) == 'ofdm_sync_carr_offset': self.assertEqual(pmt.to_long(tag.value), carr_offset) @@ -130,13 +133,13 @@ class qa_ofdm_chanest_vcvc (gr_unittest.TestCase): self.assertEqual(pmt.c32vector_elements(tag.value), channel) self.assertEqual(sink_chanest.data(), channel) - def test_004_channel_no_carroffset_1sym (self): + def test_004_channel_no_carroffset_1sym(self): """ Add a channel, check if it's correctly estimated. Only uses 1 synchronisation symbol. """ fft_len = 16 carr_offset = 0 - sync_symbol = (0, 0, 0, 1, 0, 1, 0, -1, 0, 1, 0, -1, 0, 1, 0, 0) - data_symbol = (0, 0, 0, 1, -1, 1, -1, 1, 0, 1, -1, -1, -1, 1, 0, 0) + sync_symbol = (0, 0, 0, 1, 0, 1, 0, -1, 0, 1, 0, -1, 0, 1, 0, 0) + data_symbol = (0, 0, 0, 1, -1, 1, -1, 1, 0, 1, -1, -1, -1, 1, 0, 0) tx_data = sync_symbol + data_symbol channel = [0, 0, 0, 2, 2, 2, 2, 3, 3, 2.5, 2.5, -3, -3, 1j, 1j, 0] #channel = (0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0) @@ -156,14 +159,14 @@ class qa_ofdm_chanest_vcvc (gr_unittest.TestCase): if pmt.symbol_to_string(tag.key) == 'ofdm_sync_chan_taps': self.assertEqual(pmt.c32vector_elements(tag.value), channel) - def test_005_both_1sym_force (self): + def test_005_both_1sym_force(self): """ Add a channel, check if it's correctly estimated. Only uses 1 synchronisation symbol. """ fft_len = 16 carr_offset = 0 - sync_symbol = (0, 0, 0, 1, 0, 1, 0, -1, 0, 1, 0, -1, 0, 1, 0, 0) - ref_symbol = (0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0) - data_symbol = (0, 0, 0, 1, -1, 1, -1, 1, 0, 1, -1, -1, -1, 1, 0, 0) + sync_symbol = (0, 0, 0, 1, 0, 1, 0, -1, 0, 1, 0, -1, 0, 1, 0, 0) + ref_symbol = (0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0) + data_symbol = (0, 0, 0, 1, -1, 1, -1, 1, 0, 1, -1, -1, -1, 1, 0, 0) tx_data = sync_symbol + data_symbol channel = [0, 0, 0, 2, 2, 2, 2.5, 3, 2.5, 2, 2.5, 3, 2, 1, 1, 0] src = blocks.vector_source_c(tx_data, False, fft_len) @@ -179,20 +182,22 @@ class qa_ofdm_chanest_vcvc (gr_unittest.TestCase): if pmt.symbol_to_string(tag.key) == 'ofdm_sync_chan_taps': self.assertEqual(pmt.c32vector_elements(tag.value), channel) - def test_006_channel_and_carroffset (self): + def test_006_channel_and_carroffset(self): """ Add a channel, check if it's correctly estimated """ fft_len = 16 carr_offset = 2 - # Index 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - sync_symbol1 = (0, 0, 0, 1, 0, 1, 0, -1, 0, 1, 0, -1, 0, 1, 0, 0) - sync_symbol2 = (0, 0, 0, 1j, -1, 1, -1j, 1j, 0, 1, -1j, -1, -1j, 1, 0, 0) - data_symbol = (0, 0, 0, 1, -1, 1, -1, 1, 0, 1, -1, -1, -1, 1, 0, 0) + # Index 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 + # 15 + sync_symbol1 = (0, 0, 0, 1, 0, 1, 0, -1, 0, 1, 0, -1, 0, 1, 0, 0) + sync_symbol2 = (0, 0, 0, 1j, -1, 1, -1j, 1j, + 0, 1, -1j, -1, -1j, 1, 0, 0) + data_symbol = (0, 0, 0, 1, -1, 1, -1, 1, 0, 1, -1, -1, -1, 1, 0, 0) # Channel 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 # Shifted (0, 0, 0, 0, 0, 1j, -1, 1, -1j, 1j, 0, 1, -1j, -1, -1j, 1) - chanest_exp = [0, 0, 0, 5, 6, 7, 8, 9, 0, 11, 12, 13, 14, 15, 0, 0] + chanest_exp = [0, 0, 0, 5, 6, 7, 8, 9, 0, 11, 12, 13, 14, 15, 0, 0] tx_data = shift_tuple(sync_symbol1, carr_offset) + \ - shift_tuple(sync_symbol2, carr_offset) + \ - shift_tuple(data_symbol, carr_offset) + shift_tuple(sync_symbol2, carr_offset) + \ + shift_tuple(data_symbol, carr_offset) channel = list(range(fft_len)) src = blocks.vector_source_c(tx_data, False, fft_len) chan = blocks.multiply_const_vcc(channel) @@ -208,27 +213,108 @@ class qa_ofdm_chanest_vcvc (gr_unittest.TestCase): if pmt.symbol_to_string(tag.key) == 'ofdm_sync_chan_taps': chan_est = pmt.c32vector_elements(tag.value) self.assertEqual(chan_est, chanest_exp) - self.assertEqual(sink.data(), list(numpy.multiply(shift_tuple(data_symbol, carr_offset), channel))) - + self.assertEqual( + sink.data(), + list( + numpy.multiply( + shift_tuple( + data_symbol, + carr_offset), + channel))) def test_999_all_at_once(self): """docstring for test_999_all_at_once""" fft_len = 32 - # 6 carriers empty, 10 carriers full, 1 DC carrier, 10 carriers full, 5 carriers empty - syncsym_mask = (0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0) - carrier_mask = (0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0) + # 6 carriers empty, 10 carriers full, 1 DC carrier, 10 carriers full, 5 + # carriers empty + syncsym_mask = ( + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0) + carrier_mask = ( + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0) max_offset = 4 wgn_amplitude = 0.05 min_chan_ampl = 0.1 max_chan_ampl = 5 - n_iter = 20 # The more the accurater + n_iter = 20 # The more the accurater + def run_flow_graph(sync_sym1, sync_sym2, data_sym): top_block = gr.top_block() carr_offset = random.randint(-max_offset / 2, max_offset / 2) * 2 tx_data = shift_tuple(sync_sym1, carr_offset) + \ - shift_tuple(sync_sym2, carr_offset) + \ - shift_tuple(data_sym, carr_offset) - channel = [rand_range(min_chan_ampl, max_chan_ampl) * numpy.exp(1j * rand_range(0, 2 * numpy.pi)) for x in range(fft_len)] + shift_tuple(sync_sym2, carr_offset) + \ + shift_tuple(data_sym, carr_offset) + channel = [ + rand_range( + min_chan_ampl, + max_chan_ampl) * + numpy.exp( + 1j * + rand_range( + 0, + 2 * + numpy.pi)) for x in range(fft_len)] src = blocks.vector_source_c(tx_data, False, fft_len) chan = blocks.multiply_const_vcc(channel) noise = analog.noise_source_c(analog.GR_GAUSSIAN, wgn_amplitude) @@ -236,32 +322,43 @@ class qa_ofdm_chanest_vcvc (gr_unittest.TestCase): chanest = digital.ofdm_chanest_vcvc(sync_sym1, sync_sym2, 1) sink = blocks.vector_sink_c(fft_len) top_block.connect(src, chan, (add, 0), chanest, sink) - top_block.connect(noise, blocks.stream_to_vector(gr.sizeof_gr_complex, fft_len), (add, 1)) + top_block.connect( + noise, blocks.stream_to_vector( + gr.sizeof_gr_complex, fft_len), (add, 1)) top_block.run() channel_est = None carr_offset_hat = 0 - rx_sym_est = [0,] * fft_len + rx_sym_est = [0, ] * fft_len tags = sink.tags() for tag in tags: if pmt.symbol_to_string(tag.key) == 'ofdm_sync_carr_offset': carr_offset_hat = pmt.to_long(tag.value) self.assertEqual(carr_offset, carr_offset_hat) if pmt.symbol_to_string(tag.key) == 'ofdm_sync_chan_taps': - channel_est = shift_tuple(pmt.c32vector_elements(tag.value), carr_offset) + channel_est = shift_tuple( + pmt.c32vector_elements( + tag.value), carr_offset) shifted_carrier_mask = shift_tuple(carrier_mask, carr_offset) for i in range(fft_len): if shifted_carrier_mask[i] and channel_est[i]: - self.assertAlmostEqual(channel[i], channel_est[i], places=0) + self.assertAlmostEqual( + channel[i], channel_est[i], places=0) rx_sym_est[i] = (sink.data()[i] / channel_est[i]).real - return (carr_offset, list(shift_tuple(rx_sym_est, -carr_offset_hat))) + return ( + carr_offset, list( + shift_tuple( + rx_sym_est, -carr_offset_hat))) bit_errors = 0 for k in range(n_iter): - sync_sym = [(random.randint(0, 1) * 2 - 1) * syncsym_mask[i] for i in range(fft_len)] - ref_sym = [(random.randint(0, 1) * 2 - 1) * carrier_mask[i] for i in range(fft_len)] - data_sym = [(random.randint(0, 1) * 2 - 1) * carrier_mask[i] for i in range(fft_len)] + sync_sym = [(random.randint(0, 1) * 2 - 1) * syncsym_mask[i] + for i in range(fft_len)] + ref_sym = [(random.randint(0, 1) * 2 - 1) * carrier_mask[i] + for i in range(fft_len)] + data_sym = [(random.randint(0, 1) * 2 - 1) * carrier_mask[i] + for i in range(fft_len)] data_sym[26] = 1 (carr_offset, rx_sym) = run_flow_graph(sync_sym, ref_sym, data_sym) - rx_sym_est = [0,] * fft_len + rx_sym_est = [0, ] * fft_len for i in range(fft_len): if carrier_mask[i] == 0: continue @@ -274,4 +371,3 @@ class qa_ofdm_chanest_vcvc (gr_unittest.TestCase): if __name__ == '__main__': gr_unittest.run(qa_ofdm_chanest_vcvc) - diff --git a/gr-digital/python/digital/qa_ofdm_cyclic_prefixer.py b/gr-digital/python/digital/qa_ofdm_cyclic_prefixer.py index 0d4d4f0fbe..f5eefd60f4 100644 --- a/gr-digital/python/digital/qa_ofdm_cyclic_prefixer.py +++ b/gr-digital/python/digital/qa_ofdm_cyclic_prefixer.py @@ -14,12 +14,13 @@ Unit tests for OFDM cyclic prefixer. from gnuradio import gr, gr_unittest, digital, blocks import pmt + class test_ofdm_cyclic_prefixer (gr_unittest.TestCase): - def setUp (self): - self.tb = gr.top_block () + def setUp(self): + self.tb = gr.top_block() - def tearDown (self): + def tearDown(self): self.tb = None def test_wo_tags_no_rolloff(self): @@ -40,9 +41,17 @@ class test_ofdm_cyclic_prefixer (gr_unittest.TestCase): fft_len = 8 cp_len = 2 rolloff = 2 - expected_result = [7.0 / 2, 8, 1, 2, 3, 4, 5, 6, 7, 8, # 1.0/2 - 7.0 / 2+1.0 / 2, 8, 1, 2, 3, 4, 5, 6, 7, 8] - src = blocks.vector_source_c(list(range(1, fft_len+1)) * 2, False, fft_len) + expected_result = [7.0 / 2, 8, 1, 2, 3, 4, 5, 6, 7, 8, # 1.0/2 + 7.0 / 2 + 1.0 / 2, 8, 1, 2, 3, 4, 5, 6, 7, 8] + src = blocks.vector_source_c( + list( + range( + 1, + fft_len + + 1)) * + 2, + False, + fft_len) cp = digital.ofdm_cyclic_prefixer(fft_len, fft_len + cp_len, rolloff) sink = blocks.vector_sink_c() self.tb.connect(src, cp, sink) @@ -54,22 +63,32 @@ class test_ofdm_cyclic_prefixer (gr_unittest.TestCase): fft_len = 8 cp_len = 2 tag_name = "ts_last" - expected_result = [7.0 / 2, 8, 1, 2, 3, 4, 5, 6, 7, 8, # 1.0/2 - 7.0 / 2+1.0 / 2, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1.0 / 2] + expected_result = [7.0 / 2, 8, 1, 2, 3, 4, 5, 6, 7, 8, # 1.0/2 + 7.0 / 2 + 1.0 / 2, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1.0 / 2] tag2 = gr.tag_t() tag2.offset = 1 tag2.key = pmt.string_to_symbol("random_tag") tag2.value = pmt.from_long(42) - src = blocks.vector_source_c(list(range(1, fft_len+1)) * 2, False, fft_len, (tag2,)) - cp = digital.ofdm_cyclic_prefixer(fft_len, fft_len + cp_len, 2, tag_name) + src = blocks.vector_source_c( + list(range(1, fft_len + 1)) * 2, False, fft_len, (tag2,)) + cp = digital.ofdm_cyclic_prefixer( + fft_len, fft_len + cp_len, 2, tag_name) sink = blocks.tsb_vector_sink_c(tsb_key=tag_name) - self.tb.connect(src, blocks.stream_to_tagged_stream(gr.sizeof_gr_complex, fft_len, 2, tag_name), cp, sink) + self.tb.connect( + src, + blocks.stream_to_tagged_stream( + gr.sizeof_gr_complex, + fft_len, + 2, + tag_name), + cp, + sink) self.tb.run() self.assertEqual(sink.data()[0], expected_result) tags = [gr.tag_to_python(x) for x in sink.tags()] tags = sorted([(x.offset, x.key, x.value) for x in tags]) expected_tags = [ - (fft_len+cp_len, "random_tag", 42) + (fft_len + cp_len, "random_tag", 42) ] self.assertEqual(tags, expected_tags) @@ -77,13 +96,13 @@ class test_ofdm_cyclic_prefixer (gr_unittest.TestCase): "Two CP lengths, no rolloff and no tags." fft_len = 8 cp_lengths = (3, 2, 2) - expected_result = [5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, # 1 + expected_result = [5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, # 1 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, # 2 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, # 3 - 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, # 4 + 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, # 4 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, # 5 - ] - src = blocks.vector_source_c(list(range(fft_len))*5, False, fft_len) + ] + src = blocks.vector_source_c(list(range(fft_len)) * 5, False, fft_len) cp = digital.ofdm_cyclic_prefixer(fft_len, cp_lengths) sink = blocks.vector_sink_c() self.tb.connect(src, cp, sink) @@ -95,13 +114,21 @@ class test_ofdm_cyclic_prefixer (gr_unittest.TestCase): fft_len = 8 cp_lengths = (3, 2, 2) rolloff = 2 - expected_result = [6.0/2,7,8,1,2,3,4,5,6,7,8, #1 - 7.0/2 + 1.0/2,8,1,2,3,4,5,6,7,8, #2 - 7.0/2 + 1.0/2,8,1,2,3,4,5,6,7,8, #3 - 6.0/2 + 1.0/2,7,8,1,2,3,4,5,6,7,8,#4 - 7.0/2 + 1.0/2,8,1,2,3,4,5,6,7,8 #5 - ] - src = blocks.vector_source_c(list(range(1, fft_len+1))*5, False, fft_len) + expected_result = [6.0 / 2, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, # 1 + 7.0 / 2 + 1.0 / 2, 8, 1, 2, 3, 4, 5, 6, 7, 8, # 2 + 7.0 / 2 + 1.0 / 2, 8, 1, 2, 3, 4, 5, 6, 7, 8, # 3 + 6.0 / 2 + 1.0 / 2, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, # 4 + 7.0 / 2 + 1.0 / 2, 8, 1, 2, 3, 4, 5, 6, 7, 8 # 5 + ] + src = blocks.vector_source_c( + list( + range( + 1, + fft_len + + 1)) * + 5, + False, + fft_len) cp = digital.ofdm_cyclic_prefixer(fft_len, cp_lengths, rolloff) sink = blocks.vector_sink_c() self.tb.connect(src, cp, sink) @@ -115,8 +142,8 @@ class test_ofdm_cyclic_prefixer (gr_unittest.TestCase): rolloff = 2 tag_name = "ts_last" expected_result = [ - 6.0/2, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, #1 - 7.0/2+1.0/2, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1.0/2 #Last tail + 6.0 / 2, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, # 1 + 7.0 / 2 + 1.0 / 2, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1.0 / 2 # Last tail ] # First test tag tag0 = gr.tag_t() @@ -128,10 +155,20 @@ class test_ofdm_cyclic_prefixer (gr_unittest.TestCase): tag1.offset = 1 tag1.key = pmt.string_to_symbol("second_tag") tag1.value = pmt.from_long(42) - src = blocks.vector_source_c(list(range(1, fft_len+1)) * 2, False, fft_len, (tag0, tag1)) - cp = digital.ofdm_cyclic_prefixer(fft_len, cp_lengths, rolloff, tag_name) + src = blocks.vector_source_c( + list(range(1, fft_len + 1)) * 2, False, fft_len, (tag0, tag1)) + cp = digital.ofdm_cyclic_prefixer( + fft_len, cp_lengths, rolloff, tag_name) sink = blocks.tsb_vector_sink_c(tsb_key=tag_name) - self.tb.connect(src, blocks.stream_to_tagged_stream(gr.sizeof_gr_complex, fft_len, 2, tag_name), cp, sink) + self.tb.connect( + src, + blocks.stream_to_tagged_stream( + gr.sizeof_gr_complex, + fft_len, + 2, + tag_name), + cp, + sink) self.tb.run() self.assertEqual(sink.data()[0], expected_result) tags = [gr.tag_to_python(x) for x in sink.tags()] diff --git a/gr-digital/python/digital/qa_ofdm_frame_equalizer_vcvc.py b/gr-digital/python/digital/qa_ofdm_frame_equalizer_vcvc.py index a1b2a2e070..730769e839 100755 --- a/gr-digital/python/digital/qa_ofdm_frame_equalizer_vcvc.py +++ b/gr-digital/python/digital/qa_ofdm_frame_equalizer_vcvc.py @@ -13,16 +13,17 @@ import numpy from gnuradio import gr, gr_unittest, digital, blocks import pmt + class qa_ofdm_frame_equalizer_vcvc (gr_unittest.TestCase): - def setUp (self): - self.tb = gr.top_block () + def setUp(self): + self.tb = gr.top_block() self.tsb_key = "tsb_key" - def tearDown (self): + def tearDown(self): self.tb = None - def test_001_simple (self): + def test_001_simple(self): """ Very simple functionality testing: - static equalizer - init channel state with all ones @@ -34,7 +35,7 @@ class qa_ofdm_frame_equalizer_vcvc (gr_unittest.TestCase): fft_len = 8 equalizer = digital.ofdm_equalizer_static(fft_len) n_syms = 3 - tx_data = [1,] * fft_len * n_syms + tx_data = [1, ] * fft_len * n_syms chan_tag = gr.tag_t() chan_tag.offset = 0 chan_tag.key = pmt.string_to_symbol("ofdm_sync_chan_taps") @@ -43,16 +44,21 @@ class qa_ofdm_frame_equalizer_vcvc (gr_unittest.TestCase): random_tag.offset = 1 random_tag.key = pmt.string_to_symbol("foo") random_tag.value = pmt.from_long(42) - src = blocks.vector_source_c(tx_data, False, fft_len, (chan_tag, random_tag)) - eq = digital.ofdm_frame_equalizer_vcvc(equalizer.base(), 0, self.tsb_key) + src = blocks.vector_source_c( + tx_data, False, fft_len, (chan_tag, random_tag)) + eq = digital.ofdm_frame_equalizer_vcvc( + equalizer.base(), 0, self.tsb_key) sink = blocks.tsb_vector_sink_c(fft_len, tsb_key=self.tsb_key) self.tb.connect( src, - blocks.stream_to_tagged_stream(gr.sizeof_gr_complex, fft_len, n_syms, self.tsb_key), + blocks.stream_to_tagged_stream( + gr.sizeof_gr_complex, + fft_len, + n_syms, + self.tsb_key), eq, - sink - ) - self.tb.run () + sink) + self.tb.run() # Check data self.assertEqual(tx_data, sink.data()[0]) # Check tags @@ -65,32 +71,36 @@ class qa_ofdm_frame_equalizer_vcvc (gr_unittest.TestCase): } self.assertEqual(tag_dict, expected_dict) - def test_001b_simple_skip_nothing (self): + def test_001b_simple_skip_nothing(self): """ Same as before, but put a skip-header in there """ fft_len = 8 equalizer = digital.ofdm_equalizer_static(fft_len, symbols_skipped=1) n_syms = 3 - tx_data = [1,] * fft_len * n_syms + tx_data = [1, ] * fft_len * n_syms chan_tag = gr.tag_t() chan_tag.offset = 0 chan_tag.key = pmt.string_to_symbol("ofdm_sync_chan_taps") chan_tag.value = pmt.init_c32vector(fft_len, (1,) * fft_len) src = blocks.vector_source_c(tx_data, False, fft_len, (chan_tag,)) - eq = digital.ofdm_frame_equalizer_vcvc(equalizer.base(), 0, self.tsb_key) + eq = digital.ofdm_frame_equalizer_vcvc( + equalizer.base(), 0, self.tsb_key) sink = blocks.tsb_vector_sink_c(fft_len, tsb_key=self.tsb_key) self.tb.connect( src, - blocks.stream_to_tagged_stream(gr.sizeof_gr_complex, fft_len, n_syms, self.tsb_key), + blocks.stream_to_tagged_stream( + gr.sizeof_gr_complex, + fft_len, + n_syms, + self.tsb_key), eq, - sink - ) - self.tb.run () + sink) + self.tb.run() # Check data self.assertEqual(tx_data, sink.data()[0]) - def test_001c_carrier_offset_no_cp (self): + def test_001c_carrier_offset_no_cp(self): """ Same as before, but put a carrier offset in there """ @@ -100,7 +110,7 @@ class qa_ofdm_frame_equalizer_vcvc (gr_unittest.TestCase): carr_offset = 1 occupied_carriers = ((-2, -1, 1, 2),) tx_data = ( - 0, 0, 0, -1j, -1j, 0, -1j, -1j, + 0, 0, 0, -1j, -1j, 0, -1j, -1j, ) # The rx'd signal is shifted rx_expected = (0, 0, 1, 1, 0, 1, 1, 0) * n_syms @@ -109,25 +119,32 @@ class qa_ofdm_frame_equalizer_vcvc (gr_unittest.TestCase): chan_tag.offset = 0 chan_tag.key = pmt.string_to_symbol("ofdm_sync_chan_taps") # Note: this is shifted to the correct position! - chan_tag.value = pmt.init_c32vector(fft_len, (0, 0, -1j, -1j, 0, -1j, -1j, 0)) + chan_tag.value = pmt.init_c32vector( + fft_len, (0, 0, -1j, -1j, 0, -1j, -1j, 0)) offset_tag = gr.tag_t() offset_tag.offset = 0 offset_tag.key = pmt.string_to_symbol("ofdm_sync_carr_offset") offset_tag.value = pmt.from_long(carr_offset) - src = blocks.vector_source_c(tx_data, False, fft_len, (chan_tag, offset_tag)) - eq = digital.ofdm_frame_equalizer_vcvc(equalizer.base(), cp_len, self.tsb_key) + src = blocks.vector_source_c( + tx_data, False, fft_len, (chan_tag, offset_tag)) + eq = digital.ofdm_frame_equalizer_vcvc( + equalizer.base(), cp_len, self.tsb_key) sink = blocks.tsb_vector_sink_c(fft_len, tsb_key=self.tsb_key) self.tb.connect( src, - blocks.stream_to_tagged_stream(gr.sizeof_gr_complex, fft_len, n_syms, self.tsb_key), + blocks.stream_to_tagged_stream( + gr.sizeof_gr_complex, + fft_len, + n_syms, + self.tsb_key), eq, - sink - ) - self.tb.run () + sink) + self.tb.run() # Check data - self.assertComplexTuplesAlmostEqual(rx_expected, sink.data()[0], places=4) + self.assertComplexTuplesAlmostEqual( + rx_expected, sink.data()[0], places=4) - def test_001c_carrier_offset_cp (self): + def test_001c_carrier_offset_cp(self): """ Same as before, but put a carrier offset in there and a CP """ @@ -139,9 +156,9 @@ class qa_ofdm_frame_equalizer_vcvc (gr_unittest.TestCase): occupied_carriers = ((-2, -1, 1, 2),) carr_offset = -1 tx_data = ( - 0,-1j,-1j, 0,-1j,-1j, 0, 0, - 0, -1, -1, 0, -1, -1, 0, 0, - 0, 1j, 1j, 0, 1j, 1j, 0, 0, + 0, -1j, -1j, 0, -1j, -1j, 0, 0, + 0, -1, -1, 0, -1, -1, 0, 0, + 0, 1j, 1j, 0, 1j, 1j, 0, 0, ) # Rx'd signal is corrected rx_expected = (0, 0, 1, 1, 0, 1, 1, 0) * n_syms @@ -154,68 +171,87 @@ class qa_ofdm_frame_equalizer_vcvc (gr_unittest.TestCase): offset_tag.offset = 0 offset_tag.key = pmt.string_to_symbol("ofdm_sync_carr_offset") offset_tag.value = pmt.from_long(carr_offset) - src = blocks.vector_source_c(tx_data, False, fft_len, (chan_tag, offset_tag)) - eq = digital.ofdm_frame_equalizer_vcvc(equalizer.base(), cp_len, self.tsb_key) + src = blocks.vector_source_c( + tx_data, False, fft_len, (chan_tag, offset_tag)) + eq = digital.ofdm_frame_equalizer_vcvc( + equalizer.base(), cp_len, self.tsb_key) sink = blocks.tsb_vector_sink_c(fft_len, tsb_key=self.tsb_key) self.tb.connect( src, - blocks.stream_to_tagged_stream(gr.sizeof_gr_complex, fft_len, n_syms, self.tsb_key), + blocks.stream_to_tagged_stream( + gr.sizeof_gr_complex, + fft_len, + n_syms, + self.tsb_key), eq, - sink - ) - self.tb.run () + sink) + self.tb.run() # Check data - self.assertComplexTuplesAlmostEqual(rx_expected, sink.data()[0], places=4) + self.assertComplexTuplesAlmostEqual( + rx_expected, sink.data()[0], places=4) - - def test_002_static (self): + def test_002_static(self): """ - Add a simple channel - Make symbols QPSK """ fft_len = 8 # 4 5 6 7 0 1 2 3 - tx_data = [-1, -1, 1, 2, -1, 3, 0, -1, # 0 - -1, -1, 0, 2, -1, 2, 0, -1, # 8 - -1, -1, 3, 0, -1, 1, 0, -1, # 16 (Pilot symbols) - -1, -1, 1, 1, -1, 0, 2, -1] # 24 + tx_data = [-1, -1, 1, 2, -1, 3, 0, -1, # 0 + -1, -1, 0, 2, -1, 2, 0, -1, # 8 + -1, -1, 3, 0, -1, 1, 0, -1, # 16 (Pilot symbols) + -1, -1, 1, 1, -1, 0, 2, -1] # 24 cnst = digital.constellation_qpsk() - tx_signal = [cnst.map_to_points_v(x)[0] if x != -1 else 0 for x in tx_data] + tx_signal = [ + cnst.map_to_points_v(x)[0] if x != - + 1 else 0 for x in tx_data] occupied_carriers = ((1, 2, 6, 7),) pilot_carriers = ((), (), (1, 2, 6, 7), ()) pilot_symbols = ( - [], [], [cnst.map_to_points_v(x)[0] for x in (1, 0, 3, 0)], [] + [], [], [cnst.map_to_points_v(x)[0] for x in (1, 0, 3, 0)], [] ) - equalizer = digital.ofdm_equalizer_static(fft_len, occupied_carriers, pilot_carriers, pilot_symbols) + equalizer = digital.ofdm_equalizer_static( + fft_len, occupied_carriers, pilot_carriers, pilot_symbols) channel = [ - 0, 0, 1, 1, 0, 1, 1, 0, - 0, 0, 1, 1, 0, 1, 1, 0, # These coefficients will be rotated slightly (but less than \pi/2) - 0, 0, 1j, 1j, 0, 1j, 1j, 0, # Go crazy here! + 0, 0, 1, 1, 0, 1, 1, 0, + # These coefficients will be rotated slightly (but less than \pi/2) + 0, 0, 1, 1, 0, 1, 1, 0, + 0, 0, 1j, 1j, 0, 1j, 1j, 0, # Go crazy here! 0, 0, 1j, 1j, 0, 1j, 1j, 0 ] channel = [ - 0, 0, 1, 1, 0, 1, 1, 0, - 0, 0, 1, 1, 0, 1, 1, 0, # These coefficients will be rotated slightly (but less than \pi/2) - 0, 0, 1j, 1j, 0, 1j, 1j, 0, # Go crazy here! + 0, 0, 1, 1, 0, 1, 1, 0, + # These coefficients will be rotated slightly (but less than \pi/2) + 0, 0, 1, 1, 0, 1, 1, 0, + 0, 0, 1j, 1j, 0, 1j, 1j, 0, # Go crazy here! 0, 0, 1j, 1j, 0, 1j, 1j, 0 ] - for idx in range(fft_len, 2*fft_len): - channel[idx] = channel[idx-fft_len] * numpy.exp(1j * .1 * numpy.pi * (numpy.random.rand()-.5)) + for idx in range(fft_len, 2 * fft_len): + channel[idx] = channel[idx - fft_len] * \ + numpy.exp(1j * .1 * numpy.pi * (numpy.random.rand() - .5)) chan_tag = gr.tag_t() chan_tag.offset = 0 chan_tag.key = pmt.string_to_symbol("ofdm_sync_chan_taps") chan_tag.value = pmt.init_c32vector(fft_len, channel[:fft_len]) - src = blocks.vector_source_c(numpy.multiply(tx_signal, channel), False, fft_len, (chan_tag,)) + src = blocks.vector_source_c(numpy.multiply( + tx_signal, channel), False, fft_len, (chan_tag,)) sink = blocks.tsb_vector_sink_c(vlen=fft_len, tsb_key=self.tsb_key) - eq = digital.ofdm_frame_equalizer_vcvc(equalizer.base(), 0, self.tsb_key, True) + eq = digital.ofdm_frame_equalizer_vcvc( + equalizer.base(), 0, self.tsb_key, True) self.tb.connect( - src, - blocks.stream_to_tagged_stream(gr.sizeof_gr_complex, fft_len, len(tx_data) // fft_len, self.tsb_key), - eq, - sink - ) - self.tb.run () - rx_data = [cnst.decision_maker_v((x,)) if x != 0 else -1 for x in sink.data()[0]] + src, + blocks.stream_to_tagged_stream( + gr.sizeof_gr_complex, + fft_len, + len(tx_data) // + fft_len, + self.tsb_key), + eq, + sink) + self.tb.run() + rx_data = [ + cnst.decision_maker_v( + (x,)) if x != 0 else -1 for x in sink.data()[0]] # Check data self.assertEqual(tx_data, rx_data) # Check tags @@ -228,14 +264,17 @@ class qa_ofdm_frame_equalizer_vcvc (gr_unittest.TestCase): else: tag_dict[ptag.key] = pmt.to_python(tag.value) expected_dict = { - 'ofdm_sync_chan_taps': channel[-fft_len:] + 'ofdm_sync_chan_taps': channel[-fft_len:] } # Won't be exactly the same when compiled with -fcx-limited-range - self.assertTrue(numpy.allclose(tag_dict['ofdm_sync_chan_taps'], expected_dict['ofdm_sync_chan_taps'])) + self.assertTrue( + numpy.allclose( + tag_dict['ofdm_sync_chan_taps'], + expected_dict['ofdm_sync_chan_taps'])) expected_dict['ofdm_sync_chan_taps'] = tag_dict['ofdm_sync_chan_taps'] self.assertEqual(tag_dict, expected_dict) - def test_002_static_wo_tags (self): + def test_002_static_wo_tags(self): """ Same as before, but the input stream has no tag. We specify the frame size in the constructor. We also specify a tag key, so the output stream *should* have @@ -244,145 +283,200 @@ class qa_ofdm_frame_equalizer_vcvc (gr_unittest.TestCase): fft_len = 8 n_syms = 4 # 4 5 6 7 0 1 2 3 - tx_data = [-1, -1, 1, 2, -1, 3, 0, -1, # 0 - -1, -1, 0, 2, -1, 2, 0, -1, # 8 - -1, -1, 3, 0, -1, 1, 0, -1, # 16 (Pilot symbols) - -1, -1, 1, 1, -1, 0, 2, -1] # 24 + tx_data = [-1, -1, 1, 2, -1, 3, 0, -1, # 0 + -1, -1, 0, 2, -1, 2, 0, -1, # 8 + -1, -1, 3, 0, -1, 1, 0, -1, # 16 (Pilot symbols) + -1, -1, 1, 1, -1, 0, 2, -1] # 24 cnst = digital.constellation_qpsk() - tx_signal = [cnst.map_to_points_v(x)[0] if x != -1 else 0 for x in tx_data] + tx_signal = [ + cnst.map_to_points_v(x)[0] if x != - + 1 else 0 for x in tx_data] occupied_carriers = ((1, 2, 6, 7),) pilot_carriers = ((), (), (1, 2, 6, 7), ()) pilot_symbols = ( - [], [], [cnst.map_to_points_v(x)[0] for x in (1, 0, 3, 0)], [] + [], [], [cnst.map_to_points_v(x)[0] for x in (1, 0, 3, 0)], [] ) - equalizer = digital.ofdm_equalizer_static(fft_len, occupied_carriers, pilot_carriers, pilot_symbols) + equalizer = digital.ofdm_equalizer_static( + fft_len, occupied_carriers, pilot_carriers, pilot_symbols) channel = [ - 0, 0, 1, 1, 0, 1, 1, 0, - 0, 0, 1, 1, 0, 1, 1, 0, # These coefficients will be rotated slightly (below)... - 0, 0, 1j, 1j, 0, 1j, 1j, 0, # Go crazy here! + 0, 0, 1, 1, 0, 1, 1, 0, + # These coefficients will be rotated slightly (below)... + 0, 0, 1, 1, 0, 1, 1, 0, + 0, 0, 1j, 1j, 0, 1j, 1j, 0, # Go crazy here! 0, 0, 1j, 1j, 0, 1j, 1j, 0 # ...and again here. ] - for idx in range(fft_len, 2*fft_len): - channel[idx] = channel[idx-fft_len] * numpy.exp(1j * .1 * numpy.pi * (numpy.random.rand()-.5)) - idx2 = idx+2*fft_len - channel[idx2] = channel[idx2] * numpy.exp(1j * 0 * numpy.pi * (numpy.random.rand()-.5)) - src = blocks.vector_source_c(numpy.multiply(tx_signal, channel), False, fft_len) - eq = digital.ofdm_frame_equalizer_vcvc(equalizer.base(), 0, self.tsb_key, False, n_syms) + for idx in range(fft_len, 2 * fft_len): + channel[idx] = channel[idx - fft_len] * \ + numpy.exp(1j * .1 * numpy.pi * (numpy.random.rand() - .5)) + idx2 = idx + 2 * fft_len + channel[idx2] = channel[idx2] * \ + numpy.exp(1j * 0 * numpy.pi * (numpy.random.rand() - .5)) + src = blocks.vector_source_c( + numpy.multiply( + tx_signal, + channel), + False, + fft_len) + eq = digital.ofdm_frame_equalizer_vcvc( + equalizer.base(), 0, self.tsb_key, False, n_syms) sink = blocks.tsb_vector_sink_c(vlen=fft_len, tsb_key=self.tsb_key) self.tb.connect( - src, - blocks.stream_to_tagged_stream(gr.sizeof_gr_complex, fft_len, len(tx_data) // fft_len, self.tsb_key), - eq, - sink - ) - self.tb.run () - rx_data = [cnst.decision_maker_v((x,)) if x != 0 else -1 for x in sink.data()[0]] + src, + blocks.stream_to_tagged_stream( + gr.sizeof_gr_complex, + fft_len, + len(tx_data) // + fft_len, + self.tsb_key), + eq, + sink) + self.tb.run() + rx_data = [ + cnst.decision_maker_v( + (x,)) if x != 0 else -1 for x in sink.data()[0]] self.assertEqual(tx_data, rx_data) # Check TSB Functionality packets = sink.data() self.assertEqual(len(packets), 1) self.assertEqual(len(packets[0]), len(tx_data)) - def test_002_static_wo_tags (self): + def test_002_static_wo_tags(self): fft_len = 8 # 4 5 6 7 0 1 2 3 - tx_data = [-1, -1, 1, 2, -1, 3, 0, -1, # 0 - -1, -1, 0, 2, -1, 2, 0, -1, # 8 - -1, -1, 3, 0, -1, 1, 0, -1, # 16 (Pilot symbols) - -1, -1, 1, 1, -1, 0, 2, -1] # 24 + tx_data = [-1, -1, 1, 2, -1, 3, 0, -1, # 0 + -1, -1, 0, 2, -1, 2, 0, -1, # 8 + -1, -1, 3, 0, -1, 1, 0, -1, # 16 (Pilot symbols) + -1, -1, 1, 1, -1, 0, 2, -1] # 24 cnst = digital.constellation_qpsk() - tx_signal = [cnst.map_to_points_v(x)[0] if x != -1 else 0 for x in tx_data] + tx_signal = [ + cnst.map_to_points_v(x)[0] if x != - + 1 else 0 for x in tx_data] occupied_carriers = ((1, 2, 6, 7),) pilot_carriers = ((), (), (1, 2, 6, 7), ()) pilot_symbols = ( - [], [], [cnst.map_to_points_v(x)[0] for x in (1, 0, 3, 0)], [] + [], [], [cnst.map_to_points_v(x)[0] for x in (1, 0, 3, 0)], [] ) - equalizer = digital.ofdm_equalizer_static(fft_len, occupied_carriers, pilot_carriers, pilot_symbols) + equalizer = digital.ofdm_equalizer_static( + fft_len, occupied_carriers, pilot_carriers, pilot_symbols) channel = [ - 0, 0, 1, 1, 0, 1, 1, 0, - 0, 0, 1, 1, 0, 1, 1, 0, # These coefficients will be rotated slightly... - 0, 0, 1j, 1j, 0, 1j, 1j, 0, # Go crazy here! + 0, 0, 1, 1, 0, 1, 1, 0, + # These coefficients will be rotated slightly... + 0, 0, 1, 1, 0, 1, 1, 0, + 0, 0, 1j, 1j, 0, 1j, 1j, 0, # Go crazy here! 0, 0, 1j, 1j, 0, 1j, 1j, 0 # ...and again here. ] - for idx in range(fft_len, 2*fft_len): - channel[idx] = channel[idx-fft_len] * numpy.exp(1j * .1 * numpy.pi * (numpy.random.rand()-.5)) - idx2 = idx+2*fft_len - channel[idx2] = channel[idx2] * numpy.exp(1j * 0 * numpy.pi * (numpy.random.rand()-.5)) - src = blocks.vector_source_c(numpy.multiply(tx_signal, channel), False, fft_len) + for idx in range(fft_len, 2 * fft_len): + channel[idx] = channel[idx - fft_len] * \ + numpy.exp(1j * .1 * numpy.pi * (numpy.random.rand() - .5)) + idx2 = idx + 2 * fft_len + channel[idx2] = channel[idx2] * \ + numpy.exp(1j * 0 * numpy.pi * (numpy.random.rand() - .5)) + src = blocks.vector_source_c( + numpy.multiply( + tx_signal, + channel), + False, + fft_len) sink = blocks.vector_sink_c(fft_len) - eq = digital.ofdm_frame_equalizer_vcvc(equalizer.base(), 0, "", False, 4) + eq = digital.ofdm_frame_equalizer_vcvc( + equalizer.base(), 0, "", False, 4) self.tb.connect(src, eq, sink) - self.tb.run () - rx_data = [cnst.decision_maker_v((x,)) if x != 0 else -1 for x in sink.data()] + self.tb.run() + rx_data = [ + cnst.decision_maker_v( + (x,)) if x != 0 else -1 for x in sink.data()] self.assertEqual(tx_data, rx_data) - def test_002_simpledfe (self): + def test_002_simpledfe(self): """ Use the simple DFE equalizer. """ fft_len = 8 # 4 5 6 7 0 1 2 3 - tx_data = [-1, -1, 1, 2, -1, 3, 0, -1, # 0 - -1, -1, 0, 2, -1, 2, 0, -1, # 8 - -1, -1, 3, 0, -1, 1, 0, -1, # 16 (Pilot symbols) - -1, -1, 1, 1, -1, 0, 2, -1] # 24 + tx_data = [-1, -1, 1, 2, -1, 3, 0, -1, # 0 + -1, -1, 0, 2, -1, 2, 0, -1, # 8 + -1, -1, 3, 0, -1, 1, 0, -1, # 16 (Pilot symbols) + -1, -1, 1, 1, -1, 0, 2, -1] # 24 cnst = digital.constellation_qpsk() - tx_signal = [cnst.map_to_points_v(x)[0] if x != -1 else 0 for x in tx_data] + tx_signal = [ + cnst.map_to_points_v(x)[0] if x != - + 1 else 0 for x in tx_data] occupied_carriers = ((1, 2, 6, 7),) pilot_carriers = ((), (), (1, 2, 6, 7), ()) pilot_symbols = ( - [], [], [cnst.map_to_points_v(x)[0] for x in (1, 0, 3, 0)], [] + [], [], [cnst.map_to_points_v(x)[0] for x in (1, 0, 3, 0)], [] ) equalizer = digital.ofdm_equalizer_simpledfe( - fft_len, cnst.base(), occupied_carriers, pilot_carriers, pilot_symbols, 0, 0.01 - ) + fft_len, + cnst.base(), + occupied_carriers, + pilot_carriers, + pilot_symbols, + 0, + 0.01) equalizer_soft = digital.ofdm_equalizer_simpledfe( - fft_len, cnst.base(), occupied_carriers, pilot_carriers, pilot_symbols, 0, 0.01, enable_soft_output=True - ) + fft_len, + cnst.base(), + occupied_carriers, + pilot_carriers, + pilot_symbols, + 0, + 0.01, + enable_soft_output=True) channel = [ - 0, 0, 1, 1, 0, 1, 1, 0, - 0, 0, 1, 1, 0, 1, 1, 0, # These coefficients will be rotated slightly... - 0, 0, 1j, 1j, 0, 1j, 1j, 0, # Go crazy here! + 0, 0, 1, 1, 0, 1, 1, 0, + # These coefficients will be rotated slightly... + 0, 0, 1, 1, 0, 1, 1, 0, + 0, 0, 1j, 1j, 0, 1j, 1j, 0, # Go crazy here! 0, 0, 1j, 1j, 0, 1j, 1j, 0 # ...and again here. ] - for idx in range(fft_len, 2*fft_len): - channel[idx] = channel[idx-fft_len] * numpy.exp(1j * .1 * numpy.pi * (numpy.random.rand()-.5)) - idx2 = idx+2*fft_len - channel[idx2] = channel[idx2] * numpy.exp(1j * 0 * numpy.pi * (numpy.random.rand()-.5)) + for idx in range(fft_len, 2 * fft_len): + channel[idx] = channel[idx - fft_len] * \ + numpy.exp(1j * .1 * numpy.pi * (numpy.random.rand() - .5)) + idx2 = idx + 2 * fft_len + channel[idx2] = channel[idx2] * \ + numpy.exp(1j * 0 * numpy.pi * (numpy.random.rand() - .5)) chan_tag = gr.tag_t() chan_tag.offset = 0 chan_tag.key = pmt.string_to_symbol("ofdm_sync_chan_taps") chan_tag.value = pmt.init_c32vector(fft_len, channel[:fft_len]) - src = blocks.vector_source_c(numpy.multiply(tx_signal, channel), False, fft_len, (chan_tag,)) - eq = digital.ofdm_frame_equalizer_vcvc(equalizer.base(), 0, self.tsb_key, True) - eq_soft = digital.ofdm_frame_equalizer_vcvc(equalizer_soft.base(), 0, self.tsb_key, True) + src = blocks.vector_source_c(numpy.multiply( + tx_signal, channel), False, fft_len, (chan_tag,)) + eq = digital.ofdm_frame_equalizer_vcvc( + equalizer.base(), 0, self.tsb_key, True) + eq_soft = digital.ofdm_frame_equalizer_vcvc( + equalizer_soft.base(), 0, self.tsb_key, True) sink = blocks.tsb_vector_sink_c(fft_len, tsb_key=self.tsb_key) sink_soft = blocks.tsb_vector_sink_c(fft_len, tsb_key=self.tsb_key) - stream_to_tagged = blocks.stream_to_tagged_stream(gr.sizeof_gr_complex, fft_len, len(tx_data) // fft_len, self.tsb_key) + stream_to_tagged = blocks.stream_to_tagged_stream( + gr.sizeof_gr_complex, fft_len, len(tx_data) // fft_len, self.tsb_key) self.tb.connect( - src, - stream_to_tagged, - eq, - sink + src, + stream_to_tagged, + eq, + sink ) self.tb.connect( - stream_to_tagged, - eq_soft, - sink_soft + stream_to_tagged, + eq_soft, + sink_soft ) - self.tb.run () + self.tb.run() out_syms = numpy.array(sink.data()[0]) out_syms_soft = numpy.array(sink_soft.data()[0]) - demod = lambda syms: [cnst.decision_maker_v((x,)) if x != 0 else -1 for x in syms] + + def demod(syms): return [ + cnst.decision_maker_v( + (x,)) if x != 0 else -1 for x in syms] rx_data = demod(out_syms) rx_data_soft = demod(out_syms_soft) - ## Uncomment to plot symbols + # Uncomment to plot symbols #import matplotlib.pyplot as plt #def plot_syms(d): plt.figure(); plt.plot(d.real, d.imag, 'b.') # - #plot_syms(out_syms) - #plot_syms(out_syms_soft) - #plt.show() + # plot_syms(out_syms) + # plot_syms(out_syms_soft) + # plt.show() self.assertEqual(tx_data, rx_data) self.assertEqual(rx_data, rx_data_soft) @@ -390,9 +484,9 @@ class qa_ofdm_frame_equalizer_vcvc (gr_unittest.TestCase): self.assertEqual(len(sink.tags()), 1) tag = sink.tags()[0] self.assertEqual(pmt.symbol_to_string(tag.key), "ofdm_sync_chan_taps") - self.assertComplexTuplesAlmostEqual(list(pmt.c32vector_elements(tag.value)), channel[-fft_len:], places=1) + self.assertComplexTuplesAlmostEqual( + list(pmt.c32vector_elements(tag.value)), channel[-fft_len:], places=1) if __name__ == '__main__': gr_unittest.run(qa_ofdm_frame_equalizer_vcvc) - diff --git a/gr-digital/python/digital/qa_ofdm_serializer_vcc.py b/gr-digital/python/digital/qa_ofdm_serializer_vcc.py index 049900a44e..07e801f72a 100644 --- a/gr-digital/python/digital/qa_ofdm_serializer_vcc.py +++ b/gr-digital/python/digital/qa_ofdm_serializer_vcc.py @@ -14,57 +14,76 @@ import numpy from gnuradio import gr, gr_unittest, blocks, fft, analog, digital import pmt + class qa_ofdm_serializer_vcc (gr_unittest.TestCase): - def setUp (self): - self.tb = gr.top_block () + def setUp(self): + self.tb = gr.top_block() self.tsb_key = "ts_last" - def tearDown (self): + def tearDown(self): self.tb = None - def test_001_simple (self): + def test_001_simple(self): """ Standard test """ fft_len = 16 - tx_symbols = (0, 1, 1j, 2, 3, 0, 0, 0, 0, 0, 0, 4, 5, 2j, 6, 0, - 0, 7, 8, 3j, 9, 0, 0, 0, 0, 0, 0, 10, 4j, 11, 12, 0, - 0, 13, 1j, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 2j, 0, 0) + tx_symbols = (0, 1, 1j, 2, 3, 0, 0, 0, 0, 0, 0, 4, 5, 2j, 6, 0, + 0, 7, 8, 3j, 9, 0, 0, 0, 0, 0, 0, 10, 4j, 11, 12, 0, + 0, 13, 1j, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 2j, 0, 0) expected_result = list(range(1, 16)) + [0, 0, 0] occupied_carriers = ((1, 3, 4, 11, 12, 14), (1, 2, 4, 11, 13, 14),) n_syms = len(tx_symbols) // fft_len src = blocks.vector_source_c(tx_symbols, False, fft_len) - serializer = digital.ofdm_serializer_vcc(fft_len, occupied_carriers, self.tsb_key, "", 0, "", False) + serializer = digital.ofdm_serializer_vcc( + fft_len, occupied_carriers, self.tsb_key, "", 0, "", False) sink = blocks.tsb_vector_sink_c(tsb_key=self.tsb_key) - self.tb.connect(src, blocks.stream_to_tagged_stream(gr.sizeof_gr_complex, fft_len, n_syms, self.tsb_key), serializer, sink) - self.tb.run () + self.tb.connect( + src, + blocks.stream_to_tagged_stream( + gr.sizeof_gr_complex, + fft_len, + n_syms, + self.tsb_key), + serializer, + sink) + self.tb.run() self.assertEqual(sink.data()[0], expected_result) - def test_001b_shifted (self): + def test_001b_shifted(self): """ Same as before, but shifted, because that's the normal mode in OFDM Rx """ fft_len = 16 tx_symbols = ( - 0, 0, 0, 0, 0, 0, 1, 2, 0, 3, 4, 5, 0, 0, 0, 0, - 0, 0, 0, 0, 6, 1j, 7, 8, 0, 9, 10, 1j, 11, 0, 0, 0, - 0, 0, 0, 0, 0, 12, 13, 14, 0, 15, 16, 17, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 2, 0, 3, 4, 5, 0, 0, 0, 0, + 0, 0, 0, 0, 6, 1j, 7, 8, 0, 9, 10, 1j, 11, 0, 0, 0, + 0, 0, 0, 0, 0, 12, 13, 14, 0, 15, 16, 17, 0, 0, 0, 0, ) expected_result = list(range(18)) occupied_carriers = ((13, 14, 15, 1, 2, 3), (-4, -2, -1, 1, 2, 4),) n_syms = len(tx_symbols) // fft_len src = blocks.vector_source_c(tx_symbols, False, fft_len) - serializer = digital.ofdm_serializer_vcc(fft_len, occupied_carriers, self.tsb_key) + serializer = digital.ofdm_serializer_vcc( + fft_len, occupied_carriers, self.tsb_key) sink = blocks.tsb_vector_sink_c(tsb_key=self.tsb_key) - self.tb.connect(src, blocks.stream_to_tagged_stream(gr.sizeof_gr_complex, fft_len, n_syms, self.tsb_key), serializer, sink) - self.tb.run () + self.tb.connect( + src, + blocks.stream_to_tagged_stream( + gr.sizeof_gr_complex, + fft_len, + n_syms, + self.tsb_key), + serializer, + sink) + self.tb.run() self.assertEqual(sink.data()[0], expected_result) - def test_002_with_offset (self): + def test_002_with_offset(self): """ Standard test, carrier offset """ fft_len = 16 - tx_symbols = list(range(1, 16)); - tx_symbols = (0, 0, 1, 1j, 2, 3, 0, 0, 0, 0, 0, 0, 4, 5, 2j, 6, - 0, 0, 7, 8, 3j, 9, 0, 0, 0, 0, 0, 0, 10, 4j, 11, 12, - 0, 0, 13, 1j, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 2j, 0) - carr_offset = 1 # Compare this with tx_symbols from the previous test + tx_symbols = list(range(1, 16)) + tx_symbols = (0, 0, 1, 1j, 2, 3, 0, 0, 0, 0, 0, 0, 4, 5, 2j, 6, + 0, 0, 7, 8, 3j, 9, 0, 0, 0, 0, 0, 0, 10, 4j, 11, 12, + 0, 0, 13, 1j, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 2j, 0) + carr_offset = 1 # Compare this with tx_symbols from the previous test expected_result = list(range(1, 16)) + [0, 0, 0] occupied_carriers = ((1, 3, 4, 11, 12, 14), (1, 2, 4, 11, 13, 14),) n_syms = len(tx_symbols) // fft_len @@ -75,51 +94,68 @@ class qa_ofdm_serializer_vcc (gr_unittest.TestCase): src = blocks.vector_source_c(tx_symbols, False, fft_len, (offsettag,)) sink = blocks.tsb_vector_sink_c(tsb_key=self.tsb_key) serializer = digital.ofdm_serializer_vcc( - fft_len, - occupied_carriers, - self.tsb_key, - "", 0, - "ofdm_sync_carr_offset", - False + fft_len, + occupied_carriers, + self.tsb_key, + "", 0, + "ofdm_sync_carr_offset", + False ) - self.tb.connect(src, blocks.stream_to_tagged_stream(gr.sizeof_gr_complex, fft_len, n_syms, self.tsb_key), serializer, sink) - self.tb.run () + self.tb.connect( + src, + blocks.stream_to_tagged_stream( + gr.sizeof_gr_complex, + fft_len, + n_syms, + self.tsb_key), + serializer, + sink) + self.tb.run() self.assertEqual(sink.data()[0], expected_result) self.assertEqual(len(sink.tags()), 1) - def test_003_connect (self): + def test_003_connect(self): """ Connect carrier_allocator to ofdm_serializer, make sure output==input """ fft_len = 8 n_syms = 1 occupied_carriers = ((1, 2, 6, 7),) - pilot_carriers = ((3,),(5,)) - pilot_symbols = ((1j,),(-1j,)) + pilot_carriers = ((3,), (5,)) + pilot_symbols = ((1j,), (-1j,)) #tx_data = tuple([numpy.random.randint(0, 10) for x in range(4 * n_syms)]) tx_data = [1, 2, 3, 4] src = blocks.vector_source_c(tx_data, False, 1) alloc = digital.ofdm_carrier_allocator_cvc( - fft_len, - occupied_carriers, - pilot_carriers, - pilot_symbols, - (), # No sync word - self.tsb_key, - True # Output is shifted (default) + fft_len, + occupied_carriers, + pilot_carriers, + pilot_symbols, + (), # No sync word + self.tsb_key, + True # Output is shifted (default) ) serializer = digital.ofdm_serializer_vcc( - alloc, - "", # Len tag key - 0, # Symbols skipped - "", # Carrier offset key - True # Input is shifted (default) + alloc, + "", # Len tag key + 0, # Symbols skipped + "", # Carrier offset key + True # Input is shifted (default) ) sink = blocks.tsb_vector_sink_c(tsb_key=self.tsb_key) - self.tb.connect(src, blocks.stream_to_tagged_stream(gr.sizeof_gr_complex, 1, len(tx_data), self.tsb_key), alloc, serializer, sink) - self.tb.run () + self.tb.connect( + src, + blocks.stream_to_tagged_stream( + gr.sizeof_gr_complex, + 1, + len(tx_data), + self.tsb_key), + alloc, + serializer, + sink) + self.tb.run() self.assertEqual(sink.data()[0], tx_data) - def test_004_connect (self): + def test_004_connect(self): """ Advanced test: - Allocator -> IFFT -> Frequency offset -> FFT -> Serializer @@ -130,10 +166,10 @@ class qa_ofdm_serializer_vcc (gr_unittest.TestCase): fft_len = 8 n_syms = 1 carr_offset = -2 - freq_offset = 1.0 / fft_len * carr_offset # Normalized frequency + freq_offset = 1.0 / fft_len * carr_offset # Normalized frequency occupied_carriers = ((-2, -1, 1, 2),) - pilot_carriers = ((-3,),(3,)) - pilot_symbols = ((1j,),(-1j,)) + pilot_carriers = ((-3,), (3,)) + pilot_symbols = ((1j,), (-1j,)) tx_data = [1, 2, 3, 4] offsettag = gr.tag_t() offsettag.offset = 0 @@ -141,40 +177,53 @@ class qa_ofdm_serializer_vcc (gr_unittest.TestCase): offsettag.value = pmt.from_long(carr_offset) src = blocks.vector_source_c(tx_data, False, 1, (offsettag,)) alloc = digital.ofdm_carrier_allocator_cvc(fft_len, - occupied_carriers, - pilot_carriers, - pilot_symbols, (), - self.tsb_key) - tx_ifft = fft.fft_vcc(fft_len, False, (1.0 / fft_len,)*fft_len, True) - oscillator = analog.sig_source_c(1.0, analog.GR_COS_WAVE, freq_offset, 1.0) + occupied_carriers, + pilot_carriers, + pilot_symbols, (), + self.tsb_key) + tx_ifft = fft.fft_vcc(fft_len, False, (1.0 / fft_len,) * fft_len, True) + oscillator = analog.sig_source_c( + 1.0, analog.GR_COS_WAVE, freq_offset, 1.0) mixer = blocks.multiply_cc() - rx_fft = fft.fft_vcc(fft_len, True, (), True) + rx_fft = fft.fft_vcc(fft_len, True, (), True) sink2 = blocks.tsb_vector_sink_c(vlen=fft_len, tsb_key=self.tsb_key) self.tb.connect(rx_fft, sink2) serializer = digital.ofdm_serializer_vcc( - alloc, "", 0, "ofdm_sync_carr_offset", True + alloc, "", 0, "ofdm_sync_carr_offset", True ) sink = blocks.tsb_vector_sink_c(tsb_key=self.tsb_key) self.tb.connect( - src, - blocks.stream_to_tagged_stream(gr.sizeof_gr_complex, 1, len(tx_data), self.tsb_key), - alloc, tx_ifft, - blocks.vector_to_stream(gr.sizeof_gr_complex, fft_len), - (mixer, 0), - blocks.stream_to_vector(gr.sizeof_gr_complex, fft_len), - rx_fft, serializer, sink - ) + src, + blocks.stream_to_tagged_stream( + gr.sizeof_gr_complex, + 1, + len(tx_data), + self.tsb_key), + alloc, + tx_ifft, + blocks.vector_to_stream( + gr.sizeof_gr_complex, + fft_len), + (mixer, + 0), + blocks.stream_to_vector( + gr.sizeof_gr_complex, + fft_len), + rx_fft, + serializer, + sink) self.tb.connect(oscillator, (mixer, 1)) - self.tb.run () - self.assertComplexTuplesAlmostEqual(sink.data()[0][-len(occupied_carriers[0]):], tx_data, places=4) + self.tb.run() + self.assertComplexTuplesAlmostEqual( + sink.data()[0][-len(occupied_carriers[0]):], tx_data, places=4) - def test_005_packet_len_tag (self): + def test_005_packet_len_tag(self): """ Standard test """ fft_len = 16 tx_symbols = list(range(1, 16)) - tx_symbols = (0, 1, 1j, 2, 3, 0, 0, 0, 0, 0, 0, 4, 5, 2j, 6, 0, - 0, 7, 8, 3j, 9, 0, 0, 0, 0, 0, 0, 10, 4j, 11, 12, 0, - 0, 13, 1j, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 2j, 0, 0) + tx_symbols = (0, 1, 1j, 2, 3, 0, 0, 0, 0, 0, 0, 4, 5, 2j, 6, 0, + 0, 7, 8, 3j, 9, 0, 0, 0, 0, 0, 0, 10, 4j, 11, 12, 0, + 0, 13, 1j, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 2j, 0, 0) expected_result = list(range(1, 16)) occupied_carriers = ((1, 3, 4, 11, 12, 14), (1, 2, 4, 11, 13, 14),) n_syms = len(tx_symbols) // fft_len @@ -184,21 +233,34 @@ class qa_ofdm_serializer_vcc (gr_unittest.TestCase): tag2.key = pmt.string_to_symbol("packet_len") tag2.value = pmt.from_long(len(expected_result)) src = blocks.vector_source_c(tx_symbols, False, fft_len, (tag2,)) - serializer = digital.ofdm_serializer_vcc(fft_len, occupied_carriers, self.tsb_key, packet_len_tsb_key , 0, "", False) + serializer = digital.ofdm_serializer_vcc( + fft_len, occupied_carriers, self.tsb_key, packet_len_tsb_key, 0, "", False) sink = blocks.tsb_vector_sink_c(tsb_key=packet_len_tsb_key) - self.tb.connect(src, blocks.stream_to_tagged_stream(gr.sizeof_gr_complex, fft_len, n_syms, self.tsb_key), serializer, sink) - self.tb.run () + self.tb.connect( + src, + blocks.stream_to_tagged_stream( + gr.sizeof_gr_complex, + fft_len, + n_syms, + self.tsb_key), + serializer, + sink) + self.tb.run() self.assertEqual(sink.data()[0], expected_result) - def test_099 (self): + def test_099(self): """ Make sure it fails if it should """ fft_len = 16 - occupied_carriers = ((1, 3, 4, 11, 12, 112),) # Something invalid + occupied_carriers = ((1, 3, 4, 11, 12, 112),) # Something invalid #self.assertRaises(TypeError, digital.ofdm_serializer_vcc, fft_len, occupied_carriers, self.tsb_key) - #pybind11 raises ValueError instead of TypeError - self.assertRaises(ValueError, digital.ofdm_serializer_vcc, fft_len, occupied_carriers, self.tsb_key) + # pybind11 raises ValueError instead of TypeError + self.assertRaises( + ValueError, + digital.ofdm_serializer_vcc, + fft_len, + occupied_carriers, + self.tsb_key) if __name__ == '__main__': gr_unittest.run(qa_ofdm_serializer_vcc) - diff --git a/gr-digital/python/digital/qa_ofdm_sync_sc_cfb.py b/gr-digital/python/digital/qa_ofdm_sync_sc_cfb.py index 5b84e89472..254479363e 100644 --- a/gr-digital/python/digital/qa_ofdm_sync_sc_cfb.py +++ b/gr-digital/python/digital/qa_ofdm_sync_sc_cfb.py @@ -17,24 +17,26 @@ from gnuradio import digital from gnuradio.digital.utils import tagged_streams from gnuradio.digital.ofdm_txrx import ofdm_tx + def make_bpsk_burst(fft_len, cp_len, num_bits): """ Create a burst of a sync symbol and some BPSK bits """ sync_symbol = [ - (random.randint(0, 1)*2)-1 + (random.randint(0, 1) * 2) - 1 for x in range(fft_len // 2) ] * 2 sync_symbols = sync_symbol[-cp_len:] + sync_symbol mod_symbols = [ - (random.randint(0, 1)*2)-1 + (random.randint(0, 1) * 2) - 1 for x in range(num_bits) ] return sync_symbols + mod_symbols + class qa_ofdm_sync_sc_cfb (gr_unittest.TestCase): def setUp(self): random.seed(0) - self.tb = gr.top_block () + self.tb = gr.top_block() def tearDown(self): self.tb = None @@ -47,22 +49,26 @@ class qa_ofdm_sync_sc_cfb (gr_unittest.TestCase): fft_len = 32 cp_len = 4 sig_len = (fft_len + cp_len) * 10 - tx_signal = [0,] * n_zeros + make_bpsk_burst(fft_len, cp_len, sig_len) + tx_signal = [0, ] * n_zeros + make_bpsk_burst(fft_len, cp_len, sig_len) tx_signal = tx_signal * 2 add = blocks.add_cc() sync = digital.ofdm_sync_sc_cfb(fft_len, cp_len) sink_freq = blocks.vector_sink_f() sink_detect = blocks.vector_sink_b() self.tb.connect(blocks.vector_source_c(tx_signal), (add, 0)) - self.tb.connect(analog.noise_source_c(analog.GR_GAUSSIAN, .01), (add, 1)) + self.tb.connect( + analog.noise_source_c( + analog.GR_GAUSSIAN, .01), (add, 1)) self.tb.connect(add, sync) self.tb.connect((sync, 0), sink_freq) self.tb.connect((sync, 1), sink_detect) self.tb.run() sig1_detect = sink_detect.data()[0:len(tx_signal) // 2] sig2_detect = sink_detect.data()[len(tx_signal) // 2:] - self.assertTrue(abs(sig1_detect.index(1) - (n_zeros + fft_len + cp_len)) < cp_len) - self.assertTrue(abs(sig2_detect.index(1) - (n_zeros + fft_len + cp_len)) < cp_len) + self.assertTrue(abs(sig1_detect.index( + 1) - (n_zeros + fft_len + cp_len)) < cp_len) + self.assertTrue(abs(sig2_detect.index( + 1) - (n_zeros + fft_len + cp_len)) < cp_len) self.assertEqual(numpy.sum(sig1_detect), 1) self.assertEqual(numpy.sum(sig2_detect), 1) @@ -71,7 +77,7 @@ class qa_ofdm_sync_sc_cfb (gr_unittest.TestCase): fft_len = 32 cp_len = 4 # This frequency offset is normalized to rads, i.e. \pi == f_s/2 - max_freq_offset = 2*numpy.pi/fft_len # Otherwise, it's coarse + max_freq_offset = 2 * numpy.pi / fft_len # Otherwise, it's coarse freq_offset = ((2 * random.random()) - 1) * max_freq_offset sig_len = (fft_len + cp_len) * 10 tx_signal = make_bpsk_burst(fft_len, cp_len, sig_len) @@ -98,18 +104,17 @@ class qa_ofdm_sync_sc_cfb (gr_unittest.TestCase): cp_len = 4 tx_signal = [] for _ in range(n_bursts): - gap = [0,] * random.randint(0, 2*fft_len) - tx_signal += \ - gap + \ + gap = [0, ] * random.randint(0, 2 * fft_len) + tx_signal += gap + \ make_bpsk_burst(fft_len, cp_len, fft_len * random.randint(5, 23)) # Very loose definition of SNR here - snr = 20 # dB - sigma = 10**(-snr/10) + snr = 20 # dB + sigma = 10**(-snr / 10) # Add noise -- we don't use the channel model blocks, we want to keep # this test as self-contained as possible, and all randomness should # derive from random.seed() above - complex_randn = \ - lambda N: (numpy.random.randn(N) + 1j * numpy.random.randn(N)) * sigma / numpy.sqrt(2) + def complex_randn(N): return (numpy.random.randn( + N) + 1j * numpy.random.randn(N)) * sigma / numpy.sqrt(2) tx_signal += complex_randn(len(tx_signal)) sync = digital.ofdm_sync_sc_cfb(fft_len, cp_len) sink_freq = blocks.vector_sink_f() @@ -134,7 +139,7 @@ class qa_ofdm_sync_sc_cfb (gr_unittest.TestCase): fft_len = 64 cp_len = 16 # Here, coarse freq offset is allowed - max_freq_offset = 2*numpy.pi/fft_len * 4 + max_freq_offset = 2 * numpy.pi / fft_len * 4 freq_offset = ((2 * random.random()) - 1) * max_freq_offset packets = [] tagname = "packet_length" @@ -142,17 +147,19 @@ class qa_ofdm_sync_sc_cfb (gr_unittest.TestCase): max_packet_length = 50 for _ in range(n_bursts): packet_length = random.randint(min_packet_length, - max_packet_length+1) + max_packet_length + 1) packet = [random.randint(0, 255) for i in range(packet_length)] packets.append(packet) - data, tags = tagged_streams.packets_to_vectors(packets, tagname, vlen=1) + data, tags = tagged_streams.packets_to_vectors( + packets, tagname, vlen=1) src = blocks.vector_source_b(data, False, 1, tags) mod = ofdm_tx(packet_length_tag_key=tagname) sync = digital.ofdm_sync_sc_cfb(fft_len, cp_len) sink_freq = blocks.vector_sink_f() sink_detect = blocks.vector_sink_b() noise_level = 0.005 - channel = channels.channel_model(noise_level, freq_offset / 2 / numpy.pi) + channel = channels.channel_model( + noise_level, freq_offset / 2 / numpy.pi) self.tb.connect(src, mod, channel, sync, sink_freq) self.tb.connect((sync, 1), sink_detect) self.tb.run() diff --git a/gr-digital/python/digital/qa_ofdm_txrx.py b/gr-digital/python/digital/qa_ofdm_txrx.py index a531080bc2..8bf107ebc0 100644 --- a/gr-digital/python/digital/qa_ofdm_txrx.py +++ b/gr-digital/python/digital/qa_ofdm_txrx.py @@ -1,12 +1,12 @@ #!/usr/bin/env python # # Copyright 2013 Free Software Foundation, Inc. -# +# # This file is part of GNU Radio -# +# # SPDX-License-Identifier: GPL-3.0-or-later # -# +# import random @@ -21,27 +21,46 @@ from gnuradio.digital.ofdm_txrx import ofdm_tx, ofdm_rx from gnuradio.digital.utils import tagged_streams # Set this to true if you need to write out data -LOG_DEBUG_INFO=False +LOG_DEBUG_INFO = False + class ofdm_tx_fg (gr.top_block): - def __init__(self, data, len_tag_key, scramble_bits=False, additional_tags=[]): + def __init__( + self, + data, + len_tag_key, + scramble_bits=False, + additional_tags=[]): gr.top_block.__init__(self, "ofdm_tx") tx_data, tags = tagged_streams.packets_to_vectors((data,), len_tag_key) src = blocks.vector_source_b(data, False, 1, tags + additional_tags) - self.tx = ofdm_tx(packet_length_tag_key=len_tag_key, debug_log=LOG_DEBUG_INFO, scramble_bits=scramble_bits) + self.tx = ofdm_tx( + packet_length_tag_key=len_tag_key, + debug_log=LOG_DEBUG_INFO, + scramble_bits=scramble_bits) self.sink = blocks.vector_sink_c() self.connect(src, self.tx, self.sink) def get_tx_samples(self): return self.sink.data() + class ofdm_rx_fg (gr.top_block): - def __init__(self, samples, len_tag_key, channel=None, prepend_zeros=100, scramble_bits=False): + def __init__( + self, + samples, + len_tag_key, + channel=None, + prepend_zeros=100, + scramble_bits=False): gr.top_block.__init__(self, "ofdm_rx") if prepend_zeros: samples = (0,) * prepend_zeros + tuple(samples) - src = blocks.vector_source_c(list(samples) + [0,] * 1000) - self.rx = ofdm_rx(frame_length_tag_key=len_tag_key, debug_log=LOG_DEBUG_INFO, scramble_bits=scramble_bits) + src = blocks.vector_source_c(list(samples) + [0, ] * 1000) + self.rx = ofdm_rx( + frame_length_tag_key=len_tag_key, + debug_log=LOG_DEBUG_INFO, + scramble_bits=scramble_bits) if channel is not None: self.connect(src, channel, self.rx) else: @@ -52,16 +71,17 @@ class ofdm_rx_fg (gr.top_block): def get_rx_bytes(self): return self.sink.data() + class test_ofdm_txrx (gr_unittest.TestCase): - def setUp (self): + def setUp(self): random.seed(0) - self.tb = gr.top_block () + self.tb = gr.top_block() - def tearDown (self): + def tearDown(self): self.tb = None - def test_001_tx (self): + def test_001_tx(self): """ Just make sure the Tx works in general """ # This tag gets put onto the first item of the transmit data, # it should be transmitted first, too @@ -73,14 +93,19 @@ class test_ofdm_txrx (gr_unittest.TestCase): n_bytes = 52 n_samples_expected = (numpy.ceil(1.0 * (n_bytes + 4) / 6) + 3) * 80 test_data = [random.randint(0, 255) for x in range(n_bytes)] - tx_fg = ofdm_tx_fg(test_data, len_tag_key, additional_tags=[timing_tag,]) + tx_fg = ofdm_tx_fg( + test_data, + len_tag_key, + additional_tags=[ + timing_tag, + ]) tx_fg.run() self.assertEqual(len(tx_fg.get_tx_samples()), n_samples_expected) tags_rx = [gr.tag_to_python(x) for x in tx_fg.sink.tags()] tags_rx = sorted([(x.offset, x.key, x.value) for x in tags_rx]) tags_expected = [ - (0, 'frame_len', n_samples_expected), - (0, 'tx_timing', 'now'), + (0, 'frame_len', n_samples_expected), + (0, 'tx_timing', 'now'), ] self.assertEqual(tags_rx, tags_expected) @@ -132,7 +157,12 @@ class test_ofdm_txrx (gr_unittest.TestCase): tx_fg.run() tx_samples = tx_fg.get_tx_samples() # Rx - rx_fg = ofdm_rx_fg(tx_samples, len_tag_key, channel, prepend_zeros=100, scramble_bits=True) + rx_fg = ofdm_rx_fg( + tx_samples, + len_tag_key, + channel, + prepend_zeros=100, + scramble_bits=True) rx_fg.run() rx_data = rx_fg.get_rx_bytes() self.assertEqual(list(tx_fg.tx.sync_word1), list(rx_fg.rx.sync_word1)) @@ -160,6 +190,6 @@ class test_ofdm_txrx (gr_unittest.TestCase): rx_data = rx_fg.get_rx_bytes() self.assertEqual(test_data, rx_data) + if __name__ == '__main__': gr_unittest.run(test_ofdm_txrx) - diff --git a/gr-digital/python/digital/qa_packet_format.py b/gr-digital/python/digital/qa_packet_format.py index fe2c82a798..0a6564ca8d 100644 --- a/gr-digital/python/digital/qa_packet_format.py +++ b/gr-digital/python/digital/qa_packet_format.py @@ -8,12 +8,14 @@ # # -import time, struct +import time +import struct import pmt from gnuradio import gr, gr_unittest, digital, blocks from gnuradio.digital import packet_utils + class test_packet_format_fb(gr_unittest.TestCase): def setUp(self): @@ -33,7 +35,6 @@ class test_packet_format_fb(gr_unittest.TestCase): self.tb.msg_connect(formatter, 'header', snk_hdr, 'store') self.tb.msg_connect(formatter, 'payload', snk_pld, 'store') - send_str = b"Hello World" send_pmt = pmt.make_u8vector(len(send_str), 0) for i in range(len(send_str)): @@ -58,7 +59,8 @@ class test_packet_format_fb(gr_unittest.TestCase): header = bytes(result_hdr) payload = bytes(result_pld) - access_code = packet_utils.conv_1_0_string_to_packed_binary_string(packet_utils.default_access_code)[0] + access_code = packet_utils.conv_1_0_string_to_packed_binary_string( + packet_utils.default_access_code)[0] rx_access_code = header[0:len(access_code)] length = len(send_str) @@ -69,7 +71,6 @@ class test_packet_format_fb(gr_unittest.TestCase): self.assertEqual(length, len(payload)) self.assertEqual(send_str, payload[0:length]) - def test_packet_parse_default(self): ac = packet_utils.default_access_code length = '0000000000000001' @@ -96,7 +97,9 @@ class test_packet_format_fb(gr_unittest.TestCase): self.tb.msg_connect(parser_4bps, 'info', snk_hdr_4bps, 'store') self.tb.start() - while (snk_hdr_1bps.num_messages() < 1) or (snk_hdr_4bps.num_messages() < 1): + while ( + snk_hdr_1bps.num_messages() < 1) or ( + snk_hdr_4bps.num_messages() < 1): time.sleep(0.1) self.tb.stop() self.tb.wait() @@ -114,7 +117,6 @@ class test_packet_format_fb(gr_unittest.TestCase): self.assertEqual(pmt.to_long(pmt.dict_ref( result_4bps, pmt.intern('payload symbols'), pmt.PMT_F)), 2) - def test_packet_format_async_counter(self): bps = 2 ac = packet_utils.default_access_code @@ -127,8 +129,7 @@ class test_packet_format_fb(gr_unittest.TestCase): self.tb.msg_connect(formatter, 'header', snk_hdr, 'store') self.tb.msg_connect(formatter, 'payload', snk_pld, 'store') - - send_str = b"Hello World" + 1000*b"xxx" + send_str = b"Hello World" + 1000 * b"xxx" send_pmt = pmt.make_u8vector(len(send_str), 0) for i in range(len(send_str)): pmt.u8vector_set(send_pmt, i, send_str[i]) @@ -151,13 +152,14 @@ class test_packet_format_fb(gr_unittest.TestCase): header = bytes(result_hdr) payload = bytes(result_pld) - access_code = packet_utils.conv_1_0_string_to_packed_binary_string(packet_utils.default_access_code)[0] + access_code = packet_utils.conv_1_0_string_to_packed_binary_string( + packet_utils.default_access_code)[0] rx_access_code = header[0:len(access_code)] length = len(send_str) rx_length = struct.unpack_from(b"!H", header, len(access_code))[0] - rx_bps = struct.unpack_from(b"!H", header, len(access_code)+4)[0] - rx_counter = struct.unpack_from(b"!H", header, len(access_code)+6)[0] + rx_bps = struct.unpack_from(b"!H", header, len(access_code) + 4)[0] + rx_counter = struct.unpack_from(b"!H", header, len(access_code) + 6)[0] self.assertEqual(access_code, rx_access_code) self.assertEqual(length, rx_length) @@ -166,5 +168,6 @@ class test_packet_format_fb(gr_unittest.TestCase): self.assertEqual(length, len(payload)) self.assertEqual(send_str, payload[0:length]) + if __name__ == '__main__': gr_unittest.run(test_packet_format_fb) diff --git a/gr-digital/python/digital/qa_packet_headergenerator_bb.py b/gr-digital/python/digital/qa_packet_headergenerator_bb.py index 59b565cf0a..994ae3cafb 100644 --- a/gr-digital/python/digital/qa_packet_headergenerator_bb.py +++ b/gr-digital/python/digital/qa_packet_headergenerator_bb.py @@ -1,9 +1,9 @@ #!/usr/bin/env python # -#Copyright 2012-2014 Free Software Foundation, Inc. -# +# Copyright 2012-2014 Free Software Foundation, Inc. +# # This file is part of GNU Radio -# +# # SPDX-License-Identifier: GPL-3.0-or-later # @@ -12,37 +12,39 @@ from gnuradio import gr, gr_unittest, digital, blocks from gnuradio.gr import packet_utils import pmt + class qa_packet_headergenerator_bb (gr_unittest.TestCase): - def setUp (self): - self.tb = gr.top_block () + def setUp(self): + self.tb = gr.top_block() self.tsb_key = "tsb_key" - def tearDown (self): + def tearDown(self): self.tb = None def setup_data_tags(self, data): return packet_utils.packets_to_vectors( - data, - self.tsb_key + data, + self.tsb_key ) - def test_001_12bits (self): + def test_001_12bits(self): # 3 packets: | | | - data, tags = self.setup_data_tags(((1, 2, 3, 4), (1, 2), tuple(range(25)))) + data, tags = self.setup_data_tags( + ((1, 2, 3, 4), (1, 2), tuple(range(25)))) src = blocks.vector_source_b(data, tags=tags) header = digital.packet_headergenerator_bb(12, self.tsb_key) sink = blocks.vector_sink_b() self.tb.connect(src, header, sink) self.tb.run() expected_data = [ - 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0 ] self.assertEqual(sink.data(), expected_data) - def test_002_32bits (self): + def test_002_32bits(self): # 3 packets: | | | | data, tags = self.setup_data_tags(((1, 2, 3, 4), (1, 2), (1, 2, 3, 4))) src = blocks.vector_source_b(data, tags=tags) @@ -52,18 +54,19 @@ class qa_packet_headergenerator_bb (gr_unittest.TestCase): self.tb.run() expected_data = [ # | Number of symbols | Packet number | CRC - 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, - 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, - 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1 + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1 ] self.assertEqual(sink.data(), expected_data) - def test_003_12bits_formatter_object (self): + def test_003_12bits_formatter_object(self): # 3 packets: | | | | data, tags = self.setup_data_tags(((1, 2, 3, 4), (1, 2), (1, 2, 3, 4))) src = blocks.vector_source_b(data, tags=tags) formatter_object = digital.packet_header_default(12, self.tsb_key) - header = digital.packet_headergenerator_bb(formatter_object.formatter(), self.tsb_key) + header = digital.packet_headergenerator_bb( + formatter_object.formatter(), self.tsb_key) sink = blocks.vector_sink_b() self.tb.connect(src, header, sink) self.tb.run() @@ -74,15 +77,20 @@ class qa_packet_headergenerator_bb (gr_unittest.TestCase): ] self.assertEqual(sink.data(), expected_data) - def test_004_8bits_formatter_ofdm (self): + def test_004_8bits_formatter_ofdm(self): occupied_carriers = ((1, 2, 3, 5, 6, 7),) # 3 packets: | | | | data, tags = self.setup_data_tags(((1, 2, 3, 4), (1, 2), (1, 2, 3, 4))) src = blocks.vector_source_b(data, tags=tags) - formatter_object = digital.packet_header_ofdm(occupied_carriers, 1, self.tsb_key) + formatter_object = digital.packet_header_ofdm( + occupied_carriers, 1, self.tsb_key) self.assertEqual(formatter_object.header_len(), 6) - self.assertEqual(pmt.symbol_to_string(formatter_object.len_tag_key()), self.tsb_key) - header = digital.packet_headergenerator_bb(formatter_object.formatter(), self.tsb_key) + self.assertEqual( + pmt.symbol_to_string( + formatter_object.len_tag_key()), + self.tsb_key) + header = digital.packet_headergenerator_bb( + formatter_object.formatter(), self.tsb_key) sink = blocks.vector_sink_b() self.tb.connect(src, header, sink) self.tb.run() @@ -93,6 +101,6 @@ class qa_packet_headergenerator_bb (gr_unittest.TestCase): ] self.assertEqual(sink.data(), expected_data) + if __name__ == '__main__': gr_unittest.run(qa_packet_headergenerator_bb) - diff --git a/gr-digital/python/digital/qa_packet_headerparser_b.py b/gr-digital/python/digital/qa_packet_headerparser_b.py index 13840c7cad..897220a59d 100644 --- a/gr-digital/python/digital/qa_packet_headerparser_b.py +++ b/gr-digital/python/digital/qa_packet_headerparser_b.py @@ -1,11 +1,11 @@ #!/usr/bin/env python # Copyright 2012 Free Software Foundation, Inc. -# +# # This file is part of GNU Radio -# +# # SPDX-License-Identifier: GPL-3.0-or-later # -# +# import time @@ -15,16 +15,17 @@ from gnuradio import gr, gr_unittest, blocks, digital from gnuradio.digital.utils import tagged_streams import pmt + class qa_packet_headerparser_b (gr_unittest.TestCase): - def setUp (self): + def setUp(self): random.seed(0) - self.tb = gr.top_block () + self.tb = gr.top_block() - def tearDown (self): + def tearDown(self): self.tb = None - def test_001_t (self): + def test_001_t(self): """ First header: Packet length 4, packet num 0 Second header: Packet 2, packet num 1 @@ -32,9 +33,9 @@ class qa_packet_headerparser_b (gr_unittest.TestCase): """ encoded_headers = ( # | Number of bytes | Packet number | CRC - 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, - 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, - 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 ) packet_len_tagname = "packet_len" random_tag = gr.tag_t() @@ -67,10 +68,13 @@ class qa_packet_headerparser_b (gr_unittest.TestCase): header_len = 32 packet_len_tagname = "packet_len" packet_lengths = [random.randint(1, 100) for x in range(N)] - data, tags = tagged_streams.packets_to_vectors([list(range(packet_lengths[i])) for i in range(N)], packet_len_tagname) + data, tags = tagged_streams.packets_to_vectors( + [list(range(packet_lengths[i])) for i in range(N)], packet_len_tagname) src = blocks.vector_source_b(data, False, 1, tags) - header_gen = digital.packet_headergenerator_bb(header_len, packet_len_tagname) - header_parser = digital.packet_headerparser_b(header_len, packet_len_tagname) + header_gen = digital.packet_headergenerator_bb( + header_len, packet_len_tagname) + header_parser = digital.packet_headerparser_b( + header_len, packet_len_tagname) sink = blocks.message_debug() self.tb.connect(src, header_gen, header_parser) self.tb.msg_connect(header_parser, "header_data", sink, "store") @@ -81,9 +85,11 @@ class qa_packet_headerparser_b (gr_unittest.TestCase): self.assertEqual(sink.num_messages(), N) for i in range(N): msg = pmt.to_python(sink.get_message(i)) - self.assertEqual(msg, {'packet_len': packet_lengths[i], 'packet_num': i}) + self.assertEqual( + msg, { + 'packet_len': packet_lengths[i], 'packet_num': i}) - def test_003_ofdm (self): + def test_003_ofdm(self): """ Header 1: 193 bytes Header 2: 8 bytes 2 bits per complex symbol, 32 carriers => 64 bits = 8 bytes per OFDM symbol @@ -93,20 +99,21 @@ class qa_packet_headerparser_b (gr_unittest.TestCase): """ encoded_headers = ( # | Number of bytes | Packet number | CRC - 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, + 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, ) packet_len_tagname = "packet_len" frame_len_tagname = "frame_len" src = blocks.vector_source_b(encoded_headers) header_formatter = digital.packet_header_ofdm( - (list(range(32)),list(range(4)),list(range(8))), # 32/4/8 carriers are occupied (which doesn't matter here) - 1, # 1 OFDM symbol per header (= 32 bits) - packet_len_tagname, - frame_len_tagname, - "packet_num", - 1, # 1 bit per header symbols (BPSK) - 2 # 2 bits per payload symbol (QPSK) + # 32/4/8 carriers are occupied (which doesn't matter here) + (list(range(32)), list(range(4)), list(range(8))), + 1, # 1 OFDM symbol per header (= 32 bits) + packet_len_tagname, + frame_len_tagname, + "packet_num", + 1, # 1 bit per header symbols (BPSK) + 2 # 2 bits per payload symbol (QPSK) ) parser = digital.packet_headerparser_b(header_formatter.base()) sink = blocks.message_debug() @@ -120,8 +127,11 @@ class qa_packet_headerparser_b (gr_unittest.TestCase): msg1 = pmt.to_python(sink.get_message(0)) msg2 = pmt.to_python(sink.get_message(1)) # Multiply with 4 because unpacked bytes have only two bits - self.assertEqual(msg1, {'packet_len': 193*4, 'frame_len': 52, 'packet_num': 0}) - self.assertEqual(msg2, {'packet_len': 8*4, 'frame_len': 1, 'packet_num': 1}) + self.assertEqual(msg1, {'packet_len': 193 * 4, + 'frame_len': 52, 'packet_num': 0}) + self.assertEqual( + msg2, { + 'packet_len': 8 * 4, 'frame_len': 1, 'packet_num': 1}) def test_004_ofdm_scramble(self): """ @@ -131,17 +141,19 @@ class qa_packet_headerparser_b (gr_unittest.TestCase): packet_length = 23 packet_len_tagname = "packet_len" frame_len_tagname = "frame_len" - data, tags = tagged_streams.packets_to_vectors([list(range(packet_length)),list(range(packet_length)),], packet_len_tagname) + data, tags = tagged_streams.packets_to_vectors( + [list(range(packet_length)), list(range(packet_length)), ], packet_len_tagname) src = blocks.vector_source_b(data, False, 1, tags) header_formatter = digital.packet_header_ofdm( - (list(range(32)),), # 32 carriers are occupied (which doesn't matter here) - 1, # 1 OFDM symbol per header (= 32 bits) - packet_len_tagname, - frame_len_tagname, - "packet_num", - 1, # 1 bit per header symbols (BPSK) - 2, # 2 bits per payload symbol (QPSK) - scramble_header=True + # 32 carriers are occupied (which doesn't matter here) + (list(range(32)),), + 1, # 1 OFDM symbol per header (= 32 bits) + packet_len_tagname, + frame_len_tagname, + "packet_num", + 1, # 1 bit per header symbols (BPSK) + 2, # 2 bits per payload symbol (QPSK) + scramble_header=True ) header_gen = digital.packet_headergenerator_bb(header_formatter.base()) header_parser = digital.packet_headerparser_b(header_formatter.base()) @@ -153,11 +165,14 @@ class qa_packet_headerparser_b (gr_unittest.TestCase): self.tb.stop() self.tb.wait() msg = pmt.to_python(sink.get_message(0)) - self.assertEqual(msg, {'packet_len': packet_length, 'packet_num': 0, 'frame_len': 4}) + self.assertEqual( + msg, { + 'packet_len': packet_length, 'packet_num': 0, 'frame_len': 4}) msg = pmt.to_python(sink.get_message(1)) - self.assertEqual(msg, {'packet_len': packet_length, 'packet_num': 1, 'frame_len': 4}) + self.assertEqual( + msg, { + 'packet_len': packet_length, 'packet_num': 1, 'frame_len': 4}) + if __name__ == '__main__': gr_unittest.run(qa_packet_headerparser_b) - - diff --git a/gr-digital/python/digital/qa_pfb_clock_sync.py b/gr-digital/python/digital/qa_pfb_clock_sync.py index f9dfd6d66d..6be41324bc 100644 --- a/gr-digital/python/digital/qa_pfb_clock_sync.py +++ b/gr-digital/python/digital/qa_pfb_clock_sync.py @@ -15,6 +15,7 @@ import time from gnuradio import gr, gr_unittest, filter, digital, blocks + class test_pfb_clock_sync(gr_unittest.TestCase): def setUp(self): @@ -35,8 +36,8 @@ class test_pfb_clock_sync(gr_unittest.TestCase): max_rate_deviation = 0.5 osps = 1 - ntaps = 11 * int(sps*nfilts) - taps = filter.firdes.root_raised_cosine(nfilts, nfilts*sps, + ntaps = 11 * int(sps * nfilts) + taps = filter.firdes.root_raised_cosine(nfilts, nfilts * sps, 1.0, excess_bw, ntaps) self.test = digital.pfb_clock_sync_ccf(sps, loop_bw, taps, @@ -44,7 +45,7 @@ class test_pfb_clock_sync(gr_unittest.TestCase): max_rate_deviation, osps) - data = 10000*[complex(1,0), complex(-1,0)] + data = 10000 * [complex(1, 0), complex(-1, 0)] self.src = blocks.vector_source_c(data, False) # pulse shaping interpolation filter @@ -61,7 +62,7 @@ class test_pfb_clock_sync(gr_unittest.TestCase): self.tb.connect(self.src, self.rrc_filter, self.test, self.snk) self.tb.run() - expected_result = 10000*[complex(1,0), complex(-1,0)] + expected_result = 10000 * [complex(1, 0), complex(-1, 0)] dst_data = self.snk.data() # Only compare last Ncmp samples @@ -71,12 +72,11 @@ class test_pfb_clock_sync(gr_unittest.TestCase): expected_result = expected_result[len_e - Ncmp:] dst_data = dst_data[len_d - Ncmp:] - #for e,d in zip(expected_result, dst_data): + # for e,d in zip(expected_result, dst_data): # print e, d self.assertComplexTuplesAlmostEqual(expected_result, dst_data, 1) - def test02(self): # Test real BPSK sync excess_bw = 0.35 @@ -88,8 +88,8 @@ class test_pfb_clock_sync(gr_unittest.TestCase): max_rate_deviation = 0.5 osps = 1 - ntaps = 11 * int(sps*nfilts) - taps = filter.firdes.root_raised_cosine(nfilts, nfilts*sps, + ntaps = 11 * int(sps * nfilts) + taps = filter.firdes.root_raised_cosine(nfilts, nfilts * sps, 1.0, excess_bw, ntaps) self.test = digital.pfb_clock_sync_fff(sps, loop_bw, taps, @@ -97,7 +97,7 @@ class test_pfb_clock_sync(gr_unittest.TestCase): max_rate_deviation, osps) - data = 10000*[1, -1] + data = 10000 * [1, -1] self.src = blocks.vector_source_f(data, False) # pulse shaping interpolation filter @@ -114,7 +114,7 @@ class test_pfb_clock_sync(gr_unittest.TestCase): self.tb.connect(self.src, self.rrc_filter, self.test, self.snk) self.tb.run() - expected_result = 10000*[1, -1] + expected_result = 10000 * [1, -1] dst_data = self.snk.data() # Only compare last Ncmp samples @@ -124,12 +124,11 @@ class test_pfb_clock_sync(gr_unittest.TestCase): expected_result = expected_result[len_e - Ncmp:] dst_data = dst_data[len_d - Ncmp:] - #for e,d in zip(expected_result, dst_data): + # for e,d in zip(expected_result, dst_data): # print e, d self.assertFloatTuplesAlmostEqual(expected_result, dst_data, 1) - def test03(self): # Test resting of taps excess_bw0 = 0.35 @@ -142,8 +141,8 @@ class test_pfb_clock_sync(gr_unittest.TestCase): max_rate_deviation = 0.5 osps = 1 - ntaps = 11 * int(sps*nfilts) - taps = filter.firdes.root_raised_cosine(nfilts, nfilts*sps, + ntaps = 11 * int(sps * nfilts) + taps = filter.firdes.root_raised_cosine(nfilts, nfilts * sps, 1.0, excess_bw0, ntaps) self.test = digital.pfb_clock_sync_ccf(sps, loop_bw, taps, @@ -158,7 +157,7 @@ class test_pfb_clock_sync(gr_unittest.TestCase): self.tb.start() time.sleep(0.1) - taps = filter.firdes.root_raised_cosine(nfilts, nfilts*sps, + taps = filter.firdes.root_raised_cosine(nfilts, nfilts * sps, 1.0, excess_bw1, ntaps) self.test.update_taps(taps) @@ -180,8 +179,8 @@ class test_pfb_clock_sync(gr_unittest.TestCase): max_rate_deviation = 0.5 osps = 1 - ntaps = 11 * int(sps*nfilts) - taps = filter.firdes.root_raised_cosine(nfilts, nfilts*sps, + ntaps = 11 * int(sps * nfilts) + taps = filter.firdes.root_raised_cosine(nfilts, nfilts * sps, 1.0, excess_bw0, ntaps) self.test = digital.pfb_clock_sync_fff(sps, loop_bw, taps, @@ -196,7 +195,7 @@ class test_pfb_clock_sync(gr_unittest.TestCase): self.tb.start() time.sleep(0.1) - taps = filter.firdes.root_raised_cosine(nfilts, nfilts*sps, + taps = filter.firdes.root_raised_cosine(nfilts, nfilts * sps, 1.0, excess_bw1, ntaps) self.test.update_taps(taps) diff --git a/gr-digital/python/digital/qa_pn_correlator_cc.py b/gr-digital/python/digital/qa_pn_correlator_cc.py index c82229bd95..3f81295bdf 100644 --- a/gr-digital/python/digital/qa_pn_correlator_cc.py +++ b/gr-digital/python/digital/qa_pn_correlator_cc.py @@ -11,6 +11,7 @@ from gnuradio import gr, gr_unittest, digital, blocks + class test_pn_correlator_cc(gr_unittest.TestCase): def setUp(self): @@ -24,16 +25,17 @@ class test_pn_correlator_cc(gr_unittest.TestCase): def test_001_correlate(self): degree = 10 - length = 2**degree-1 + length = 2**degree - 1 src = digital.glfsr_source_f(degree) - head = blocks.head(gr.sizeof_float, length*length) + head = blocks.head(gr.sizeof_float, length * length) f2c = blocks.float_to_complex() corr = digital.pn_correlator_cc(degree) dst = blocks.vector_sink_c() self.tb.connect(src, head, f2c, corr, dst) self.tb.run() data = dst.data() - self.assertEqual(data[-1], (1.0+0j)) + self.assertEqual(data[-1], (1.0 + 0j)) + if __name__ == '__main__': gr_unittest.run(test_pn_correlator_cc) diff --git a/gr-digital/python/digital/qa_probe_density.py b/gr-digital/python/digital/qa_probe_density.py index 30e24e9522..c2249c1b51 100644 --- a/gr-digital/python/digital/qa_probe_density.py +++ b/gr-digital/python/digital/qa_probe_density.py @@ -1,16 +1,17 @@ #!/usr/bin/env python # # Copyright 2012,2013 Free Software Foundation, Inc. -# +# # This file is part of GNU Radio -# +# # SPDX-License-Identifier: GPL-3.0-or-later # -# +# from gnuradio import gr, gr_unittest, digital, blocks + class test_probe_density(gr_unittest.TestCase): def setUp(self): @@ -30,7 +31,6 @@ class test_probe_density(gr_unittest.TestCase): result_data = op.density() self.assertEqual(expected_data, result_data) - def test_002(self): src_data = [1, 1, 1, 1] expected_data = 1 @@ -54,6 +54,6 @@ class test_probe_density(gr_unittest.TestCase): print(result_data) self.assertAlmostEqual(expected_data, result_data, 5) + if __name__ == '__main__': gr_unittest.run(test_probe_density) - diff --git a/gr-digital/python/digital/qa_scrambler.py b/gr-digital/python/digital/qa_scrambler.py index c6e357bbef..6f6c35134a 100644 --- a/gr-digital/python/digital/qa_scrambler.py +++ b/gr-digital/python/digital/qa_scrambler.py @@ -13,16 +13,19 @@ from gnuradio import gr, gr_unittest, digital, blocks import pmt # See gr-digital/lib/additive_scrambler_bb_impl.cc for reference. + + def additive_scramble_lfsr(mask, seed, reglen, bpb, data): l = digital.lfsr(mask, seed, reglen) out = [] for d in data: scramble_word = 0 - for i in range(0,bpb): + for i in range(0, bpb): scramble_word ^= l.next_bit() << i out.append(d ^ scramble_word) return out + class test_scrambler(gr_unittest.TestCase): def setUp(self): @@ -32,17 +35,19 @@ class test_scrambler(gr_unittest.TestCase): self.tb = None def test_scrambler_descrambler(self): - src_data = [1,]*1000 + src_data = [1, ] * 1000 src = blocks.vector_source_b(src_data, False) - scrambler = digital.scrambler_bb(0x8a, 0x7F, 7) # CCSDS 7-bit scrambler + scrambler = digital.scrambler_bb( + 0x8a, 0x7F, 7) # CCSDS 7-bit scrambler descrambler = digital.descrambler_bb(0x8a, 0x7F, 7) dst = blocks.vector_sink_b() self.tb.connect(src, scrambler, descrambler, dst) self.tb.run() - self.assertEqual(src_data[:-8], dst.data()[8:]) # skip garbage during synchronization + # skip garbage during synchronization + self.assertEqual(src_data[:-8], dst.data()[8:]) def test_additive_scrambler(self): - src_data = [1,]*1000 + src_data = [1, ] * 1000 src = blocks.vector_source_b(src_data, False) scrambler = digital.additive_scrambler_bb(0x8a, 0x7f, 7) descrambler = digital.additive_scrambler_bb(0x8a, 0x7f, 7) @@ -52,7 +57,7 @@ class test_scrambler(gr_unittest.TestCase): self.assertEqual(src_data, dst.data()) def test_additive_scrambler_reset(self): - src_data = [1,]*200 + src_data = [1, ] * 200 src = blocks.vector_source_b(src_data, False) scrambler = digital.additive_scrambler_bb(0x8a, 0x7f, 7, 50) dst = blocks.vector_sink_b() @@ -62,7 +67,7 @@ class test_scrambler(gr_unittest.TestCase): self.assertEqual(output[:50] * 4, output) def test_additive_scrambler_reset_3bpb(self): - src_data = [5,]*200 + src_data = [5, ] * 200 src = blocks.vector_source_b(src_data, False) scrambler = digital.additive_scrambler_bb(0x8a, 0x7f, 7, 50, 3) dst = blocks.vector_sink_b() @@ -72,7 +77,7 @@ class test_scrambler(gr_unittest.TestCase): self.assertEqual(output[:50] * 4, output) def test_additive_scrambler_tags(self): - src_data = [1,]*1000 + src_data = [1, ] * 1000 src = blocks.vector_source_b(src_data, False) scrambler = digital.additive_scrambler_bb(0x8a, 0x7f, 7, 100) descrambler = digital.additive_scrambler_bb(0x8a, 0x7f, 7, 100) @@ -86,9 +91,12 @@ class test_scrambler(gr_unittest.TestCase): reset_tag3 = gr.tag_t() reset_tag3.key = pmt.string_to_symbol(reset_tag_key) reset_tag3.offset = 523 - src = blocks.vector_source_b(src_data, False, 1, (reset_tag1, reset_tag2, reset_tag3)) - scrambler = digital.additive_scrambler_bb(0x8a, 0x7f, 7, 100, 1, reset_tag_key) - descrambler = digital.additive_scrambler_bb(0x8a, 0x7f, 7, 100, 1, reset_tag_key) + src = blocks.vector_source_b( + src_data, False, 1, (reset_tag1, reset_tag2, reset_tag3)) + scrambler = digital.additive_scrambler_bb( + 0x8a, 0x7f, 7, 100, 1, reset_tag_key) + descrambler = digital.additive_scrambler_bb( + 0x8a, 0x7f, 7, 100, 1, reset_tag_key) dst = blocks.vector_sink_b() self.tb.connect(src, scrambler, descrambler, dst) self.tb.run() @@ -106,13 +114,16 @@ class test_scrambler(gr_unittest.TestCase): reset_tag3 = gr.tag_t() reset_tag3.key = pmt.string_to_symbol(reset_tag_key) reset_tag3.offset = 20 - src = blocks.vector_source_b(src_data * 3, False, 1, (reset_tag1, reset_tag2, reset_tag3)) - scrambler = digital.additive_scrambler_bb(0x8a, 0x7f, 7, 0, 8, reset_tag_key) + src = blocks.vector_source_b( + src_data * 3, False, 1, (reset_tag1, reset_tag2, reset_tag3)) + scrambler = digital.additive_scrambler_bb( + 0x8a, 0x7f, 7, 0, 8, reset_tag_key) dst = blocks.vector_sink_b() self.tb.connect(src, scrambler, dst) self.tb.run() expected_data = additive_scramble_lfsr(0x8a, 0x7f, 7, 8, src_data) self.assertEqual(expected_data * 3, dst.data()) + if __name__ == '__main__': gr_unittest.run(test_scrambler) diff --git a/gr-digital/python/digital/qa_simple_correlator.py b/gr-digital/python/digital/qa_simple_correlator.py index 1f5bf5bd72..9b7690c883 100644 --- a/gr-digital/python/digital/qa_simple_correlator.py +++ b/gr-digital/python/digital/qa_simple_correlator.py @@ -11,6 +11,7 @@ from gnuradio import gr, gr_unittest, blocks, filter, digital + class test_simple_correlator(gr_unittest.TestCase): def setUp(self): @@ -30,7 +31,7 @@ class test_simple_correlator(gr_unittest.TestCase): # Filter taps to expand the data to oversample by 8 # Just using a RRC for some basic filter shape taps = filter.firdes.root_raised_cosine(8, 8, 1.0, 0.5, 21) - + src = blocks.vector_source_b(expected_result) frame = digital.simple_framer(4) unpack = blocks.packed_to_unpacked_bb(1, gr.GR_MSB_FIRST) @@ -47,5 +48,6 @@ class test_simple_correlator(gr_unittest.TestCase): self.assertEqual(expected_result, result_data) + if __name__ == '__main__': gr_unittest.run(test_simple_correlator) diff --git a/gr-digital/python/digital/qa_simple_framer.py b/gr-digital/python/digital/qa_simple_framer.py index 5c8c65ee86..7acfc82977 100644 --- a/gr-digital/python/digital/qa_simple_framer.py +++ b/gr-digital/python/digital/qa_simple_framer.py @@ -11,6 +11,7 @@ from gnuradio import gr, gr_unittest, digital, blocks + class test_simple_framer(gr_unittest.TestCase): def setUp(self): @@ -26,11 +27,62 @@ class test_simple_framer(gr_unittest.TestCase): 0xcc, 0xdd, 0xee, 0xff) expected_result = [ - 0xac, 0xdd, 0xa4, 0xe2, 0xf2, 0x8c, 0x20, 0xfc, 0x00, 0x00, 0x11, 0x22, 0x33, 0x55, - 0xac, 0xdd, 0xa4, 0xe2, 0xf2, 0x8c, 0x20, 0xfc, 0x01, 0x44, 0x55, 0x66, 0x77, 0x55, - 0xac, 0xdd, 0xa4, 0xe2, 0xf2, 0x8c, 0x20, 0xfc, 0x02, 0x88, 0x99, 0xaa, 0xbb, 0x55, - 0xac, 0xdd, 0xa4, 0xe2, 0xf2, 0x8c, 0x20, 0xfc, 0x03, 0xcc, 0xdd, 0xee, 0xff, 0x55 - ] + 0xac, + 0xdd, + 0xa4, + 0xe2, + 0xf2, + 0x8c, + 0x20, + 0xfc, + 0x00, + 0x00, + 0x11, + 0x22, + 0x33, + 0x55, + 0xac, + 0xdd, + 0xa4, + 0xe2, + 0xf2, + 0x8c, + 0x20, + 0xfc, + 0x01, + 0x44, + 0x55, + 0x66, + 0x77, + 0x55, + 0xac, + 0xdd, + 0xa4, + 0xe2, + 0xf2, + 0x8c, + 0x20, + 0xfc, + 0x02, + 0x88, + 0x99, + 0xaa, + 0xbb, + 0x55, + 0xac, + 0xdd, + 0xa4, + 0xe2, + 0xf2, + 0x8c, + 0x20, + 0xfc, + 0x03, + 0xcc, + 0xdd, + 0xee, + 0xff, + 0x55] src = blocks.vector_source_b(src_data) op = digital.simple_framer(4) @@ -41,6 +93,6 @@ class test_simple_framer(gr_unittest.TestCase): result_data = dst.data() self.assertEqual(expected_result, result_data) + if __name__ == '__main__': gr_unittest.run(test_simple_framer) - diff --git a/gr-digital/python/digital/qam.py b/gr-digital/python/digital/qam.py index 29e88ee236..d74866b946 100644 --- a/gr-digital/python/digital/qam.py +++ b/gr-digital/python/digital/qam.py @@ -29,13 +29,16 @@ _def_differential = True # coding is used within but not between each quadrant. _def_mod_code = mod_codes.NO_CODE + def is_power_of_four(x): v = log(x) / log(4) return int(v) == v + def get_bit(x, n): """ Get the n'th bit of integer x (from little end).""" - return (x&(0x01 << n)) >> n + return (x & (0x01 << n)) >> n + def get_bits(x, n, k): """ Get the k bits of integer x starting at bit n(from little end).""" @@ -44,6 +47,7 @@ def get_bits(x, n, k): # Remove all bits bigger than n+k-1 return v % pow(2, k) + def make_differential_constellation(m, gray_coded): """ Create a constellation with m possible symbols where m must be @@ -71,9 +75,9 @@ def make_differential_constellation(m, gray_coded): else: i_gcs = dict([(i, i) for i in range(0, side)]) # The distance between points is found. - step = 1 / (side-0.5) + step = 1 / (side - 0.5) - gc_to_x = [(i_gcs[gc]+0.5)*step for gc in range(0, side)] + gc_to_x = [(i_gcs[gc] + 0.5) * step for gc in range(0, side)] # Takes the (x, y) location of the point with the quadrant along # with the quadrant number. (x, y) are integers referring to which @@ -93,16 +97,18 @@ def make_differential_constellation(m, gray_coded): # First two bits determine quadrant. # Next (k-2)/2 bits determine x position. # Following (k-2)/2 bits determine y position. - # How x and y relate to real and imag depends on quadrant (see get_c function). + # How x and y relate to real and imag depends on quadrant (see get_c + # function). const_map = [] for i in range(m): - y = get_bits(i, 0, (k-2) // 2) - x = get_bits(i, (k-2) // 2, (k-2) // 2) - quad = get_bits(i, k-2, 2) + y = get_bits(i, 0, (k - 2) // 2) + x = get_bits(i, (k - 2) // 2, (k - 2) // 2) + quad = get_bits(i, k - 2, 2) const_map.append(get_c(x, y, quad)) return const_map + def make_non_differential_constellation(m, gray_coded): side = int(pow(m, 0.5)) if (not isinstance(m, int) or m < 4 or not is_power_of_four(m)): @@ -117,22 +123,23 @@ def make_non_differential_constellation(m, gray_coded): else: i_gcs = list(range(0, side)) # The distance between points is found. - step = 2.0 / (side-1) + step = 2.0 / (side - 1) - gc_to_x = [-1 + i_gcs[gc]*step for gc in range(0, side)] + gc_to_x = [-1 + i_gcs[gc] * step for gc in range(0, side)] # First k/2 bits determine x position. # Following k/2 bits determine y position. const_map = [] for i in range(m): y = gc_to_x[get_bits(i, 0, k // 2)] x = gc_to_x[get_bits(i, k // 2, k // 2)] - const_map.append(complex(x,y)) + const_map.append(complex(x, y)) return const_map # ///////////////////////////////////////////////////////////////////////////// # QAM constellation # ///////////////////////////////////////////////////////////////////////////// + def qam_constellation(constellation_points=_def_constellation_points, differential=_def_differential, mod_code=_def_mod_code, @@ -154,18 +161,20 @@ def qam_constellation(constellation_points=_def_constellation_points, else: raise ValueError("Mod code is not implemented for QAM") if differential: - points = make_differential_constellation(constellation_points, gray_coded=False) + points = make_differential_constellation( + constellation_points, gray_coded=False) else: - points = make_non_differential_constellation(constellation_points, gray_coded) + points = make_non_differential_constellation( + constellation_points, gray_coded) side = int(sqrt(constellation_points)) - width = 2.0 / (side-1) + width = 2.0 / (side - 1) # No pre-diff code # Should add one so that we can gray-code the quadrant bits too. pre_diff_code = [] if not large_ampls_to_corners: constellation = digital.constellation_rect(points, pre_diff_code, 4, - side, side, width, width) + side, side, width, width) else: sector_values = large_ampls_to_corners_mapping(side, points, width) constellation = digital.constellation_expl_rect( @@ -173,6 +182,7 @@ def qam_constellation(constellation_points=_def_constellation_points, return constellation + def find_closest_point(p, qs): """ Return in index of the closest point in 'qs' to 'p'. @@ -180,12 +190,13 @@ def find_closest_point(p, qs): min_dist = None min_i = None for i, q in enumerate(qs): - dist = abs(q-p) + dist = abs(q - p) if min_dist is None or dist < min_dist: min_dist = dist min_i = i return min_i + def large_ampls_to_corners_mapping(side, points, width): """ We have a grid that we use for decision making. One additional row/column @@ -222,7 +233,7 @@ def large_ampls_to_corners_mapping(side, points, width): # Value in this extra layer will be mapped to the closest corner rather # than the closest constellation point. extra_layers = 1 - side = side + extra_layers*2 + side = side + extra_layers * 2 # Calculate sector values sector_values = [] for real_x in range(side): @@ -230,10 +241,10 @@ def large_ampls_to_corners_mapping(side, points, width): sector = real_x * side + imag_x # If this sector is a normal constellation sector then # use the center point. - c = ((real_x-side / 2.0+0.5)*width + - (imag_x-side / 2.0+0.5)*width*1j) - if (real_x >= extra_layers and real_x < side-extra_layers - and imag_x >= extra_layers and imag_x < side-extra_layers): + c = ((real_x - side / 2.0 + 0.5) * width + + (imag_x - side / 2.0 + 0.5) * width * 1j) + if (real_x >= extra_layers and real_x < side - extra_layers + and imag_x >= extra_layers and imag_x < side - extra_layers): # This is not an edge row/column. Find closest point. index = find_closest_point(c, points) else: @@ -242,4 +253,5 @@ def large_ampls_to_corners_mapping(side, points, width): sector_values.append(index) return sector_values + modulation_utils.add_type_1_constellation('qam', qam_constellation) diff --git a/gr-digital/python/digital/qam_constellations.py b/gr-digital/python/digital/qam_constellations.py index 2ddaa92d15..42aa31611f 100644 --- a/gr-digital/python/digital/qam_constellations.py +++ b/gr-digital/python/digital/qam_constellations.py @@ -85,6 +85,7 @@ For 16QAM: 3, 2, 1, 0 ''' + def qam_16_0x0_0_1_2_3(): ''' | 0010 0110 | 1110 1010 @@ -95,18 +96,21 @@ def qam_16_0x0_0_1_2_3(): | | 0000 0100 | 1100 1000 ''' - const_points = [-3-3j, -1-3j, 1-3j, 3-3j, - -3-1j, -1-1j, 1-1j, 3-1j, - -3+1j, -1+1j, 1+1j, 3+1j, - -3+3j, -1+3j, 1+3j, 3+3j] + const_points = [-3 - 3j, -1 - 3j, 1 - 3j, 3 - 3j, + -3 - 1j, -1 - 1j, 1 - 1j, 3 - 1j, + -3 + 1j, -1 + 1j, 1 + 1j, 3 + 1j, + -3 + 3j, -1 + 3j, 1 + 3j, 3 + 3j] symbols = [0x0, 0x4, 0xC, 0x8, 0x1, 0x5, 0xD, 0x9, 0x3, 0x7, 0xF, 0xB, 0x2, 0x6, 0xE, 0xA] return (const_points, symbols) + + qam_16 = qam_16_0x0_0_1_2_3 qam_16_0 = qam_16 + def qam_16_0x1_0_1_2_3(): ''' | 0011 0111 | 1111 1011 @@ -120,8 +124,11 @@ def qam_16_0x1_0_1_2_3(): k = 0x1 pi = [0, 1, 2, 3] return constellation_map_generator(qam_16()[0], qam_16()[1], k, pi) + + qam_16_1 = qam_16_0x1_0_1_2_3 + def qam_16_0x2_0_1_2_3(): ''' | 0000 0100 | 1100 1000 @@ -135,8 +142,11 @@ def qam_16_0x2_0_1_2_3(): k = 0x2 pi = [0, 1, 2, 3] return constellation_map_generator(qam_16()[0], qam_16()[1], k, pi) + + qam_16_2 = qam_16_0x2_0_1_2_3 + def qam_16_0x3_0_1_2_3(): ''' | 0001 0101 | 1101 1001 @@ -150,6 +160,8 @@ def qam_16_0x3_0_1_2_3(): k = 0x3 pi = [0, 1, 2, 3] return constellation_map_generator(qam_16()[0], qam_16()[1], k, pi) + + qam_16_3 = qam_16_0x3_0_1_2_3 @@ -166,8 +178,11 @@ def qam_16_0x0_1_0_2_3(): k = 0x0 pi = [1, 0, 2, 3] return constellation_map_generator(qam_16()[0], qam_16()[1], k, pi) + + qam_16_4 = qam_16_0x0_1_0_2_3 + def qam_16_0x1_1_0_2_3(): ''' | 0000 0100 | 1100 1000 @@ -181,8 +196,11 @@ def qam_16_0x1_1_0_2_3(): k = 0x1 pi = [1, 0, 2, 3] return constellation_map_generator(qam_16()[0], qam_16()[1], k, pi) + + qam_16_5 = qam_16_0x1_1_0_2_3 + def qam_16_0x2_1_0_2_3(): ''' | 0011 0111 | 1111 1011 @@ -196,8 +214,11 @@ def qam_16_0x2_1_0_2_3(): k = 0x2 pi = [1, 0, 2, 3] return constellation_map_generator(qam_16()[0], qam_16()[1], k, pi) + + qam_16_6 = qam_16_0x2_1_0_2_3 + def qam_16_0x3_1_0_2_3(): ''' | 0010 0110 | 1110 1010 @@ -211,6 +232,8 @@ def qam_16_0x3_1_0_2_3(): k = 0x3 pi = [1, 0, 2, 3] return constellation_map_generator(qam_16()[0], qam_16()[1], k, pi) + + qam_16_7 = qam_16_0x3_1_0_2_3 @@ -229,7 +252,7 @@ def sd_qam_16_0x0_0_1_2_3(x, Es=1): | 0000 0100 | 1100 1000 ''' - dist = Es*numpy.sqrt(2) + dist = Es * numpy.sqrt(2) boundary = dist / 3.0 dist0 = dist / 6.0 # print "Sample: ", x @@ -242,26 +265,29 @@ def sd_qam_16_0x0_0_1_2_3(x, Es=1): x_im = x.imag if x_re < -boundary: - b3 = boundary*(x_re + dist0) + b3 = boundary * (x_re + dist0) elif x_re < boundary: b3 = x_re else: - b3 = boundary*(x_re - dist0) + b3 = boundary * (x_re - dist0) if x_im < -boundary: - b1 = boundary*(x_im + dist0) + b1 = boundary * (x_im + dist0) elif x_im < boundary: b1 = x_im else: - b1 = boundary*(x_im - dist0) + b1 = boundary * (x_im - dist0) b2 = -abs(x_re) + boundary b0 = -abs(x_im) + boundary - return [(Es / 2.0)*b3, (Es / 2.0)*b2, (Es / 2.0)*b1, (Es / 2.0)*b0] + return [(Es / 2.0) * b3, (Es / 2.0) * b2, (Es / 2.0) * b1, (Es / 2.0) * b0] + + sd_qam_16 = sd_qam_16_0x0_0_1_2_3 sd_qam_16_0 = sd_qam_16 + def sd_qam_16_0x1_0_1_2_3(x, Es=1): ''' | Soft bit LUT generator for constellation: @@ -274,29 +300,32 @@ def sd_qam_16_0x1_0_1_2_3(x, Es=1): | | 0001 0101 | 1101 1001 ''' - x_re = 3*x.real - x_im = 3*x.imag + x_re = 3 * x.real + x_im = 3 * x.imag if x_re < -2: - b3 = 2*(x_re + 1) + b3 = 2 * (x_re + 1) elif x_re < 2: b3 = x_re else: - b3 = 2*(x_re - 1) + b3 = 2 * (x_re - 1) if x_im < -2: - b1 = 2*(x_im + 1) + b1 = 2 * (x_im + 1) elif x_im < 2: b1 = x_im else: - b1 = 2*(x_im - 1) + b1 = 2 * (x_im - 1) b2 = -abs(x_re) + 2 b0 = +abs(x_im) - 2 return [b3, b2, b1, b0] + + sd_qam_16_1 = sd_qam_16_0x1_0_1_2_3 + def sd_qam_16_0x2_0_1_2_3(x, Es=1): ''' | Soft bit LUT generator for constellation: @@ -310,29 +339,32 @@ def sd_qam_16_0x2_0_1_2_3(x, Es=1): | 0010 0110 | 1110 1010 ''' - x_re = 3*x.real - x_im = 3*x.imag + x_re = 3 * x.real + x_im = 3 * x.imag if x_re < -2: - b3 = 2*(x_re + 1) + b3 = 2 * (x_re + 1) elif x_re < 2: b3 = x_re else: - b3 = 2*(x_re - 1) + b3 = 2 * (x_re - 1) if x_im < -2: - b1 = -2*(x_im + 1) + b1 = -2 * (x_im + 1) elif x_im < 2: b1 = -x_im else: - b1 = -2*(x_im - 1) + b1 = -2 * (x_im - 1) b2 = -abs(x_re) + 2 b0 = -abs(x_im) + 2 return [b3, b2, b1, b0] + + sd_qam_16_2 = sd_qam_16_0x2_0_1_2_3 + def sd_qam_16_0x3_0_1_2_3(x, Es=1): ''' | Soft bit LUT generator for constellation: @@ -345,29 +377,32 @@ def sd_qam_16_0x3_0_1_2_3(x, Es=1): | | 0011 0111 | 1111 1011 ''' - x_re = 3*x.real - x_im = 3*x.imag + x_re = 3 * x.real + x_im = 3 * x.imag if x_re < -2: - b3 = 2*(x_re + 1) + b3 = 2 * (x_re + 1) elif x_re < 2: b3 = x_re else: - b3 = 2*(x_re - 1) + b3 = 2 * (x_re - 1) if x_im < -2: - b1 = -2*(x_im + 1) + b1 = -2 * (x_im + 1) elif x_im < 2: b1 = -x_im else: - b1 = -2*(x_im - 1) + b1 = -2 * (x_im - 1) b2 = -abs(x_re) + 2 b0 = +abs(x_im) - 2 return [b3, b2, b1, b0] + + sd_qam_16_3 = sd_qam_16_0x3_0_1_2_3 + def sd_qam_16_0x0_1_0_2_3(x, Es=1): ''' | Soft bit LUT generator for constellation: @@ -380,29 +415,32 @@ def sd_qam_16_0x0_1_0_2_3(x, Es=1): | | 0000 0100 | 1100 1000 ''' - x_re = 3*x.real - x_im = 3*x.imag + x_re = 3 * x.real + x_im = 3 * x.imag if x_re < -2: - b3 = 2*(x_re + 1) + b3 = 2 * (x_re + 1) elif x_re < 2: b3 = x_re else: - b3 = 2*(x_re - 1) + b3 = 2 * (x_re - 1) if x_im < -2: - b0 = 2*(x_im + 1) + b0 = 2 * (x_im + 1) elif x_im < 2: b0 = x_im else: - b0 = 2*(x_im - 1) + b0 = 2 * (x_im - 1) b2 = -abs(x_re) + 2 b1 = -abs(x_im) + 2 return [b3, b2, b1, b0] + + sd_qam_16_4 = sd_qam_16_0x0_1_0_2_3 + def sd_qam_16_0x1_1_0_2_3(x, Es=1): ''' | Soft bit LUT generator for constellation: @@ -415,29 +453,32 @@ def sd_qam_16_0x1_1_0_2_3(x, Es=1): | | 0001 0101 | 1101 1001 ''' - x_re = 3*x.real - x_im = 3*x.imag + x_re = 3 * x.real + x_im = 3 * x.imag if x_re < -2: - b3 = 2*(x_re + 1) + b3 = 2 * (x_re + 1) elif x_re < 2: b3 = x_re else: - b3 = 2*(x_re - 1) + b3 = 2 * (x_re - 1) if x_im < -2: - b0 = -2*(x_im + 1) + b0 = -2 * (x_im + 1) elif x_im < 2: b0 = -x_im else: - b0 = -2*(x_im - 1) + b0 = -2 * (x_im - 1) b2 = -abs(x_re) + 2 b1 = -abs(x_im) + 2 return [b3, b2, b1, b0] + + sd_qam_16_5 = sd_qam_16_0x1_1_0_2_3 + def sd_qam_16_0x2_1_0_2_3(x, Es=1): ''' | Soft bit LUT generator for constellation: @@ -450,29 +491,32 @@ def sd_qam_16_0x2_1_0_2_3(x, Es=1): | | 0010 0110 | 1110 1010 ''' - x_re = 3*x.real - x_im = 3*x.imag + x_re = 3 * x.real + x_im = 3 * x.imag if x_re < -2: - b3 = 2*(x_re + 1) + b3 = 2 * (x_re + 1) elif x_re < 2: b3 = x_re else: - b3 = 2*(x_re - 1) + b3 = 2 * (x_re - 1) if x_im < -2: - b0 = 2*(x_im + 1) + b0 = 2 * (x_im + 1) elif x_im < 2: b0 = x_im else: - b0 = 2*(x_im - 1) + b0 = 2 * (x_im - 1) b2 = -abs(x_re) + 2 b1 = +abs(x_im) - 2 return [b3, b2, b1, b0] + + sd_qam_16_6 = sd_qam_16_0x2_1_0_2_3 + def sd_qam_16_0x3_1_0_2_3(x, Es=1): ''' | Soft bit LUT generator for constellation: @@ -485,25 +529,27 @@ def sd_qam_16_0x3_1_0_2_3(x, Es=1): | | 0011 0111 | 1111 1011 ''' - x_re = 3*x.real - x_im = 3*x.imag + x_re = 3 * x.real + x_im = 3 * x.imag if x_re < -2: - b3 = 2*(x_re + 1) + b3 = 2 * (x_re + 1) elif x_re < 2: b3 = x_re else: - b3 = 2*(x_re - 1) + b3 = 2 * (x_re - 1) if x_im < -2: - b0 = -2*(x_im + 1) + b0 = -2 * (x_im + 1) elif x_im < 2: b0 = -x_im else: - b0 = -2*(x_im - 1) + b0 = -2 * (x_im - 1) b2 = -abs(x_re) + 2 b1 = +abs(x_im) - 2 return [b3, b2, b1, b0] + + sd_qam_16_7 = sd_qam_16_0x3_1_0_2_3 diff --git a/gr-digital/python/digital/qamlike.py b/gr-digital/python/digital/qamlike.py index 88ff423e15..4939f20437 100644 --- a/gr-digital/python/digital/qamlike.py +++ b/gr-digital/python/digital/qamlike.py @@ -13,6 +13,7 @@ This file contains constellations that are similar to QAM, but are not perfect s from . import digital_python from .qam import large_ampls_to_corners_mapping + def qam32_holeinside_constellation(large_ampls_to_corners=False): # First make constellation for one quadrant. # 0 1 2 @@ -36,10 +37,10 @@ def qam32_holeinside_constellation(large_ampls_to_corners=False): ((1, 2), 0b111), ((2, 1), 0b100), ((2, 2), 0b110), - ) - points = [None]*32 + ) + points = [None] * 32 for indices, number in indices_and_numbers: - p_in_quadrant = 0.5+indices[0] + 1j*(0.5+indices[1]) + p_in_quadrant = 0.5 + indices[0] + 1j * (0.5 + indices[1]) for quadrant in range(4): index = number + 8 * quadrant rotation = pow(1j, quadrant) @@ -53,8 +54,8 @@ def qam32_holeinside_constellation(large_ampls_to_corners=False): width = 0.5 pre_diff_code = [] if not large_ampls_to_corners: - constellation = digital_python.constellation_rect(points, pre_diff_code, 4, - side, side, width, width) + constellation = digital_python.constellation_rect( + points, pre_diff_code, 4, side, side, width, width) else: sector_values = large_ampls_to_corners_mapping(side, points, width) constellation = digital_python.constellation_expl_rect( |