summaryrefslogtreecommitdiff
path: root/gr-digital/python
diff options
context:
space:
mode:
authorBen Reynwar <ben@reynwar.net>2012-08-08 14:26:07 -0700
committerBen Reynwar <ben@reynwar.net>2012-08-08 14:26:07 -0700
commit9be7c30d6df3fb8bd75db0659fa7a7d163d65657 (patch)
treeeaca0dec00f1aad0c8b883944f40e7c9730644f3 /gr-digital/python
parentc27d9d3bac3a870fee9ec8c4289ae65ab4f2decc (diff)
parent9305abf4be93205cf240e99ce7136702f724c490 (diff)
Merge branch 'master' into comments
Diffstat (limited to 'gr-digital/python')
-rw-r--r--gr-digital/python/CMakeLists.txt1
-rw-r--r--gr-digital/python/__init__.py1
-rw-r--r--gr-digital/python/generic_mod_demod.py24
-rw-r--r--gr-digital/python/gfsk.py306
-rwxr-xr-xgr-digital/python/qa_bytes_to_syms.py51
-rwxr-xr-xgr-digital/python/qa_chunks_to_symbols.py140
-rwxr-xr-xgr-digital/python/qa_correlate_access_code.py21
-rwxr-xr-xgr-digital/python/qa_diff_encoder.py87
-rwxr-xr-xgr-digital/python/qa_diff_phasor_cc.py49
-rwxr-xr-xgr-digital/python/qa_framer_sink.py98
-rwxr-xr-xgr-digital/python/qa_glfsr_source.py95
-rwxr-xr-xgr-digital/python/qa_map.py60
-rwxr-xr-xgr-digital/python/qa_pfb_clock_sync.py142
-rwxr-xr-xgr-digital/python/qa_pn_correlator_cc.py51
-rwxr-xr-xgr-digital/python/qa_probe_density.py71
-rwxr-xr-xgr-digital/python/qa_scrambler.py65
-rwxr-xr-xgr-digital/python/qa_simple_framer.py59
17 files changed, 1306 insertions, 15 deletions
diff --git a/gr-digital/python/CMakeLists.txt b/gr-digital/python/CMakeLists.txt
index c786b5a142..6a9f102955 100644
--- a/gr-digital/python/CMakeLists.txt
+++ b/gr-digital/python/CMakeLists.txt
@@ -30,6 +30,7 @@ GR_PYTHON_INSTALL(
crc.py
generic_mod_demod.py
gmsk.py
+ gfsk.py
modulation_utils.py
ofdm.py
ofdm_packet_utils.py
diff --git a/gr-digital/python/__init__.py b/gr-digital/python/__init__.py
index 3599fe91c1..662bb2d8f8 100644
--- a/gr-digital/python/__init__.py
+++ b/gr-digital/python/__init__.py
@@ -30,6 +30,7 @@ from qam import *
from bpsk import *
from qpsk import *
from gmsk import *
+from gfsk import *
from cpm import *
from pkt import *
from crc import *
diff --git a/gr-digital/python/generic_mod_demod.py b/gr-digital/python/generic_mod_demod.py
index ae876e1086..a6c4f3445a 100644
--- a/gr-digital/python/generic_mod_demod.py
+++ b/gr-digital/python/generic_mod_demod.py
@@ -28,7 +28,7 @@ Generic modulation and demodulation.
from gnuradio import gr
from modulation_utils import extract_kwargs_from_options_for_class
from utils import mod_codes
-import digital_swig
+import digital_swig as digital
import math
# default values (used in __init__ and add_options)
@@ -121,12 +121,12 @@ class generic_mod(gr.hier_block2):
gr.packed_to_unpacked_bb(self.bits_per_symbol(), gr.GR_MSB_FIRST)
if gray_coded == True:
- self.symbol_mapper = gr.map_bb(self._constellation.pre_diff_code())
+ self.symbol_mapper = digital.map_bb(self._constellation.pre_diff_code())
if differential:
- self.diffenc = gr.diff_encoder_bb(arity)
+ self.diffenc = digital.diff_encoder_bb(arity)
- self.chunks2symbols = gr.chunks_to_symbols_bc(self._constellation.points())
+ self.chunks2symbols = digital.chunks_to_symbols_bc(self._constellation.points())
# pulse shaping filter
nfilts = 32
@@ -269,28 +269,28 @@ class generic_demod(gr.hier_block2):
# Frequency correction
fll_ntaps = 55
- self.freq_recov = digital_swig.fll_band_edge_cc(self._samples_per_symbol, self._excess_bw,
- fll_ntaps, self._freq_bw)
+ self.freq_recov = digital.fll_band_edge_cc(self._samples_per_symbol, self._excess_bw,
+ fll_ntaps, self._freq_bw)
# symbol timing recovery with RRC data filter
taps = gr.firdes.root_raised_cosine(nfilts, nfilts*self._samples_per_symbol,
1.0, self._excess_bw, ntaps)
- self.time_recov = gr.pfb_clock_sync_ccf(self._samples_per_symbol,
- self._timing_bw, taps,
- nfilts, nfilts//2, self._timing_max_dev)
+ self.time_recov = digital.pfb_clock_sync_ccf(self._samples_per_symbol,
+ self._timing_bw, taps,
+ nfilts, nfilts//2, self._timing_max_dev)
fmin = -0.25
fmax = 0.25
- self.receiver = digital_swig.constellation_receiver_cb(
+ self.receiver = digital.constellation_receiver_cb(
self._constellation, self._phase_bw,
fmin, fmax)
# Do differential decoding based on phase change of symbols
if differential:
- self.diffdec = gr.diff_decoder_bb(arity)
+ self.diffdec = digital.diff_decoder_bb(arity)
if gray_coded:
- self.symbol_mapper = gr.map_bb(
+ self.symbol_mapper = digital.map_bb(
mod_codes.invert_code(self._constellation.pre_diff_code()))
# unpack the k bit vector into a stream of bits
diff --git a/gr-digital/python/gfsk.py b/gr-digital/python/gfsk.py
new file mode 100644
index 0000000000..c85fdf0e00
--- /dev/null
+++ b/gr-digital/python/gfsk.py
@@ -0,0 +1,306 @@
+#
+# GFSK modulation and demodulation.
+#
+#
+# Copyright 2005,2006,2007 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+# See gnuradio-examples/python/digital for examples
+
+from gnuradio import gr
+import modulation_utils
+import digital_swig as digital
+from math import pi
+import numpy
+from pprint import pprint
+import inspect
+
+# default values (used in __init__ and add_options)
+_def_samples_per_symbol = 2
+_def_sensitivity = 1
+_def_bt = 0.35
+_def_verbose = False
+_def_log = False
+
+_def_gain_mu = None
+_def_mu = 0.5
+_def_freq_error = 0.0
+_def_omega_relative_limit = 0.005
+
+
+# FIXME: Figure out how to make GFSK work with pfb_arb_resampler_fff for both
+# transmit and receive so we don't require integer samples per symbol.
+
+
+# /////////////////////////////////////////////////////////////////////////////
+# GFSK modulator
+# /////////////////////////////////////////////////////////////////////////////
+
+class gfsk_mod(gr.hier_block2):
+
+ def __init__(self,
+ samples_per_symbol=_def_samples_per_symbol,
+ sensitivity=_def_sensitivity,
+ bt=_def_bt,
+ verbose=_def_verbose,
+ log=_def_log):
+ """
+ Hierarchical block for Gaussian Frequency Shift Key (GFSK)
+ modulation.
+
+ The input is a byte stream (unsigned char) and the
+ output is the complex modulated signal at baseband.
+
+ @param samples_per_symbol: samples per baud >= 2
+ @type samples_per_symbol: integer
+ @param bt: Gaussian filter bandwidth * symbol time
+ @type bt: float
+ @param verbose: Print information about modulator?
+ @type verbose: bool
+ @param debug: Print modualtion data to files?
+ @type debug: bool
+ """
+
+ gr.hier_block2.__init__(self, "gfsk_mod",
+ gr.io_signature(1, 1, gr.sizeof_char), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature
+
+ samples_per_symbol = int(samples_per_symbol)
+ self._samples_per_symbol = samples_per_symbol
+ self._bt = bt
+ self._differential = False
+
+ if not isinstance(samples_per_symbol, int) or samples_per_symbol < 2:
+ raise TypeError, ("samples_per_symbol must be an integer >= 2, is %r" % (samples_per_symbol,))
+
+ ntaps = 4 * samples_per_symbol # up to 3 bits in filter at once
+ #sensitivity = (pi / 2) / samples_per_symbol # phase change per bit = pi / 2
+
+ # Turn it into NRZ data.
+ self.nrz = gr.bytes_to_syms()
+
+ # Form Gaussian filter
+ # Generate Gaussian response (Needs to be convolved with window below).
+ self.gaussian_taps = gr.firdes.gaussian(
+ 1.0, # gain
+ samples_per_symbol, # symbol_rate
+ bt, # bandwidth * symbol time
+ ntaps # number of taps
+ )
+
+ self.sqwave = (1,) * samples_per_symbol # rectangular window
+ self.taps = numpy.convolve(numpy.array(self.gaussian_taps),numpy.array(self.sqwave))
+ self.gaussian_filter = gr.interp_fir_filter_fff(samples_per_symbol, self.taps)
+
+ # FM modulation
+ self.fmmod = gr.frequency_modulator_fc(sensitivity)
+
+ # small amount of output attenuation to prevent clipping USRP sink
+ self.amp = gr.multiply_const_cc(0.999)
+
+ if verbose:
+ self._print_verbage()
+
+ if log:
+ self._setup_logging()
+
+ # Connect & Initialize base class
+ self.connect(self, self.nrz, self.gaussian_filter, self.fmmod, self.amp, self)
+
+ def samples_per_symbol(self):
+ return self._samples_per_symbol
+
+ def bits_per_symbol(self=None): # staticmethod that's also callable on an instance
+ return 1
+ bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method.
+
+
+ def _print_verbage(self):
+ print "bits per symbol = %d" % self.bits_per_symbol()
+ print "Gaussian filter bt = %.2f" % self._bt
+
+
+ def _setup_logging(self):
+ print "Modulation logging turned on."
+ self.connect(self.nrz,
+ gr.file_sink(gr.sizeof_float, "nrz.dat"))
+ self.connect(self.gaussian_filter,
+ gr.file_sink(gr.sizeof_float, "gaussian_filter.dat"))
+ self.connect(self.fmmod,
+ gr.file_sink(gr.sizeof_gr_complex, "fmmod.dat"))
+
+
+ def add_options(parser):
+ """
+ Adds GFSK modulation-specific options to the standard parser
+ """
+ parser.add_option("", "--bt", type="float", default=_def_bt,
+ help="set bandwidth-time product [default=%default] (GFSK)")
+ add_options=staticmethod(add_options)
+
+
+ def extract_kwargs_from_options(options):
+ """
+ Given command line options, create dictionary suitable for passing to __init__
+ """
+ return modulation_utils.extract_kwargs_from_options(gfsk_mod.__init__,
+ ('self',), options)
+ extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
+
+
+
+# /////////////////////////////////////////////////////////////////////////////
+# GFSK demodulator
+# /////////////////////////////////////////////////////////////////////////////
+
+class gfsk_demod(gr.hier_block2):
+
+ def __init__(self,
+ samples_per_symbol=_def_samples_per_symbol,
+ sensitivity=_def_sensitivity,
+ gain_mu=_def_gain_mu,
+ mu=_def_mu,
+ omega_relative_limit=_def_omega_relative_limit,
+ freq_error=_def_freq_error,
+ verbose=_def_verbose,
+ log=_def_log):
+ """
+ Hierarchical block for Gaussian Minimum Shift Key (GFSK)
+ demodulation.
+
+ The input is the complex modulated signal at baseband.
+ The output is a stream of bits packed 1 bit per byte (the LSB)
+
+ @param samples_per_symbol: samples per baud
+ @type samples_per_symbol: integer
+ @param verbose: Print information about modulator?
+ @type verbose: bool
+ @param log: Print modualtion data to files?
+ @type log: bool
+
+ Clock recovery parameters. These all have reasonble defaults.
+
+ @param gain_mu: controls rate of mu adjustment
+ @type gain_mu: float
+ @param mu: fractional delay [0.0, 1.0]
+ @type mu: float
+ @param omega_relative_limit: sets max variation in omega
+ @type omega_relative_limit: float, typically 0.000200 (200 ppm)
+ @param freq_error: bit rate error as a fraction
+ @param float
+ """
+
+ gr.hier_block2.__init__(self, "gfsk_demod",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_char)) # Output signature
+
+ self._samples_per_symbol = samples_per_symbol
+ self._gain_mu = gain_mu
+ self._mu = mu
+ self._omega_relative_limit = omega_relative_limit
+ self._freq_error = freq_error
+ self._differential = False
+
+ if samples_per_symbol < 2:
+ raise TypeError, "samples_per_symbol >= 2, is %f" % samples_per_symbol
+
+ self._omega = samples_per_symbol*(1+self._freq_error)
+
+ if not self._gain_mu:
+ self._gain_mu = 0.175
+
+ self._gain_omega = .25 * self._gain_mu * self._gain_mu # critically damped
+
+ # Demodulate FM
+ #sensitivity = (pi / 2) / samples_per_symbol
+ self.fmdemod = gr.quadrature_demod_cf(1.0 / sensitivity)
+
+ # the clock recovery block tracks the symbol clock and resamples as needed.
+ # the output of the block is a stream of soft symbols (float)
+ self.clock_recovery = digital.clock_recovery_mm_ff(self._omega, self._gain_omega,
+ self._mu, self._gain_mu,
+ self._omega_relative_limit)
+
+ # slice the floats at 0, outputting 1 bit (the LSB of the output byte) per sample
+ self.slicer = digital.binary_slicer_fb()
+
+ if verbose:
+ self._print_verbage()
+
+ if log:
+ self._setup_logging()
+
+ # Connect & Initialize base class
+ self.connect(self, self.fmdemod, self.clock_recovery, self.slicer, self)
+
+ def samples_per_symbol(self):
+ return self._samples_per_symbol
+
+ def bits_per_symbol(self=None): # staticmethod that's also callable on an instance
+ return 1
+ bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method.
+
+
+ def _print_verbage(self):
+ print "bits per symbol = %d" % self.bits_per_symbol()
+ print "M&M clock recovery omega = %f" % self._omega
+ print "M&M clock recovery gain mu = %f" % self._gain_mu
+ print "M&M clock recovery mu = %f" % self._mu
+ print "M&M clock recovery omega rel. limit = %f" % self._omega_relative_limit
+ print "frequency error = %f" % self._freq_error
+
+
+ def _setup_logging(self):
+ print "Demodulation logging turned on."
+ self.connect(self.fmdemod,
+ gr.file_sink(gr.sizeof_float, "fmdemod.dat"))
+ self.connect(self.clock_recovery,
+ gr.file_sink(gr.sizeof_float, "clock_recovery.dat"))
+ self.connect(self.slicer,
+ gr.file_sink(gr.sizeof_char, "slicer.dat"))
+
+ def add_options(parser):
+ """
+ Adds GFSK demodulation-specific options to the standard parser
+ """
+ parser.add_option("", "--gain-mu", type="float", default=_def_gain_mu,
+ help="M&M clock recovery gain mu [default=%default] (GFSK/PSK)")
+ parser.add_option("", "--mu", type="float", default=_def_mu,
+ help="M&M clock recovery mu [default=%default] (GFSK/PSK)")
+ parser.add_option("", "--omega-relative-limit", type="float", default=_def_omega_relative_limit,
+ help="M&M clock recovery omega relative limit [default=%default] (GFSK/PSK)")
+ parser.add_option("", "--freq-error", type="float", default=_def_freq_error,
+ help="M&M clock recovery frequency error [default=%default] (GFSK)")
+ add_options=staticmethod(add_options)
+
+ def extract_kwargs_from_options(options):
+ """
+ Given command line options, create dictionary suitable for passing to __init__
+ """
+ return modulation_utils.extract_kwargs_from_options(gfsk_demod.__init__,
+ ('self',), options)
+ extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
+
+
+#
+# Add these to the mod/demod registry
+#
+modulation_utils.add_type_1_mod('gfsk', gfsk_mod)
+modulation_utils.add_type_1_demod('gfsk', gfsk_demod)
diff --git a/gr-digital/python/qa_bytes_to_syms.py b/gr-digital/python/qa_bytes_to_syms.py
new file mode 100755
index 0000000000..75475a95b2
--- /dev/null
+++ b/gr-digital/python/qa_bytes_to_syms.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+#
+# Copyright 2004,2007,2010,2012 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+from gnuradio import gr, gr_unittest
+import digital_swig as digital
+import math
+
+class test_bytes_to_syms (gr_unittest.TestCase):
+
+ def setUp (self):
+ self.tb = gr.top_block ()
+
+ def tearDown (self):
+ self.tb = None
+
+ def test_bytes_to_syms_001 (self):
+ src_data = (0x01, 0x80, 0x03)
+ expected_result = (-1, -1, -1, -1, -1, -1, -1, +1,
+ +1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, +1, +1)
+ src = gr.vector_source_b (src_data)
+ op = digital.bytes_to_syms ()
+ dst = gr.vector_sink_f ()
+ self.tb.connect (src, op)
+ self.tb.connect (op, dst)
+ self.tb.run ()
+ result_data = dst.data ()
+ self.assertEqual (expected_result, result_data)
+
+if __name__ == '__main__':
+ gr_unittest.run(test_bytes_to_syms, "test_bytes_to_syms.xml")
+
diff --git a/gr-digital/python/qa_chunks_to_symbols.py b/gr-digital/python/qa_chunks_to_symbols.py
new file mode 100755
index 0000000000..63af10d8ff
--- /dev/null
+++ b/gr-digital/python/qa_chunks_to_symbols.py
@@ -0,0 +1,140 @@
+#!/usr/bin/env python
+#
+# Copyright 2012 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+from gnuradio import gr, gr_unittest
+import digital_swig as digital
+
+class test_chunks_to_symbols(gr_unittest.TestCase):
+
+ def setUp (self):
+ self.tb = gr.top_block ()
+
+ def tearDown (self):
+ self.tb = None
+
+ def test_bc_001(self):
+ 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)
+
+ src = gr.vector_source_b(src_data)
+ op = digital.chunks_to_symbols_bc(const)
+
+ dst = gr.vector_sink_c()
+ self.tb.connect(src, op)
+ self.tb.connect(op, dst)
+ self.tb.run()
+
+ actual_result = dst.data()
+ self.assertEqual(expected_result, actual_result)
+
+ def test_bf_002(self):
+ 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)
+
+ src = gr.vector_source_b(src_data)
+ op = digital.chunks_to_symbols_bf(const)
+
+ dst = gr.vector_sink_f()
+ self.tb.connect(src, op)
+ self.tb.connect(op, dst)
+ self.tb.run()
+
+ actual_result = dst.data()
+ self.assertEqual(expected_result, actual_result)
+
+ def test_ic_003(self):
+ 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)
+
+ src = gr.vector_source_i(src_data)
+ op = digital.chunks_to_symbols_ic(const)
+
+ dst = gr.vector_sink_c()
+ self.tb.connect(src, op)
+ self.tb.connect(op, dst)
+ self.tb.run()
+
+ actual_result = dst.data()
+ self.assertEqual(expected_result, actual_result)
+
+ def test_if_004(self):
+ 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)
+
+ src = gr.vector_source_i(src_data)
+ op = digital.chunks_to_symbols_if(const)
+
+ dst = gr.vector_sink_f()
+ self.tb.connect(src, op)
+ self.tb.connect(op, dst)
+ self.tb.run()
+
+ actual_result = dst.data()
+ self.assertEqual(expected_result, actual_result)
+
+ def test_sc_005(self):
+ 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)
+
+ src = gr.vector_source_s(src_data)
+ op = digital.chunks_to_symbols_sc(const)
+
+ dst = gr.vector_sink_c()
+ self.tb.connect(src, op)
+ self.tb.connect(op, dst)
+ self.tb.run()
+
+ actual_result = dst.data()
+ self.assertEqual(expected_result, actual_result)
+
+ def test_sf_006(self):
+ 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)
+
+ src = gr.vector_source_s(src_data)
+ op = digital.chunks_to_symbols_sf(const)
+
+ dst = gr.vector_sink_f()
+ self.tb.connect(src, op)
+ self.tb.connect(op, dst)
+ self.tb.run()
+
+ actual_result = dst.data()
+ self.assertEqual(expected_result, actual_result)
+
+if __name__ == '__main__':
+ gr_unittest.run(test_chunks_to_symbols, "test_chunks_to_symbols.xml")
diff --git a/gr-digital/python/qa_correlate_access_code.py b/gr-digital/python/qa_correlate_access_code.py
index 6b6f25051e..96246dcfb9 100755
--- a/gr-digital/python/qa_correlate_access_code.py
+++ b/gr-digital/python/qa_correlate_access_code.py
@@ -21,7 +21,7 @@
#
from gnuradio import gr, gr_unittest
-import digital_swig
+import digital_swig as digital
import math
default_access_code = '\xAC\xDD\xA4\xE2\xF2\x8C\x20\xFC'
@@ -53,7 +53,7 @@ class test_correlate_access_code(gr_unittest.TestCase):
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 = gr.vector_source_b (src_data)
- op = digital_swig.correlate_access_code_bb("1011", 0)
+ op = digital.correlate_access_code_bb("1011", 0)
dst = gr.vector_sink_b ()
self.tb.connect (src, op, dst)
self.tb.run ()
@@ -70,13 +70,28 @@ class test_correlate_access_code(gr_unittest.TestCase):
src_data = code + (1, 0, 1, 1) + pad
expected_result = pad + code + (3, 0, 1, 1)
src = gr.vector_source_b (src_data)
- op = digital_swig.correlate_access_code_bb(access_code, 0)
+ op = digital.correlate_access_code_bb(access_code, 0)
dst = gr.vector_sink_b ()
self.tb.connect (src, op, dst)
self.tb.run ()
result_data = dst.data ()
self.assertEqual (expected_result, result_data)
+ def test_003(self):
+ 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
+ src_data = code + (1, 0, 1, 1) + pad
+ expected_result = code + (1, 0, 1, 1) + pad
+ src = gr.vector_source_b (src_data)
+ op = digital.correlate_access_code_tag_bb(access_code, 0, "test")
+ dst = gr.vector_sink_b ()
+ self.tb.connect (src, op, dst)
+ self.tb.run ()
+ result_data = dst.data ()
+ self.assertEqual (expected_result, result_data)
if __name__ == '__main__':
diff --git a/gr-digital/python/qa_diff_encoder.py b/gr-digital/python/qa_diff_encoder.py
new file mode 100755
index 0000000000..e4f5470af5
--- /dev/null
+++ b/gr-digital/python/qa_diff_encoder.py
@@ -0,0 +1,87 @@
+#!/usr/bin/env python
+#
+# Copyright 2006,2007,2010,2012 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+from gnuradio import gr, gr_unittest
+import digital_swig as digital
+import math
+import random
+
+def make_random_int_tuple(L, min, max):
+ result = []
+ for x in range(L):
+ result.append(random.randint(min, max))
+ return tuple(result)
+
+
+class test_diff_encoder (gr_unittest.TestCase):
+
+ def setUp (self):
+ self.tb = gr.top_block ()
+
+ def tearDown (self):
+ self.tb = None
+
+ def test_diff_encdec_000(self):
+ random.seed(0)
+ modulus = 2
+ src_data = make_random_int_tuple(1000, 0, modulus-1)
+ expected_result = src_data
+ src = gr.vector_source_b(src_data)
+ enc = digital.diff_encoder_bb(modulus)
+ dec = digital.diff_decoder_bb(modulus)
+ dst = gr.vector_sink_b()
+ self.tb.connect(src, enc, dec, dst)
+ self.tb.run() # run the graph and wait for it to finish
+ actual_result = dst.data() # fetch the contents of the sink
+ self.assertEqual(expected_result, actual_result)
+
+ def test_diff_encdec_001(self):
+ random.seed(0)
+ modulus = 4
+ src_data = make_random_int_tuple(1000, 0, modulus-1)
+ expected_result = src_data
+ src = gr.vector_source_b(src_data)
+ enc = digital.diff_encoder_bb(modulus)
+ dec = digital.diff_decoder_bb(modulus)
+ dst = gr.vector_sink_b()
+ self.tb.connect(src, enc, dec, dst)
+ self.tb.run() # run the graph and wait for it to finish
+ actual_result = dst.data() # fetch the contents of the sink
+ self.assertEqual(expected_result, actual_result)
+
+ def test_diff_encdec_002(self):
+ random.seed(0)
+ modulus = 8
+ src_data = make_random_int_tuple(40000, 0, modulus-1)
+ expected_result = src_data
+ src = gr.vector_source_b(src_data)
+ enc = digital.diff_encoder_bb(modulus)
+ dec = digital.diff_decoder_bb(modulus)
+ dst = gr.vector_sink_b()
+ self.tb.connect(src, enc, dec, dst)
+ self.tb.run() # run the graph and wait for it to finish
+ 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, "test_diff_encoder.xml")
+
diff --git a/gr-digital/python/qa_diff_phasor_cc.py b/gr-digital/python/qa_diff_phasor_cc.py
new file mode 100755
index 0000000000..3e7617fe47
--- /dev/null
+++ b/gr-digital/python/qa_diff_phasor_cc.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+#
+# Copyright 2004,2007,2010 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+from gnuradio import gr, gr_unittest
+import digital_swig as digital
+import math
+
+class test_diff_phasor (gr_unittest.TestCase):
+
+ def setUp (self):
+ self.tb = gr.top_block ()
+
+ def tearDown (self):
+ 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 = gr.vector_source_c (src_data)
+ op = digital.diff_phasor_cc ()
+ dst = gr.vector_sink_c ()
+ self.tb.connect (src, op)
+ self.tb.connect (op, dst)
+ self.tb.run () # run the graph and wait for it to finish
+ 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, "test_diff_phasor.xml")
+
diff --git a/gr-digital/python/qa_framer_sink.py b/gr-digital/python/qa_framer_sink.py
new file mode 100755
index 0000000000..bccc86dc78
--- /dev/null
+++ b/gr-digital/python/qa_framer_sink.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python
+#
+# Copyright 2012 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+from gnuradio import gr, gr_unittest
+import digital_swig as digital
+
+default_access_code = '\xAC\xDD\xA4\xE2\xF2\x8C\x20\xFC'
+
+def string_to_1_0_list(s):
+ r = []
+ for ch in s:
+ x = ord(ch)
+ for i in range(8):
+ t = (x >> i) & 0x1
+ r.append(t)
+ return r
+
+def to_1_0_string(L):
+ return ''.join(map(lambda x: chr(x + ord('0')), L))
+
+class test_framker_sink(gr_unittest.TestCase):
+
+ def setUp(self):
+ self.tb = gr.top_block()
+
+ def tearDown(self):
+ self.tb = None
+
+ def test_001(self):
+
+ 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
+ pad = (0,) * 100
+ src_data = code + header + (0,1,0,0,0,0,0,1) + pad
+ expected_data = 'A'
+
+ rcvd_pktq = gr.msg_queue()
+
+ src = gr.vector_source_b(src_data)
+ correlator = digital.correlate_access_code_bb(access_code, 0)
+ framer_sink = digital.framer_sink_1(rcvd_pktq)
+ vsnk = gr.vector_sink_b()
+
+ self.tb.connect(src, correlator, framer_sink)
+ self.tb.connect(correlator, vsnk)
+ self.tb.run ()
+
+ result_data = rcvd_pktq.delete_head()
+ result_data = result_data.to_string()
+ self.assertEqual (expected_data, result_data)
+
+ def test_002(self):
+
+ 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
+ pad = (0,) * 100
+ src_data = code + header + (0,1,0,0,1,0,0,0) + (0,1,0,0,1,0,0,1) + pad
+ expected_data = 'HI'
+
+ rcvd_pktq = gr.msg_queue()
+
+ src = gr.vector_source_b(src_data)
+ correlator = digital.correlate_access_code_bb(access_code, 0)
+ framer_sink = digital.framer_sink_1(rcvd_pktq)
+ vsnk = gr.vector_sink_b()
+
+ self.tb.connect(src, correlator, framer_sink)
+ self.tb.connect(correlator, vsnk)
+ self.tb.run ()
+
+ result_data = rcvd_pktq.delete_head()
+ result_data = result_data.to_string()
+ self.assertEqual (expected_data, result_data)
+
+if __name__ == '__main__':
+ gr_unittest.run(test_framker_sink, "test_framker_sink.xml")
+
diff --git a/gr-digital/python/qa_glfsr_source.py b/gr-digital/python/qa_glfsr_source.py
new file mode 100755
index 0000000000..157520d7f8
--- /dev/null
+++ b/gr-digital/python/qa_glfsr_source.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python
+#
+# Copyright 2007,2010,2012 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+from gnuradio import gr, gr_unittest
+import digital_swig as digital
+
+class test_glfsr_source(gr_unittest.TestCase):
+
+ def setUp (self):
+ self.tb = gr.top_block ()
+
+ def tearDown (self):
+ self.tb = None
+
+ def test_000_make_b(self):
+ src = digital.glfsr_source_b(16)
+ self.assertEquals(src.mask(), 0x8016)
+ self.assertEquals(src.period(), 2**16-1)
+
+ def test_001_degree_b(self):
+ self.assertRaises(RuntimeError,
+ lambda: gr.glfsr_source_b(0))
+ self.assertRaises(RuntimeError,
+ lambda: gr.glfsr_source_b(33))
+
+ def test_002_correlation_b(self):
+ 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)
+ dst = gr.vector_sink_f()
+ 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
+
+ def test_003_make_f(self):
+ src = digital.glfsr_source_f(16)
+ self.assertEquals(src.mask(), 0x8016)
+ self.assertEquals(src.period(), 2**16-1)
+
+ def test_004_degree_f(self):
+ self.assertRaises(RuntimeError,
+ lambda: gr.glfsr_source_f(0))
+ self.assertRaises(RuntimeError,
+ lambda: gr.glfsr_source_f(33))
+ def test_005_correlation_f(self):
+ for degree in range(1,11): # Higher degrees take too long to correlate
+ src = digital.glfsr_source_f(degree, False)
+ dst = gr.vector_sink_f()
+ 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
+
+def auto_correlate(data):
+ l = len(data)
+ R = [0,]*l
+ for lag in range(l):
+ for i in range(l):
+ R[lag] += data[i]*data[i-lag]
+ return R
+
+if __name__ == '__main__':
+ gr_unittest.run(test_glfsr_source, "test_glfsr_source.xml")
diff --git a/gr-digital/python/qa_map.py b/gr-digital/python/qa_map.py
new file mode 100755
index 0000000000..3ad99a2c12
--- /dev/null
+++ b/gr-digital/python/qa_map.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+#
+# Copyright 2012 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+from gnuradio import gr, gr_unittest
+import digital_swig as digital
+
+class test_map(gr_unittest.TestCase):
+
+ def setUp(self):
+ self.tb = gr.top_block()
+
+ def tearDown(self):
+ self.tb = None
+
+ def helper(self, symbols):
+ src_data = [0, 1, 2, 3, 0, 1, 2, 3]
+ expected_data = map(lambda x: symbols[x], src_data)
+ src = gr.vector_source_b (src_data)
+ op = digital.map_bb(symbols)
+ dst = gr.vector_sink_b ()
+ self.tb.connect (src, op, dst)
+ self.tb.run ()
+
+ result_data = list(dst.data())
+ self.assertEqual (expected_data, result_data)
+
+ 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]
+ self.helper(symbols)
+
+if __name__ == '__main__':
+ gr_unittest.run(test_map, "test_map.xml")
+
diff --git a/gr-digital/python/qa_pfb_clock_sync.py b/gr-digital/python/qa_pfb_clock_sync.py
new file mode 100755
index 0000000000..06c8a60ba7
--- /dev/null
+++ b/gr-digital/python/qa_pfb_clock_sync.py
@@ -0,0 +1,142 @@
+#!/usr/bin/env python
+#
+# Copyright 2011 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+from gnuradio import gr, gr_unittest
+import digital_swig as digital
+import random, cmath
+
+class test_pfb_clock_sync(gr_unittest.TestCase):
+
+ def setUp (self):
+ self.tb = gr.top_block ()
+
+ def tearDown (self):
+ self.tb = None
+
+ def test01 (self):
+ # Test BPSK sync
+ excess_bw = 0.35
+
+ sps = 4
+ loop_bw = cmath.pi/100.0
+ nfilts = 32
+ init_phase = nfilts/2
+ max_rate_deviation = 1.5
+ osps = 1
+
+ ntaps = 11 * int(sps*nfilts)
+ taps = gr.firdes.root_raised_cosine(nfilts, nfilts*sps,
+ 1.0, excess_bw, ntaps)
+
+ self.test = digital.pfb_clock_sync_ccf(sps, loop_bw, taps,
+ nfilts, init_phase,
+ max_rate_deviation,
+ osps)
+
+ data = 1000*[complex(1,0), complex(-1,0)]
+ self.src = gr.vector_source_c(data, False)
+
+ # pulse shaping interpolation filter
+ rrc_taps = gr.firdes.root_raised_cosine(
+ nfilts, # gain
+ nfilts, # sampling rate based on 32 filters in resampler
+ 1.0, # symbol rate
+ excess_bw, # excess bandwidth (roll-off factor)
+ ntaps)
+ self.rrc_filter = gr.pfb_arb_resampler_ccf(sps, rrc_taps)
+
+ self.snk = gr.vector_sink_c()
+
+ self.tb.connect(self.src, self.rrc_filter, self.test, self.snk)
+ self.tb.run()
+
+ expected_result = 1000*[complex(-1,0), complex(1,0)]
+ dst_data = self.snk.data()
+
+ # Only compare last Ncmp samples
+ Ncmp = 100
+ len_e = len(expected_result)
+ len_d = len(dst_data)
+ expected_result = expected_result[len_e - Ncmp:]
+ dst_data = dst_data[len_d - Ncmp:]
+
+ #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
+
+ sps = 4
+ loop_bw = cmath.pi/100.0
+ nfilts = 32
+ init_phase = nfilts/2
+ max_rate_deviation = 1.5
+ osps = 1
+
+ ntaps = 11 * int(sps*nfilts)
+ taps = gr.firdes.root_raised_cosine(nfilts, nfilts*sps,
+ 1.0, excess_bw, ntaps)
+
+ self.test = digital.pfb_clock_sync_fff(sps, loop_bw, taps,
+ nfilts, init_phase,
+ max_rate_deviation,
+ osps)
+
+ data = 1000*[1, -1]
+ self.src = gr.vector_source_f(data, False)
+
+ # pulse shaping interpolation filter
+ rrc_taps = gr.firdes.root_raised_cosine(
+ nfilts, # gain
+ nfilts, # sampling rate based on 32 filters in resampler
+ 1.0, # symbol rate
+ excess_bw, # excess bandwidth (roll-off factor)
+ ntaps)
+ self.rrc_filter = gr.pfb_arb_resampler_fff(sps, rrc_taps)
+
+ self.snk = gr.vector_sink_f()
+
+ self.tb.connect(self.src, self.rrc_filter, self.test, self.snk)
+ self.tb.run()
+
+ expected_result = 1000*[-1, 1]
+ dst_data = self.snk.data()
+
+ # Only compare last Ncmp samples
+ Ncmp = 100
+ len_e = len(expected_result)
+ len_d = len(dst_data)
+ expected_result = expected_result[len_e - Ncmp:]
+ dst_data = dst_data[len_d - Ncmp:]
+
+ #for e,d in zip(expected_result, dst_data):
+ # print e, d
+
+ self.assertComplexTuplesAlmostEqual (expected_result, dst_data, 1)
+
+
+if __name__ == '__main__':
+ gr_unittest.run(test_pfb_clock_sync, "test_pfb_clock_sync.xml")
diff --git a/gr-digital/python/qa_pn_correlator_cc.py b/gr-digital/python/qa_pn_correlator_cc.py
new file mode 100755
index 0000000000..377bef5feb
--- /dev/null
+++ b/gr-digital/python/qa_pn_correlator_cc.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+#
+# Copyright 2007,2010,2012 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+from gnuradio import gr, gr_unittest
+import digital_swig as digital
+
+class test_pn_correlator_cc(gr_unittest.TestCase):
+
+ def setUp(self):
+ self.tb = gr.top_block ()
+
+ def tearDown(self):
+ self.tb = None
+
+ def test_000_make(self):
+ c = digital.pn_correlator_cc(10)
+
+ def test_001_correlate(self):
+ degree = 10
+ length = 2**degree-1
+ src = digital.glfsr_source_f(degree)
+ head = gr.head(gr.sizeof_float, length*length)
+ f2c = gr.float_to_complex()
+ corr = digital.pn_correlator_cc(degree)
+ dst = gr.vector_sink_c()
+ self.tb.connect(src, head, f2c, corr, dst)
+ self.tb.run()
+ data = dst.data()
+ self.assertEqual(data[-1], (1.0+0j))
+
+if __name__ == '__main__':
+ gr_unittest.run(test_pn_correlator_cc, "test_pn_correlator_cc.xml")
diff --git a/gr-digital/python/qa_probe_density.py b/gr-digital/python/qa_probe_density.py
new file mode 100755
index 0000000000..c5b7e0e7c2
--- /dev/null
+++ b/gr-digital/python/qa_probe_density.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python
+#
+# Copyright 2012 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+from gnuradio import gr, gr_unittest
+import digital_swig as digital
+
+class test_probe_density(gr_unittest.TestCase):
+
+ def setUp(self):
+ self.tb = gr.top_block()
+
+ def tearDown(self):
+ self.tb = None
+
+ def test_001(self):
+ src_data = [0, 1, 0, 1]
+ expected_data = 1
+ src = gr.vector_source_b (src_data)
+ op = digital.probe_density_b(1)
+ self.tb.connect (src, op)
+ self.tb.run ()
+
+ result_data = op.density()
+ self.assertEqual (expected_data, result_data)
+
+
+ def test_002(self):
+ src_data = [1, 1, 1, 1]
+ expected_data = 1
+ src = gr.vector_source_b (src_data)
+ op = digital.probe_density_b(0.01)
+ self.tb.connect (src, op)
+ self.tb.run ()
+
+ result_data = op.density()
+ self.assertEqual (expected_data, result_data)
+
+ def test_003(self):
+ src_data = [0, 1, 0, 1, 0, 1, 0, 1, 0, 1]
+ expected_data = 0.95243
+ src = gr.vector_source_b (src_data)
+ op = digital.probe_density_b(0.01)
+ self.tb.connect (src, op)
+ self.tb.run ()
+
+ result_data = op.density()
+ print result_data
+ self.assertAlmostEqual (expected_data, result_data, 5)
+
+if __name__ == '__main__':
+ gr_unittest.run(test_probe_density, "test_probe_density.xml")
+
diff --git a/gr-digital/python/qa_scrambler.py b/gr-digital/python/qa_scrambler.py
new file mode 100755
index 0000000000..f5bd612429
--- /dev/null
+++ b/gr-digital/python/qa_scrambler.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+#
+# Copyright 2008,2010,2012 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+from gnuradio import gr, gr_unittest
+import digital_swig as digital
+
+class test_scrambler(gr_unittest.TestCase):
+
+ def setUp (self):
+ self.tb = gr.top_block()
+
+ def tearDown(self):
+ self.tb = None
+
+ def test_scrambler_descrambler(self):
+ src_data = (1,)*1000
+ src = gr.vector_source_b(src_data, False)
+ scrambler = digital.scrambler_bb(0x8a, 0x7F, 7) # CCSDS 7-bit scrambler
+ descrambler = digital.descrambler_bb(0x8a, 0x7F, 7)
+ dst = gr.vector_sink_b()
+ self.tb.connect(src, scrambler, descrambler, dst)
+ self.tb.run()
+ self.assertEqual(tuple(src_data[:-8]), dst.data()[8:]) # skip garbage during synchronization
+
+ def test_additive_scrambler(self):
+ src_data = (1,)*1000
+ src = gr.vector_source_b(src_data, False)
+ scrambler = digital.additive_scrambler_bb(0x8a, 0x7f, 7)
+ descrambler = digital.additive_scrambler_bb(0x8a, 0x7f, 7)
+ dst = gr.vector_sink_b()
+ self.tb.connect(src, scrambler, descrambler, dst)
+ self.tb.run()
+ self.assertEqual(src_data, dst.data())
+
+ def test_additive_scrambler_reset(self):
+ src_data = (1,)*1000
+ src = gr.vector_source_b(src_data, False)
+ scrambler = digital.additive_scrambler_bb(0x8a, 0x7f, 7, 100)
+ descrambler = digital.additive_scrambler_bb(0x8a, 0x7f, 7, 100)
+ dst = gr.vector_sink_b()
+ self.tb.connect(src, scrambler, descrambler, dst)
+ self.tb.run()
+ self.assertEqual(src_data, dst.data())
+
+if __name__ == '__main__':
+ gr_unittest.run(test_scrambler, "test_scrambler.xml")
diff --git a/gr-digital/python/qa_simple_framer.py b/gr-digital/python/qa_simple_framer.py
new file mode 100755
index 0000000000..09b2d329b2
--- /dev/null
+++ b/gr-digital/python/qa_simple_framer.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+#
+# Copyright 2004,2007,2010,2012 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+from gnuradio import gr, gr_unittest
+import digital_swig as digital
+import math
+
+class test_simple_framer (gr_unittest.TestCase):
+
+ def setUp (self):
+ self.tb = gr.top_block ()
+
+ def tearDown (self):
+ self.tb = None
+
+ def test_simple_framer_001 (self):
+ src_data = (0x00, 0x11, 0x22, 0x33,
+ 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xaa, 0xbb,
+ 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)
+
+ src = gr.vector_source_b (src_data)
+ op = digital.simple_framer (4)
+ dst = gr.vector_sink_b ()
+ self.tb.connect (src, op)
+ self.tb.connect (op, dst)
+ self.tb.run ()
+ result_data = dst.data ()
+ self.assertEqual (expected_result, result_data)
+
+
+if __name__ == '__main__':
+ gr_unittest.run(test_simple_framer, "test_simple_framer.xml")
+