summaryrefslogtreecommitdiff
path: root/gr-digital/python/digital
diff options
context:
space:
mode:
authorElof Wecksell <elof@wecksell.se>2021-01-12 10:35:31 +0100
committerMartin Braun <martin@gnuradio.org>2021-01-29 03:31:03 -0800
commitb16924381c90e07d5d8cf5bc236c7dc48a0fd677 (patch)
treee5fe0c4005af6c6f0a6178139439a478de0abacf /gr-digital/python/digital
parent761b327c761e0596f72cbe9f63e510f1b36c4b47 (diff)
gr-digital: improved performance and capability of scramblers to 64-bit registers. Use __builtin_parity or volk popcnt. qa was also enhanced to detect errors.
Signed-off-by: Elof Wecksell <elof@wecksell.se> Co-authored-by: Martin Braun <martin@gnuradio.org>
Diffstat (limited to 'gr-digital/python/digital')
-rw-r--r--gr-digital/python/digital/CMakeLists.txt1
-rw-r--r--gr-digital/python/digital/bindings/additive_scrambler_bb_python.cc4
-rw-r--r--gr-digital/python/digital/bindings/descrambler_bb_python.cc4
-rw-r--r--gr-digital/python/digital/bindings/glfsr_python.cc6
-rw-r--r--gr-digital/python/digital/bindings/glfsr_source_b_python.cc4
-rw-r--r--gr-digital/python/digital/bindings/glfsr_source_f_python.cc4
-rw-r--r--gr-digital/python/digital/bindings/lfsr_python.cc6
-rw-r--r--gr-digital/python/digital/bindings/scrambler_bb_python.cc4
-rw-r--r--gr-digital/python/digital/qa_glfsr_source.py6
-rw-r--r--gr-digital/python/digital/qa_lfsr.py19
-rw-r--r--gr-digital/python/digital/qa_scrambler.py81
-rw-r--r--gr-digital/python/digital/utils/__init__.py2
-rw-r--r--gr-digital/python/digital/utils/lfsr.py21
13 files changed, 138 insertions, 24 deletions
diff --git a/gr-digital/python/digital/CMakeLists.txt b/gr-digital/python/digital/CMakeLists.txt
index b425e4dc72..5dc40f8e3a 100644
--- a/gr-digital/python/digital/CMakeLists.txt
+++ b/gr-digital/python/digital/CMakeLists.txt
@@ -37,6 +37,7 @@ GR_PYTHON_INSTALL(
FILES
utils/__init__.py
utils/gray_code.py
+ utils/lfsr.py
utils/mod_codes.py
utils/alignment.py
utils/tagged_streams.py
diff --git a/gr-digital/python/digital/bindings/additive_scrambler_bb_python.cc b/gr-digital/python/digital/bindings/additive_scrambler_bb_python.cc
index 8e25963e31..76bbe87eaf 100644
--- a/gr-digital/python/digital/bindings/additive_scrambler_bb_python.cc
+++ b/gr-digital/python/digital/bindings/additive_scrambler_bb_python.cc
@@ -13,8 +13,8 @@
/* If manual edits are made, the following tags should be modified accordingly. */
/* BINDTOOL_GEN_AUTOMATIC(0) */
/* BINDTOOL_USE_PYGCCXML(0) */
-/* BINDTOOL_HEADER_FILE(additive_scrambler_bb.h) */
-/* BINDTOOL_HEADER_FILE_HASH(a35bcdbbc4e320dd37c13a0adb156c57) */
+/* BINDTOOL_HEADER_FILE(additive_scrambler_bb.h) */
+/* BINDTOOL_HEADER_FILE_HASH(526b44ff08fc8ae301bc1e7a3508c540) */
/***********************************************************************************/
#include <pybind11/complex.h>
diff --git a/gr-digital/python/digital/bindings/descrambler_bb_python.cc b/gr-digital/python/digital/bindings/descrambler_bb_python.cc
index 2f1aa8dccc..6d8d4344a6 100644
--- a/gr-digital/python/digital/bindings/descrambler_bb_python.cc
+++ b/gr-digital/python/digital/bindings/descrambler_bb_python.cc
@@ -13,8 +13,8 @@
/* If manual edits are made, the following tags should be modified accordingly. */
/* BINDTOOL_GEN_AUTOMATIC(0) */
/* BINDTOOL_USE_PYGCCXML(0) */
-/* BINDTOOL_HEADER_FILE(descrambler_bb.h) */
-/* BINDTOOL_HEADER_FILE_HASH(d630c5081c027a198e21e0622963b40b) */
+/* BINDTOOL_HEADER_FILE(descrambler_bb.h) */
+/* BINDTOOL_HEADER_FILE_HASH(af9fc52c6846ef88340101d3c6bbacc7) */
/***********************************************************************************/
#include <pybind11/complex.h>
diff --git a/gr-digital/python/digital/bindings/glfsr_python.cc b/gr-digital/python/digital/bindings/glfsr_python.cc
index e716305931..4f120b0e1e 100644
--- a/gr-digital/python/digital/bindings/glfsr_python.cc
+++ b/gr-digital/python/digital/bindings/glfsr_python.cc
@@ -13,8 +13,8 @@
/* If manual edits are made, the following tags should be modified accordingly. */
/* BINDTOOL_GEN_AUTOMATIC(0) */
/* BINDTOOL_USE_PYGCCXML(0) */
-/* BINDTOOL_HEADER_FILE(glfsr.h) */
-/* BINDTOOL_HEADER_FILE_HASH(4299ef7303d0f404e97b16abb6de32ee) */
+/* BINDTOOL_HEADER_FILE(glfsr.h) */
+/* BINDTOOL_HEADER_FILE_HASH(0a9a03db1fc3d6a7b81b009e620c41c2) */
/***********************************************************************************/
#include <pybind11/complex.h>
@@ -35,7 +35,7 @@ void bind_glfsr(py::module& m)
py::class_<glfsr, std::shared_ptr<glfsr>>(m, "glfsr", D(glfsr))
- .def(py::init<uint32_t, uint32_t>(),
+ .def(py::init<uint64_t, uint64_t>(),
py::arg("mask"),
py::arg("seed"),
D(glfsr, glfsr, 0))
diff --git a/gr-digital/python/digital/bindings/glfsr_source_b_python.cc b/gr-digital/python/digital/bindings/glfsr_source_b_python.cc
index 5c8a850f41..17b3e7636f 100644
--- a/gr-digital/python/digital/bindings/glfsr_source_b_python.cc
+++ b/gr-digital/python/digital/bindings/glfsr_source_b_python.cc
@@ -13,8 +13,8 @@
/* If manual edits are made, the following tags should be modified accordingly. */
/* BINDTOOL_GEN_AUTOMATIC(0) */
/* BINDTOOL_USE_PYGCCXML(0) */
-/* BINDTOOL_HEADER_FILE(glfsr_source_b.h) */
-/* BINDTOOL_HEADER_FILE_HASH(7b6d09b85b54ce73f4e3c80b1809bed7) */
+/* BINDTOOL_HEADER_FILE(glfsr_source_b.h) */
+/* BINDTOOL_HEADER_FILE_HASH(d5e395b769198beb82a644f02b11f443) */
/***********************************************************************************/
#include <pybind11/complex.h>
diff --git a/gr-digital/python/digital/bindings/glfsr_source_f_python.cc b/gr-digital/python/digital/bindings/glfsr_source_f_python.cc
index 4e8a9883a0..7926ae0e09 100644
--- a/gr-digital/python/digital/bindings/glfsr_source_f_python.cc
+++ b/gr-digital/python/digital/bindings/glfsr_source_f_python.cc
@@ -13,8 +13,8 @@
/* If manual edits are made, the following tags should be modified accordingly. */
/* BINDTOOL_GEN_AUTOMATIC(0) */
/* BINDTOOL_USE_PYGCCXML(0) */
-/* BINDTOOL_HEADER_FILE(glfsr_source_f.h) */
-/* BINDTOOL_HEADER_FILE_HASH(fefa5e006f5c5c49a91ff379b1c571d4) */
+/* BINDTOOL_HEADER_FILE(glfsr_source_f.h) */
+/* BINDTOOL_HEADER_FILE_HASH(2e85e8ef0b1f9d6585364f2342f14ad1) */
/***********************************************************************************/
#include <pybind11/complex.h>
diff --git a/gr-digital/python/digital/bindings/lfsr_python.cc b/gr-digital/python/digital/bindings/lfsr_python.cc
index 8efe61e005..c971d77f46 100644
--- a/gr-digital/python/digital/bindings/lfsr_python.cc
+++ b/gr-digital/python/digital/bindings/lfsr_python.cc
@@ -13,8 +13,8 @@
/* If manual edits are made, the following tags should be modified accordingly. */
/* BINDTOOL_GEN_AUTOMATIC(0) */
/* BINDTOOL_USE_PYGCCXML(0) */
-/* BINDTOOL_HEADER_FILE(lfsr.h) */
-/* BINDTOOL_HEADER_FILE_HASH(6ad566b46874d5852d96814797e67bc4) */
+/* BINDTOOL_HEADER_FILE(lfsr.h) */
+/* BINDTOOL_HEADER_FILE_HASH(ae0c3aeb06a21a60a4415fe89135120e) */
/***********************************************************************************/
#include <pybind11/complex.h>
@@ -35,7 +35,7 @@ void bind_lfsr(py::module& m)
py::class_<lfsr, std::shared_ptr<lfsr>>(m, "lfsr", D(lfsr))
- .def(py::init<uint32_t, uint32_t, uint32_t>(),
+ .def(py::init<uint64_t, uint64_t, uint32_t>(),
py::arg("mask"),
py::arg("seed"),
py::arg("reg_len"),
diff --git a/gr-digital/python/digital/bindings/scrambler_bb_python.cc b/gr-digital/python/digital/bindings/scrambler_bb_python.cc
index 6632e97261..1afaa9e2e1 100644
--- a/gr-digital/python/digital/bindings/scrambler_bb_python.cc
+++ b/gr-digital/python/digital/bindings/scrambler_bb_python.cc
@@ -13,8 +13,8 @@
/* If manual edits are made, the following tags should be modified accordingly. */
/* BINDTOOL_GEN_AUTOMATIC(0) */
/* BINDTOOL_USE_PYGCCXML(0) */
-/* BINDTOOL_HEADER_FILE(scrambler_bb.h) */
-/* BINDTOOL_HEADER_FILE_HASH(857ba8ebaf0d0a1080493edc410b3aea) */
+/* BINDTOOL_HEADER_FILE(scrambler_bb.h) */
+/* BINDTOOL_HEADER_FILE_HASH(83d0f3673216d2c2d68b1833512e01e2) */
/***********************************************************************************/
#include <pybind11/complex.h>
diff --git a/gr-digital/python/digital/qa_glfsr_source.py b/gr-digital/python/digital/qa_glfsr_source.py
index dbe488399b..7fde483ed3 100644
--- a/gr-digital/python/digital/qa_glfsr_source.py
+++ b/gr-digital/python/digital/qa_glfsr_source.py
@@ -29,7 +29,7 @@ class test_glfsr_source(gr_unittest.TestCase):
self.assertRaises(RuntimeError,
lambda: digital.glfsr_source_b(0))
self.assertRaises(RuntimeError,
- lambda: digital.glfsr_source_b(33))
+ lambda: digital.glfsr_source_b(65))
def test_002_correlation_b(self):
for degree in range(
@@ -59,8 +59,8 @@ class test_glfsr_source(gr_unittest.TestCase):
self.assertRaises(RuntimeError,
lambda: digital.glfsr_source_f(0))
self.assertRaises(RuntimeError,
- lambda: digital.glfsr_source_f(33))
-
+ lambda: digital.glfsr_source_f(65))
+
def test_005_correlation_f(self):
for degree in range(
1, 11): # Higher degrees take too long to correlate
diff --git a/gr-digital/python/digital/qa_lfsr.py b/gr-digital/python/digital/qa_lfsr.py
index 0d7a2ccb94..e0db6a382b 100644
--- a/gr-digital/python/digital/qa_lfsr.py
+++ b/gr-digital/python/digital/qa_lfsr.py
@@ -10,9 +10,9 @@
import math
-
+import numpy as np
from gnuradio import gr, gr_unittest, digital
-
+from gnuradio.digital.utils import lfsr_args
class test_lfsr(gr_unittest.TestCase):
@@ -25,7 +25,6 @@ class test_lfsr(gr_unittest.TestCase):
def test_lfsr_001(self):
reglen = 8
l = digital.lfsr(1, 1, reglen)
-
result_data = []
for i in range(4 * (reglen + 1)):
result_data.append(l.next_bit())
@@ -33,6 +32,20 @@ class test_lfsr(gr_unittest.TestCase):
expected_result = 4 * ([1, ] + reglen * [0, ])
self.assertFloatTuplesAlmostEqual(expected_result, result_data, 5)
+ def test_lfsr_002(self):
+ l = digital.lfsr(*lfsr_args(0b1,5,3,0))
+ result_data = [l.next_bit() for _ in range(2*(2**5-1))]
+
+ expected_result = [1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0,
+ 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0]*2
+ self.assertEqual(expected_result, result_data)
+
+ seq1 = [l.next_bit() for _ in range(2**5-1)]
+ seq2 = [l.next_bit() for _ in range(2**5-1)]
+ self.assertEqual(seq1,seq2)
+
+ res = (np.convolve(seq1,[1,0,1,0,0,1])%2)
+ self.assertTrue(sum(res[5:-5])==0,"LRS not generated properly")
if __name__ == '__main__':
gr_unittest.run(test_lfsr)
diff --git a/gr-digital/python/digital/qa_scrambler.py b/gr-digital/python/digital/qa_scrambler.py
index 6f6c35134a..7d87f87b6c 100644
--- a/gr-digital/python/digital/qa_scrambler.py
+++ b/gr-digital/python/digital/qa_scrambler.py
@@ -8,8 +8,9 @@
#
#
-
from gnuradio import gr, gr_unittest, digital, blocks
+from gnuradio.digital.utils import lfsr_args
+import numpy as np
import pmt
# See gr-digital/lib/additive_scrambler_bb_impl.cc for reference.
@@ -25,7 +26,6 @@ def additive_scramble_lfsr(mask, seed, reglen, bpb, data):
out.append(d ^ scramble_word)
return out
-
class test_scrambler(gr_unittest.TestCase):
def setUp(self):
@@ -34,6 +34,83 @@ class test_scrambler(gr_unittest.TestCase):
def tearDown(self):
self.tb = None
+
+ def test_lfsr_002(self):
+ _a = lfsr_args(1,51,3,0)
+ l = digital.lfsr(*_a)
+ seq = [l.next_bit() for _ in range(2**10)]
+ reg = np.zeros(52,np.int8)
+ reg[::-1][(51,3,0),] = 1
+ res = (np.convolve(seq,reg)%2)
+ self.assertTrue(sum(res[52:-52])==0,"LRS not generated properly")
+
+ def test_scrambler_descrambler_001(self):
+ src_data = np.random.randint(0,2,500,dtype=np.int8)
+ src = blocks.vector_source_b(src_data, False)
+ scrambler = digital.scrambler_bb(*lfsr_args(0b1,7,2,0)) # p(x) = x^7 + x^2 + 1
+ descrambler = digital.descrambler_bb(*lfsr_args(0b111,7,2,0)) # we can use any seed here, it is descrambling.
+ m_tap = blocks.vector_sink_b()
+ dst = blocks.vector_sink_b()
+ self.tb.connect(src, scrambler, descrambler, dst)
+ self.tb.connect(scrambler, m_tap)
+ self.tb.run()
+ self.assertEqual(src_data[:-7].tolist(), dst.data()[7:]) # skip garbage during synchronization
+ self.assertEqual(tuple(np.convolve(m_tap.data(),[1,0,0,0,0,1,0,1])%2)[7:-10],
+ tuple(src_data[:-10])) # manual descrambling test
+
+ def test_scrambler_descrambler_002(self):
+ _a = lfsr_args(0b1,51,6,0) #p(x) = x^51+x^6+1
+ src_data = np.random.randint(0,2,1000,dtype=np.int8)
+ src = blocks.vector_source_b(src_data, False)
+ scrambler = digital.scrambler_bb(*_a)
+ m_tap = blocks.vector_sink_b()
+ descrambler = digital.descrambler_bb(*_a)
+ dst = blocks.vector_sink_b()
+ self.tb.connect(src, scrambler, descrambler, dst)
+ self.tb.connect(scrambler, m_tap)
+ self.tb.run()
+ self.assertTrue(np.all(src_data[:-51]==dst.data()[51:])) # skip garbage during synchronization
+ reg = np.zeros(52,np.int8)
+ reg[::-1][(51,6,0),] = 1
+ self.assertTrue(np.all( np.convolve(m_tap.data(),reg)[51:-60]%2
+ == src_data[:-60])) # manual descrambling test
+
+ def test_scrambler_descrambler_003(self):
+ src_data = np.random.randint(0,2,1000,dtype=np.int8)
+ src = blocks.vector_source_b(src_data, False)
+ scrambler = digital.scrambler_bb(*lfsr_args(1,12,10,3,2,0)) # this is the product of the other two
+ descrambler1 = digital.descrambler_bb(*lfsr_args(1,5,3,0))
+ descrambler2 = digital.descrambler_bb(*lfsr_args(1,7,2,0))
+ dst = blocks.vector_sink_b()
+ self.tb.connect(src, scrambler, descrambler1, descrambler2, dst)
+ self.tb.run()
+ self.assertTrue(np.all(src_data[:-12]==dst.data()[12:])) # skip garbage during synchronization
+
+ def test_additive_scrambler_001(self):
+ _a = lfsr_args(1,51,3,0) #i p(x) = x^51+x^3+1, seed 0x1
+ src_data = np.random.randint(0,2,1000,dtype=np.int8).tolist()
+ src = blocks.vector_source_b(src_data, False)
+ scrambler = digital.additive_scrambler_bb(*_a)
+ descrambler = digital.additive_scrambler_bb(*_a)
+ dst = blocks.vector_sink_b()
+ self.tb.connect(src, scrambler, descrambler, dst)
+ self.tb.run()
+ self.assertEqual(tuple(src_data), tuple(dst.data()))
+
+ def test_additive_scrambler_002(self):
+ _a = lfsr_args(1,51,3,0) #i p(x) = x^51+x^3+1, seed 0x1
+ src_data = [1,]*1000
+ src = blocks.vector_source_b(src_data, False)
+ scrambler = digital.additive_scrambler_bb(*_a)
+ dst = blocks.vector_sink_b()
+ self.tb.connect(src, scrambler, dst)
+ self.tb.run()
+ reg = np.zeros(52,np.int8)
+ reg[::-1][(51,3,0),] = 1
+ res = (np.convolve(dst.data(),reg)%2)[52:-52]
+ self.assertEqual(len(res), sum(res)) # when convolved with mask,
+ # after sync, only 1's would be returned.
+
def test_scrambler_descrambler(self):
src_data = [1, ] * 1000
src = blocks.vector_source_b(src_data, False)
diff --git a/gr-digital/python/digital/utils/__init__.py b/gr-digital/python/digital/utils/__init__.py
index 47378f54c5..0d5aae0b79 100644
--- a/gr-digital/python/digital/utils/__init__.py
+++ b/gr-digital/python/digital/utils/__init__.py
@@ -7,3 +7,5 @@
# SPDX-License-Identifier: GPL-3.0-or-later
#
#
+
+from .lfsr import lfsr_args
diff --git a/gr-digital/python/digital/utils/lfsr.py b/gr-digital/python/digital/utils/lfsr.py
new file mode 100644
index 0000000000..2b8a47cb76
--- /dev/null
+++ b/gr-digital/python/digital/utils/lfsr.py
@@ -0,0 +1,21 @@
+#!/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
+#
+#
+
+def lfsr_args(seed, *exp):
+ """
+ Produce arguments to create scrambler objects from exponent polynomial expressions.
+ seed: start-value of register
+ *exp: exponents of desired polynomial.
+ Example:
+ >>> l = digital.lfsr(*lfrs_args(0b11001,7,1,0))
+ Creates an lfsr object with seed 0b11001, mask 0b1000011, K=6
+ """
+ from functools import reduce
+ return reduce(int.__xor__, map(lambda x:2**x, exp)), seed, max(exp)-1