summaryrefslogtreecommitdiff
path: root/gr-digital/python
diff options
context:
space:
mode:
Diffstat (limited to 'gr-digital/python')
-rw-r--r--gr-digital/python/Makefile.am1
-rw-r--r--gr-digital/python/__init__.py1
-rw-r--r--gr-digital/python/generic_mod_demod.py23
-rw-r--r--gr-digital/python/gmsk.py106
-rwxr-xr-xgr-digital/python/qa_constellation.py11
-rwxr-xr-xgr-digital/python/qa_constellation_receiver.py12
-rwxr-xr-xgr-digital/python/qa_cpm.py91
-rwxr-xr-x[-rw-r--r--]gr-digital/python/qa_crc32.py0
-rwxr-xr-x[-rw-r--r--]gr-digital/python/qa_fll_band_edge.py0
-rwxr-xr-x[-rw-r--r--]gr-digital/python/qa_lms_equalizer.py0
-rwxr-xr-x[-rw-r--r--]gr-digital/python/qa_mpsk_receiver.py26
-rw-r--r--gr-digital/python/qpsk.py67
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)