diff options
Diffstat (limited to 'gr-digital/python')
-rw-r--r-- | gr-digital/python/Makefile.am | 1 | ||||
-rw-r--r-- | gr-digital/python/__init__.py | 1 | ||||
-rw-r--r-- | gr-digital/python/generic_mod_demod.py | 23 | ||||
-rw-r--r-- | gr-digital/python/gmsk.py | 106 | ||||
-rwxr-xr-x | gr-digital/python/qa_constellation.py | 11 | ||||
-rwxr-xr-x | gr-digital/python/qa_constellation_receiver.py | 12 | ||||
-rwxr-xr-x | gr-digital/python/qa_cpm.py | 91 | ||||
-rwxr-xr-x[-rw-r--r--] | gr-digital/python/qa_crc32.py | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | gr-digital/python/qa_fll_band_edge.py | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | gr-digital/python/qa_lms_equalizer.py | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | gr-digital/python/qa_mpsk_receiver.py | 26 | ||||
-rw-r--r-- | gr-digital/python/qpsk.py | 67 |
12 files changed, 238 insertions, 100 deletions
diff --git a/gr-digital/python/Makefile.am b/gr-digital/python/Makefile.am index 6c61002f1..a33e4963d 100644 --- a/gr-digital/python/Makefile.am +++ b/gr-digital/python/Makefile.am @@ -35,6 +35,7 @@ noinst_PYTHON = \ qa_binary_slicer_fb.py \ qa_clock_recovery_mm.py \ qa_cma_equalizer.py \ + qa_cpm.py \ qa_constellation.py \ qa_constellation_receiver.py \ qa_constellation_decoder_cb.py \ diff --git a/gr-digital/python/__init__.py b/gr-digital/python/__init__.py index 4046f7faf..7173fa09d 100644 --- a/gr-digital/python/__init__.py +++ b/gr-digital/python/__init__.py @@ -26,6 +26,7 @@ from psk2 import * from bpsk import * from qpsk import * from qam import * +from gmsk import * from pkt import * from packet_utils import * from crc import * diff --git a/gr-digital/python/generic_mod_demod.py b/gr-digital/python/generic_mod_demod.py index da8e2cfd9..b1986512f 100644 --- a/gr-digital/python/generic_mod_demod.py +++ b/gr-digital/python/generic_mod_demod.py @@ -54,7 +54,7 @@ def add_common_options(parser): Sets options common to both modulator and demodulator. """ parser.add_option("-p", "--constellation-points", type="int", default=_def_constellation_points, - help="set the number of constellation points (must be a power of 2 (power of 4 for QAM) [default=%default]") + help="set the number of constellation points (must be a power of 2 for psk, power of 4 for QAM) [default=%default]") parser.add_option("", "--non-differential", action="store_true", dest="differential", default=False, help="do not use differential encoding [default=%default]") @@ -120,7 +120,7 @@ class generic_mod(gr.hier_block2): self.bytes2chunks = \ gr.packed_to_unpacked_bb(self.bits_per_symbol(), gr.GR_MSB_FIRST) - if self._constellation.apply_pre_diff_code(): + if gray_coded == True: self.symbol_mapper = gr.map_bb(self._constellation.pre_diff_code()) if differential: @@ -142,7 +142,7 @@ class generic_mod(gr.hier_block2): # Connect blocks = [self, self.bytes2chunks] - if self._constellation.apply_pre_diff_code(): + if gray_coded == True: blocks.append(self.symbol_mapper) if differential: blocks.append(self.diffenc) @@ -211,6 +211,7 @@ class generic_demod(gr.hier_block2): samples_per_symbol=_def_samples_per_symbol, differential=_def_differential, excess_bw=_def_excess_bw, + gray_coded=True, freq_bw=_def_freq_bw, timing_bw=_def_timing_bw, phase_bw=_def_phase_bw, @@ -228,9 +229,11 @@ class generic_demod(gr.hier_block2): @type samples_per_symbol: float @param excess_bw: Root-raised cosine filter excess bandwidth @type excess_bw: float + @param gray_coded: turn gray coding on/off + @type gray_coded: bool @param freq_bw: loop filter lock-in bandwidth @type freq_bw: float - @param timing_bw: timing recoery loop lock-in bandwidth + @param timing_bw: timing recovery loop lock-in bandwidth @type timing_bw: float @param phase_bw: phase recovery loop bandwidth @type phase_bw: float @@ -265,8 +268,9 @@ class generic_demod(gr.hier_block2): self.agc = gr.agc2_cc(0.6e-1, 1e-3, 1, 1, 100) # Frequency correction + fll_ntaps = 55 self.freq_recov = digital_swig.fll_band_edge_cc(self._samples_per_symbol, self._excess_bw, - ntaps, self._freq_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, @@ -280,12 +284,12 @@ class generic_demod(gr.hier_block2): self.receiver = digital_swig.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) - if self._constellation.apply_pre_diff_code(): + if gray_coded: self.symbol_mapper = gr.map_bb( mod_codes.invert_code(self._constellation.pre_diff_code())) @@ -297,9 +301,10 @@ class generic_demod(gr.hier_block2): if log: self._setup_logging() - + # Connect and Initialize base class - blocks = [self, self.agc, self.freq_recov, self.time_recov, self.receiver] + blocks = [self, self.agc, self.freq_recov, + self.time_recov, self.receiver] if differential: blocks.append(self.diffdec) if self._constellation.apply_pre_diff_code(): diff --git a/gr-digital/python/gmsk.py b/gr-digital/python/gmsk.py index 3b6c016a0..ba122821e 100644 --- a/gr-digital/python/gmsk.py +++ b/gr-digital/python/gmsk.py @@ -25,7 +25,9 @@ # See gnuradio-examples/python/digital for examples from gnuradio import gr -from gnuradio import modulation_utils +import digital_swig +import modulation_utils2 + from math import pi import numpy from pprint import pprint @@ -37,11 +39,9 @@ _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 - +# Symbol timing recovery +_def_timing_bw = 2*pi/100.0 +_def_timing_max_dev = 1.5 # ///////////////////////////////////////////////////////////////////////////// # GMSK modulator @@ -79,7 +79,8 @@ class gmsk_mod(gr.hier_block2): self._bt = bt 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,)) + 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 @@ -128,11 +129,11 @@ class gmsk_mod(gr.hier_block2): def _setup_logging(self): print "Modulation logging turned on." self.connect(self.nrz, - gr.file_sink(gr.sizeof_float, "nrz.dat")) + gr.file_sink(gr.sizeof_float, "tx_gmsk_nrz.32f")) self.connect(self.gaussian_filter, - gr.file_sink(gr.sizeof_float, "gaussian_filter.dat")) + gr.file_sink(gr.sizeof_float, "tx_gmsk_gaussian_filter.32f")) self.connect(self.fmmod, - gr.file_sink(gr.sizeof_gr_complex, "fmmod.dat")) + gr.file_sink(gr.sizeof_gr_complex, "tx_gmsk_fmmod.32fc")) def add_options(parser): @@ -148,7 +149,7 @@ class gmsk_mod(gr.hier_block2): """ Given command line options, create dictionary suitable for passing to __init__ """ - return modulation_utils.extract_kwargs_from_options(gmsk_mod.__init__, + return modulation_utils2.extract_kwargs_from_options(gmsk_mod.__init__, ('self',), options) extract_kwargs_from_options=staticmethod(extract_kwargs_from_options) @@ -162,10 +163,8 @@ class gmsk_demod(gr.hier_block2): def __init__(self, samples_per_symbol=_def_samples_per_symbol, - gain_mu=_def_gain_mu, - mu=_def_mu, - omega_relative_limit=_def_omega_relative_limit, - freq_error=_def_freq_error, + bt=_def_bt, + timing_bw=_def_timing_bw, verbose=_def_verbose, log=_def_log): """ @@ -177,21 +176,12 @@ class gmsk_demod(gr.hier_block2): @param samples_per_symbol: samples per baud @type samples_per_symbol: integer + @param timing_bw: timing recovery loop lock-in bandwidth + @type timing_bw: float @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, "gmsk_demod", @@ -199,33 +189,31 @@ class gmsk_demod(gr.hier_block2): 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._bt = bt + self._timing_bw = timing_bw + self._timing_max_dev= _def_timing_max_dev 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 = gr.clock_recovery_mm_ff(self._omega, self._gain_omega, - self._mu, self._gain_mu, - self._omega_relative_limit) - + nfilts = 32 + ntaps = 11 * int(self._samples_per_symbol*nfilts) + taps = gr.firdes.gaussian(nfilts, + nfilts*self._samples_per_symbol, + self._bt, ntaps) + self.clock_recovery = \ + gr.pfb_clock_sync_fff(self._samples_per_symbol, + self._timing_bw, taps, + nfilts, nfilts//2, self._timing_max_dev) + # slice the floats at 0, outputting 1 bit (the LSB of the output byte) per sample - self.slicer = gr.binary_slicer_fb() + self.slicer = digital_swig.binary_slicer_fb() if verbose: self._print_verbage() @@ -245,48 +233,38 @@ class gmsk_demod(gr.hier_block2): 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 + print "bits per symbol: %d" % self.bits_per_symbol() + print "Bandwidth-Time Prod: %f" % self._bw + print "Timing bandwidth: %.2e" % self._timing_bw def _setup_logging(self): print "Demodulation logging turned on." self.connect(self.fmdemod, - gr.file_sink(gr.sizeof_float, "fmdemod.dat")) + gr.file_sink(gr.sizeof_float, "rx_gmsk_fmdemod.32f")) self.connect(self.clock_recovery, - gr.file_sink(gr.sizeof_float, "clock_recovery.dat")) + gr.file_sink(gr.sizeof_float, "rx_gmsk_clock_recovery.32f")) self.connect(self.slicer, - gr.file_sink(gr.sizeof_char, "slicer.dat")) + gr.file_sink(gr.sizeof_char, "rx_gmsk_slicer.8b")) def add_options(parser): """ Adds GMSK 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] (GMSK/PSK)") - parser.add_option("", "--mu", type="float", default=_def_mu, - help="M&M clock recovery mu [default=%default] (GMSK/PSK)") - parser.add_option("", "--omega-relative-limit", type="float", default=_def_omega_relative_limit, - help="M&M clock recovery omega relative limit [default=%default] (GMSK/PSK)") - parser.add_option("", "--freq-error", type="float", default=_def_freq_error, - help="M&M clock recovery frequency error [default=%default] (GMSK)") + parser.add_option("", "--timing-bw", type="float", default=_def_timing_bw, + help="set timing symbol sync loop gain lock-in bandwidth [default=%default]") 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(gmsk_demod.__init__, - ('self',), options) + return modulation_utils2.extract_kwargs_from_options(gmsk_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('gmsk', gmsk_mod) -modulation_utils.add_type_1_demod('gmsk', gmsk_demod) +modulation_utils2.add_type_1_mod('gmsk', gmsk_mod) +modulation_utils2.add_type_1_demod('gmsk', gmsk_demod) diff --git a/gr-digital/python/qa_constellation.py b/gr-digital/python/qa_constellation.py index 02afb8d2d..264ff7de6 100755 --- a/gr-digital/python/qa_constellation.py +++ b/gr-digital/python/qa_constellation.py @@ -70,10 +70,8 @@ tested_constellation_info = ( 'mod_code': tested_mod_codes, }, True, None), (digital_swig.constellation_bpsk, {}, True, None), - # No differential testing for qpsk because it is gray-coded. - # This is because soft decision making is simpler if we can assume - # gray coding. (digital_swig.constellation_qpsk, {}, False, None), + (digital_swig.constellation_dqpsk, {}, True, None), (digital_swig.constellation_8psk, {}, False, None), (twod_constell, {}, True, None), (threed_constell, {}, True, None), @@ -143,8 +141,8 @@ class test_constellation (gr_unittest.TestCase): 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. + # 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.") gr.hier_block2.__init__(self, "mod_demod", @@ -174,7 +172,8 @@ class mod_demod(gr.hier_block2): if self.differential: self.blocks.append(gr.diff_encoder_bb(arity)) # Convert to constellation symbols. - self.blocks.append(gr.chunks_to_symbols_bc(self.constellation.points(), self.constellation.dimensionality())) + self.blocks.append(gr.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: diff --git a/gr-digital/python/qa_constellation_receiver.py b/gr-digital/python/qa_constellation_receiver.py index 79dded8ba..25107e4a7 100755 --- a/gr-digital/python/qa_constellation_receiver.py +++ b/gr-digital/python/qa_constellation_receiver.py @@ -29,6 +29,7 @@ from generic_mod_demod import generic_mod, generic_demod from qa_constellation import tested_constellations, twod_constell +import math # Set a seed so that if errors turn up they are reproducible. # 1234 fails @@ -47,11 +48,8 @@ FREQUENCY_OFFSET = 0.01 TIMING_OFFSET = 1.0 # RECEIVER PARAMETERS -# Increased from normal default of 0.01 to speed things up. -FREQ_ALPHA = 0.02 -# Decreased from normal default of 0.1 is required for the constellations -# with smaller point separations. -PHASE_ALPHA = 0.02 +FREQ_BW = 2*math.pi/100.0 +PHASE_BW = 2*math.pi/100.0 class test_constellation_receiver (gr_unittest.TestCase): @@ -127,8 +125,8 @@ class rec_test_tb (gr.top_block): channel = gr.channel_model(NOISE_VOLTAGE, FREQUENCY_OFFSET, TIMING_OFFSET) # Receiver Blocks demod = generic_demod(constellation, differential=differential, - freq_alpha=FREQ_ALPHA, - phase_alpha=PHASE_ALPHA) + freq_bw=FREQ_BW, + phase_bw=PHASE_BW) self.dst = gr.vector_sink_b() self.connect(src, packer, mod, channel, demod, self.dst) diff --git a/gr-digital/python/qa_cpm.py b/gr-digital/python/qa_cpm.py new file mode 100755 index 000000000..12a84c76c --- /dev/null +++ b/gr-digital/python/qa_cpm.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python +# +# Copyright 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 +import numpy + +class test_cpm(gr_unittest.TestCase): + + def setUp (self): + self.tb = gr.top_block () + + def tearDown (self): + self.tb = None + + def do_check_phase_shift(self, type, name): + sps = 2 + L = 1 + in_bits = (1,) * 20 + src = gr.vector_source_b(in_bits, False) + cpm = digital_swig.cpmmod_bc(type, 0.5, sps, L) + arg = gr.complex_to_arg() + sink = gr.vector_sink_f() + + self.tb.connect(src, cpm, arg, sink) + self.tb.run() + + 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) + + def test_001_lrec(self): + self.do_check_phase_shift(gr.cpm.LRC, 'LREC') + + def test_001_lrc(self): + self.do_check_phase_shift(gr.cpm.LRC, 'LRC') + + def test_001_lsrc(self): + self.do_check_phase_shift(gr.cpm.LSRC, 'LSRC') + + def test_001_ltfm(self): + self.do_check_phase_shift(gr.cpm.TFM, 'TFM') + + def test_001_lgmsk(self): + sps = 2 + L = 5 + bt = 0.3 + in_bits = (1,) * 20 + src = gr.vector_source_b(in_bits, False) + gmsk = digital_swig.gmskmod_bc(sps, bt, L) + arg = gr.complex_to_arg() + sink = gr.vector_sink_f() + + self.tb.connect(src, gmsk, arg, sink) + self.tb.run() + + 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") + + def test_phase_response(self): + phase_response = gr.cpm.phase_response(gr.cpm.LREC, 2, 4) + self.assertAlmostEqual(numpy.sum(phase_response), 1) + + +if __name__ == '__main__': + gr_unittest.run(test_cpm, "test_cpm.xml") + diff --git a/gr-digital/python/qa_crc32.py b/gr-digital/python/qa_crc32.py index f86813f3f..f86813f3f 100644..100755 --- a/gr-digital/python/qa_crc32.py +++ b/gr-digital/python/qa_crc32.py diff --git a/gr-digital/python/qa_fll_band_edge.py b/gr-digital/python/qa_fll_band_edge.py index 088eb2b68..088eb2b68 100644..100755 --- a/gr-digital/python/qa_fll_band_edge.py +++ b/gr-digital/python/qa_fll_band_edge.py diff --git a/gr-digital/python/qa_lms_equalizer.py b/gr-digital/python/qa_lms_equalizer.py index 025c785aa..025c785aa 100644..100755 --- a/gr-digital/python/qa_lms_equalizer.py +++ b/gr-digital/python/qa_lms_equalizer.py diff --git a/gr-digital/python/qa_mpsk_receiver.py b/gr-digital/python/qa_mpsk_receiver.py index 7e9a76e1f..6531e59f7 100644..100755 --- a/gr-digital/python/qa_mpsk_receiver.py +++ b/gr-digital/python/qa_mpsk_receiver.py @@ -36,8 +36,7 @@ class test_mpsk_receiver(gr_unittest.TestCase): # Test BPSK sync M = 2 theta = 0 - alpha = 0.1 - beta = 0.25*alpha*alpha + loop_bw = cmath.pi/100.0 fmin = -0.5 fmax = 0.5 mu = 0.25 @@ -46,7 +45,7 @@ class test_mpsk_receiver(gr_unittest.TestCase): gain_omega = 0.001 omega_rel = 0.001 - self.test = digital_swig.mpsk_receiver_cc(M, theta, alpha, beta, + self.test = digital_swig.mpsk_receiver_cc(M, theta, loop_bw, fmin, fmax, mu, gain_mu, omega, gain_omega, omega_rel) @@ -68,8 +67,8 @@ class test_mpsk_receiver(gr_unittest.TestCase): expected_result = expected_result[len_e - Ncmp:] dst_data = dst_data[len_d - Ncmp:] - #print expected_result - #print dst_data + #for e,d in zip(expected_result, dst_data): + # print e, d self.assertComplexTuplesAlmostEqual (expected_result, dst_data, 1) @@ -78,8 +77,7 @@ class test_mpsk_receiver(gr_unittest.TestCase): # Test QPSK sync M = 4 theta = 0 - alpha = 0.1 - beta = 0.25*alpha*alpha + loop_bw = 2*cmath.pi/100.0 fmin = -0.5 fmax = 0.5 mu = 0.25 @@ -88,11 +86,11 @@ class test_mpsk_receiver(gr_unittest.TestCase): gain_omega = 0.001 omega_rel = 0.001 - self.test = digital_swig.mpsk_receiver_cc(M, theta, alpha, beta, + self.test = digital_swig.mpsk_receiver_cc(M, theta, loop_bw, fmin, fmax, mu, gain_mu, omega, gain_omega, omega_rel) - + data = 1000*[complex( 0.707, 0.707), complex( 0.707, 0.707), complex(-0.707, 0.707), complex(-0.707, 0.707), complex(-0.707, -0.707), complex(-0.707, -0.707), @@ -103,8 +101,8 @@ class test_mpsk_receiver(gr_unittest.TestCase): self.tb.connect(self.src, self.test, self.snk) self.tb.run() - expected_result = 1000*[complex(1.2, 0), complex(0, 1.2), - complex(-1.2, 0), complex(0, -1.2)] + expected_result = 1000*[complex(0, -1.0), complex(1.0, 0), + complex(0, 1.0), complex(-1.0, 0)] dst_data = self.snk.data() # Only compare last Ncmp samples @@ -114,9 +112,9 @@ class test_mpsk_receiver(gr_unittest.TestCase): expected_result = expected_result[len_e - Ncmp:] dst_data = dst_data[len_d - Ncmp:] - #print expected_result - #print dst_data - + #for e,d in zip(expected_result, dst_data): + # print e, d + self.assertComplexTuplesAlmostEqual (expected_result, dst_data, 1) if __name__ == '__main__': diff --git a/gr-digital/python/qpsk.py b/gr-digital/python/qpsk.py index 76e5df270..481b7cb5b 100644 --- a/gr-digital/python/qpsk.py +++ b/gr-digital/python/qpsk.py @@ -100,10 +100,77 @@ class qpsk_demod(generic_demod): super(qpsk_demod, self).__init__(constellation=constellation, *args, **kwargs) + + +# ///////////////////////////////////////////////////////////////////////////// +# DQPSK constellation +# ///////////////////////////////////////////////////////////////////////////// + +def dqpsk_constellation(m=_def_constellation_points): + if m != _def_constellation_points: + raise ValueError("DQPSK can only have 4 constellation points.") + return digital_swig.constellation_dqpsk() + +# ///////////////////////////////////////////////////////////////////////////// +# DQPSK modulator +# ///////////////////////////////////////////////////////////////////////////// + +class dqpsk_mod(generic_mod): + + def __init__(self, constellation_points=_def_constellation_points, + gray_coded=_def_gray_coded, + differential=True, *args, **kwargs): + """ + Hierarchical block for RRC-filtered DQPSK modulation. + + The input is a byte stream (unsigned char) and the + output is the complex modulated signal at baseband. + + See generic_mod block for list of parameters. + """ + + constellation_points = _def_constellation_points + constellation = digital_swig.constellation_dqpsk() + if constellation_points != 4: + raise ValueError('Number of constellation points must be 4 for DQPSK.') + super(dqpsk_mod, self).__init__(constellation=constellation, + gray_coded=gray_coded, + differential=True, + *args, **kwargs) + +# ///////////////////////////////////////////////////////////////////////////// +# DQPSK demodulator +# +# ///////////////////////////////////////////////////////////////////////////// + +class dqpsk_demod(generic_demod): + + def __init__(self, constellation_points=_def_constellation_points, + differential=True, *args, **kwargs): + + """ + Hierarchical block for RRC-filtered DQPSK modulation. + + The input is a byte stream (unsigned char) and the + output is the complex modulated signal at baseband. + + See generic_demod block for list of parameters. + """ + constellation_points = _def_constellation_points + constellation = digital_swig.constellation_dqpsk() + if constellation_points != 4: + raise ValueError('Number of constellation points must be 4 for DQPSK.') + super(dqpsk_demod, self).__init__(constellation=constellation, + differential=True, + *args, **kwargs) + # # Add these to the mod/demod registry # modulation_utils2.add_type_1_mod('qpsk', qpsk_mod) modulation_utils2.add_type_1_demod('qpsk', qpsk_demod) modulation_utils2.add_type_1_constellation('qpsk', qpsk_constellation) +modulation_utils2.add_type_1_mod('dqpsk', dqpsk_mod) +modulation_utils2.add_type_1_demod('dqpsk', dqpsk_demod) +modulation_utils2.add_type_1_constellation('dqpsk', dqpsk_constellation) |