summaryrefslogtreecommitdiff
path: root/gr-digital
diff options
context:
space:
mode:
Diffstat (limited to 'gr-digital')
-rw-r--r--gr-digital/lib/Makefile.am29
-rw-r--r--gr-digital/lib/digital_constellation_decoder_cb.cc77
-rw-r--r--gr-digital/lib/digital_constellation_decoder_cb.h64
-rw-r--r--gr-digital/lib/digital_constellation_receiver_cb.cc131
-rw-r--r--gr-digital/lib/digital_constellation_receiver_cb.h149
-rw-r--r--gr-digital/python/Makefile.am1
-rw-r--r--gr-digital/python/generic_mod_demod.py4
-rwxr-xr-xgr-digital/python/qa_constellation.py205
-rwxr-xr-xgr-digital/python/qa_constellation_receiver.py133
-rwxr-xr-x[-rw-r--r--]gr-digital/python/qa_costas_loop_cc.py0
-rw-r--r--gr-digital/python/utils/Makefile.am9
-rw-r--r--gr-digital/python/utils/run_tests.in11
-rw-r--r--gr-digital/swig/Makefile.am16
-rw-r--r--gr-digital/swig/digital_constellation.i2
-rw-r--r--gr-digital/swig/digital_constellation_decoder_cb.i38
-rw-r--r--gr-digital/swig/digital_constellation_receiver_cb.i47
-rw-r--r--gr-digital/swig/digital_swig.i4
17 files changed, 883 insertions, 37 deletions
diff --git a/gr-digital/lib/Makefile.am b/gr-digital/lib/Makefile.am
index 5d7fdecbf..560d242ad 100644
--- a/gr-digital/lib/Makefile.am
+++ b/gr-digital/lib/Makefile.am
@@ -24,22 +24,27 @@ include $(top_srcdir)/Makefile.common
AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(PYTHON_CPPFLAGS) $(WITH_INCLUDES)
# These headers get installed in ${prefix}/include/gnuradio
-grinclude_HEADERS = \
- digital_constellation.h \
- digital_costas_loop_cc.h \
- digital_cma_equalizer_cc.h \
- digital_lms_dd_equalizer_cc.h \
- digital_kurtotic_equalizer_cc.h \
+grinclude_HEADERS = \
+ digital_constellation.h \
+ digital_constellation_receiver_cb.h \
+ digital_constellation_decoder_cb.h \
+ digital_costas_loop_cc.h \
+ digital_cma_equalizer_cc.h \
+ digital_lms_dd_equalizer_cc.h \
+ digital_kurtotic_equalizer_cc.h \
digital_metric_type.h
lib_LTLIBRARIES = libgnuradio-digital.la
-libgnuradio_digital_la_SOURCES = \
- digital_constellation.cc \
- digital_costas_loop_cc.cc \
- digital_cma_equalizer_cc.cc \
- digital_lms_dd_equalizer_cc.cc \
- digital_kurtotic_equalizer_cc.cc
+libgnuradio_digital_la_SOURCES = \
+ digital_constellation.cc \
+ digital_constellation_receiver_cb.h \
+ digital_constellation_decoder_cb.h \
+ digital_costas_loop_cc.cc \
+ digital_cma_equalizer_cc.cc \
+ digital_lms_dd_equalizer_cc.cc \
+ digital_kurtotic_equalizer_cc.cc \
+ digital_constellation_receiver_cb.h
libgnuradio_digital_la_LIBADD = \
$(GNURADIO_CORE_LA)
diff --git a/gr-digital/lib/digital_constellation_decoder_cb.cc b/gr-digital/lib/digital_constellation_decoder_cb.cc
new file mode 100644
index 000000000..8ac34f1d6
--- /dev/null
+++ b/gr-digital/lib/digital_constellation_decoder_cb.cc
@@ -0,0 +1,77 @@
+/* -*- c++ -*- */
+/*
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <digital_constellation_decoder_cb.h>
+#include <digital_constellation.h>
+#include <gr_io_signature.h>
+#include <iostream>
+
+digital_constellation_decoder_cb_sptr
+digital_make_constellation_decoder_cb (digital_constellation_sptr constellation)
+{
+ return digital_constellation_decoder_cb_sptr
+ (new digital_constellation_decoder_cb(constellation));
+}
+
+digital_constellation_decoder_cb::
+digital_constellation_decoder_cb (digital_constellation_sptr constellation)
+ : gr_block ("constellation_decoder_cb",
+ gr_make_io_signature (1, 1, sizeof (gr_complex)),
+ gr_make_io_signature (1, 1, sizeof (unsigned char))),
+ d_constellation(constellation),
+ d_dim(constellation->dimensionality())
+{
+ set_relative_rate (1.0 / ((double) d_dim));
+}
+
+void
+digital_constellation_decoder_cb::forecast (int noutput_items,
+ gr_vector_int &ninput_items_required)
+{
+ unsigned int input_required = noutput_items * d_dim;
+
+ unsigned ninputs = ninput_items_required.size();
+ for (unsigned int i = 0; i < ninputs; i++)
+ ninput_items_required[i] = input_required;
+}
+
+
+int
+digital_constellation_decoder_cb::general_work (int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+ gr_complex const *in = (const gr_complex *) input_items[0];
+ unsigned char *out = (unsigned char *) output_items[0];
+
+ for(int i = 0; i < noutput_items; i++){
+ out[i] = d_constellation->decision_maker(&(in[i*d_dim]));
+ }
+
+ consume_each (noutput_items * d_dim);
+ return noutput_items;
+}
diff --git a/gr-digital/lib/digital_constellation_decoder_cb.h b/gr-digital/lib/digital_constellation_decoder_cb.h
new file mode 100644
index 000000000..420ae5c74
--- /dev/null
+++ b/gr-digital/lib/digital_constellation_decoder_cb.h
@@ -0,0 +1,64 @@
+/* -*- c++ -*- */
+/*
+ * 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.
+ */
+
+#ifndef INCLUDED_DIGITAL_CONSTELLATION_DECODER_CB_H
+#define INCLUDED_DIGITAL_CONSTELLATION_DECODER_CB_H
+
+#include <gr_block.h>
+#include <digital_constellation.h>
+#include <vector>
+
+class digital_constellation_decoder_cb;
+typedef boost::shared_ptr<digital_constellation_decoder_cb>digital_constellation_decoder_cb_sptr;
+
+digital_constellation_decoder_cb_sptr
+digital_make_constellation_decoder_cb (digital_constellation_sptr constellation);
+
+/*!
+ * \brief Constellation Decoder
+ * \ingroup coding_blk
+ *
+ */
+class digital_constellation_decoder_cb : public gr_block
+{
+
+ private:
+ digital_constellation_sptr d_constellation;
+ unsigned int d_dim;
+
+ friend digital_constellation_decoder_cb_sptr
+ gr_make_constellation_decoder_cb (digital_constellation_sptr constellation);
+
+ digital_constellation_decoder_cb (digital_constellation_sptr constellation);
+
+ public:
+
+ void forecast (int noutput_items,
+ gr_vector_int &ninput_items_required);
+
+ int general_work (int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+};
+
+#endif
diff --git a/gr-digital/lib/digital_constellation_receiver_cb.cc b/gr-digital/lib/digital_constellation_receiver_cb.cc
new file mode 100644
index 000000000..56385f11e
--- /dev/null
+++ b/gr-digital/lib/digital_constellation_receiver_cb.cc
@@ -0,0 +1,131 @@
+/* -*- c++ -*- */
+/*
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gr_io_signature.h>
+#include <gr_prefs.h>
+#include <digital_constellation_receiver_cb.h>
+#include <stdexcept>
+#include <gr_math.h>
+#include <gr_expj.h>
+
+
+#define M_TWOPI (2*M_PI)
+#define VERBOSE_MM 0 // Used for debugging symbol timing loop
+#define VERBOSE_COSTAS 0 // Used for debugging phase and frequency tracking
+
+// Public constructor
+
+digital_constellation_receiver_cb_sptr
+digital_make_constellation_receiver_cb(digital_constellation_sptr constell,
+ float alpha, float beta,
+ float fmin, float fmax)
+{
+ return gnuradio::get_initial_sptr(new digital_constellation_receiver_cb (constell,
+ alpha, beta,
+ fmin, fmax));
+}
+
+static int ios[] = {sizeof(char), sizeof(float), sizeof(float), sizeof(float)};
+static std::vector<int> iosig(ios, ios+sizeof(ios)/sizeof(int));
+digital_constellation_receiver_cb::digital_constellation_receiver_cb (digital_constellation_sptr constellation,
+ float alpha, float beta,
+ float fmin, float fmax)
+ : gr_block ("constellation_receiver_cb",
+ gr_make_io_signature (1, 1, sizeof (gr_complex)),
+ gr_make_io_signaturev (1, 4, iosig)),
+ d_constellation(constellation),
+ d_alpha(alpha), d_beta(beta), d_freq(0), d_max_freq(fmax), d_min_freq(fmin), d_phase(0),
+ d_current_const_point(0)
+{
+ if (d_constellation->dimensionality() != 1)
+ throw std::runtime_error ("This receiver only works with constellations of dimension 1.");
+}
+
+void
+digital_constellation_receiver_cb::phase_error_tracking(float phase_error)
+{
+ d_freq += d_beta*phase_error; // adjust frequency based on error
+ d_phase += d_freq + d_alpha*phase_error; // adjust phase based on error
+
+ // Make sure we stay within +-2pi
+ while(d_phase > M_TWOPI)
+ d_phase -= M_TWOPI;
+ while(d_phase < -M_TWOPI)
+ d_phase += M_TWOPI;
+
+ // Limit the frequency range
+ d_freq = gr_branchless_clip(d_freq, d_max_freq);
+
+#if VERBOSE_COSTAS
+ printf("cl: phase_error: %f phase: %f freq: %f sample: %f+j%f constellation: %f+j%f\n",
+ phase_error, d_phase, d_freq, sample.real(), sample.imag(),
+ d_constellation->points()[d_current_const_point].real(),
+ d_constellation->points()[d_current_const_point].imag());
+#endif
+}
+
+int
+digital_constellation_receiver_cb::general_work (int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+ const gr_complex *in = (const gr_complex *) input_items[0];
+ unsigned char *out = (unsigned char *) output_items[0];
+
+ int i=0;
+
+ float phase_error;
+ unsigned int sym_value;
+ gr_complex sample, nco;
+
+ float *out_err = 0, *out_phase = 0, *out_freq = 0;
+ if(output_items.size() == 4) {
+ out_err = (float *) output_items[1];
+ out_phase = (float *) output_items[2];
+ out_freq = (float *) output_items[3];
+ }
+
+ while((i < noutput_items) && (i < ninput_items[0])) {
+ sample = in[i];
+ nco = gr_expj(d_phase); // get the NCO value for derotating the current sample
+ sample = nco*sample; // get the downconverted symbol
+ sym_value = d_constellation->decision_maker_pe(&sample, &phase_error);
+ // phase_error = -arg(sample*conj(d_constellation->points()[sym_value]));
+ phase_error_tracking(phase_error); // corrects phase and frequency offsets
+ out[i] = sym_value;
+ if(output_items.size() == 4) {
+ out_err[i] = phase_error;
+ out_phase[i] = d_phase;
+ out_freq[i] = d_freq;
+ }
+ i++;
+ }
+
+ consume_each(i);
+ return i;
+}
+
diff --git a/gr-digital/lib/digital_constellation_receiver_cb.h b/gr-digital/lib/digital_constellation_receiver_cb.h
new file mode 100644
index 000000000..bf6fc51fa
--- /dev/null
+++ b/gr-digital/lib/digital_constellation_receiver_cb.h
@@ -0,0 +1,149 @@
+/* -*- c++ -*- */
+/*
+ * 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.
+ */
+
+#ifndef INCLUDED_DIGITAL_CONSTELLATION_RECEIVER_CB_H
+#define INCLUDED_DIGITAL_CONSTELLATION_RECEIVER_CB_H
+
+#include <gr_block.h>
+#include <digital_constellation.h>
+#include <gr_complex.h>
+#include <math.h>
+#include <fstream>
+
+class digital_constellation_receiver_cb;
+typedef boost::shared_ptr<digital_constellation_receiver_cb> digital_constellation_receiver_cb_sptr;
+
+// public constructor
+digital_constellation_receiver_cb_sptr
+digital_make_constellation_receiver_cb (digital_constellation_sptr constellation,
+ float alpha, float beta,
+ float fmin, float fmax);
+
+/*!
+ * \brief This block takes care of receiving generic modulated signals through phase, frequency, and symbol
+ * synchronization.
+ * \ingroup sync_blk
+ * \ingroup demod_blk
+ *
+ * This block takes care of receiving generic modulated signals through phase, frequency, and symbol
+ * synchronization. It performs carrier frequency and phase locking as well as symbol timing recovery.
+ *
+ * The phase and frequency synchronization are based on a Costas loop that finds the error of the incoming
+ * signal point compared to its nearest constellation point. The frequency and phase of the NCO are
+ * updated according to this error.
+ *
+ * The symbol synchronization is done using a modified Mueller and Muller circuit from the paper:
+ *
+ * G. R. Danesfahani, T.G. Jeans, "Optimisation of modified Mueller and Muller
+ * algorithm," Electronics Letters, Vol. 31, no. 13, 22 June 1995, pp. 1032 - 1033.
+ *
+ * This circuit interpolates the downconverted sample (using the NCO developed by the Costas loop)
+ * every mu samples, then it finds the sampling error based on this and the past symbols and the decision
+ * made on the samples. Like the phase error detector, there are optimized decision algorithms for BPSK
+ * and QPKS, but 8PSK uses another brute force computation against all possible symbols. The modifications
+ * to the M&M used here reduce self-noise.
+ *
+ */
+
+class digital_constellation_receiver_cb : public gr_block
+{
+ public:
+ int general_work (int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+
+
+ // Member function related to the phase/frequency tracking portion of the receiver
+ //! (CL) Returns the value for alpha (the phase gain term)
+ float alpha() const { return d_alpha; }
+
+ //! (CL) Returns the value of beta (the frequency gain term)
+ float beta() const { return d_beta; }
+
+ //! (CL) Returns the current value of the frequency of the NCO in the Costas loop
+ float freq() const { return d_freq; }
+
+ //! (CL) Returns the current value of the phase of the NCO in the Costal loop
+ float phase() const { return d_phase; }
+
+ //! (CL) Sets the value for alpha (the phase gain term)
+ void set_alpha(float alpha) { d_alpha = alpha; }
+
+ //! (CL) Setss the value of beta (the frequency gain term)
+ void set_beta(float beta) { d_beta = beta; }
+
+ //! (CL) Sets the current value of the frequency of the NCO in the Costas loop
+ void set_freq(float freq) { d_freq = freq; }
+
+ //! (CL) Setss the current value of the phase of the NCO in the Costal loop
+ void set_phase(float phase) { d_phase = phase; }
+
+
+protected:
+
+ /*!
+ * \brief Constructor to synchronize incoming M-PSK symbols
+ *
+ * \param constellation constellation of points for generic modulation
+ * \param alpha gain parameter to adjust the phase in the Costas loop (~0.01)
+ * \param beta gain parameter to adjust the frequency in the Costas loop (~alpha^2/4)
+ * \param fmin minimum normalized frequency value the loop can achieve
+ * \param fmax maximum normalized frequency value the loop can achieve
+ *
+ * The constructor also chooses which phase detector and decision maker to use in the
+ * work loop based on the value of M.
+ */
+ digital_constellation_receiver_cb (digital_constellation_sptr constellation,
+ float alpha, float beta,
+ float fmin, float fmax);
+
+ void phase_error_tracking(float phase_error);
+
+ private:
+ unsigned int d_M;
+
+ // Members related to carrier and phase tracking
+ float d_alpha;
+ float d_beta;
+ float d_freq, d_max_freq, d_min_freq;
+ float d_phase;
+
+ digital_constellation_sptr d_constellation;
+ unsigned int d_current_const_point;
+
+ //! delay line length.
+ static const unsigned int DLLEN = 8;
+
+ //! delay line plus some length for overflow protection
+ gr_complex d_dl[2*DLLEN] __attribute__ ((aligned(8)));
+
+ //! index to delay line
+ unsigned int d_dl_idx;
+
+ friend digital_constellation_receiver_cb_sptr
+ digital_make_constellation_receiver_cb (digital_constellation_sptr constell,
+ float alpha, float beta,
+ float fmin, float fmax);
+};
+
+#endif
diff --git a/gr-digital/python/Makefile.am b/gr-digital/python/Makefile.am
index b1d0d11d8..f4f72f8d8 100644
--- a/gr-digital/python/Makefile.am
+++ b/gr-digital/python/Makefile.am
@@ -25,6 +25,7 @@ TESTS =
EXTRA_DIST += run_tests.in
if PYTHON
+SUBDIRS = utils
TESTS += run_tests
digitaldir = $(grpythondir)/digital
diff --git a/gr-digital/python/generic_mod_demod.py b/gr-digital/python/generic_mod_demod.py
index 4b1819ed7..a85b21219 100644
--- a/gr-digital/python/generic_mod_demod.py
+++ b/gr-digital/python/generic_mod_demod.py
@@ -85,7 +85,7 @@ class generic_mod(gr.hier_block2):
output is the complex modulated signal at baseband.
@param constellation: determines the modulation type
- @type constellation: gnuradio.gr.gr_constellation
+ @type constellation: gnuradio.digital.gr_constellation
@param samples_per_symbol: samples per baud >= 2
@type samples_per_symbol: integer
@param excess_bw: Root-raised cosine filter excess bandwidth
@@ -219,7 +219,7 @@ class generic_demod(gr.hier_block2):
The output is a stream of bits packed 1 bit per byte (LSB)
@param constellation: determines the modulation type
- @type constellation: gnuradio.gr.gr_constellation
+ @type constellation: gnuradio.digital.gr_constellation
@param samples_per_symbol: samples per symbol >= 2
@type samples_per_symbol: float
@param excess_bw: Root-raised cosine filter excess bandwidth
diff --git a/gr-digital/python/qa_constellation.py b/gr-digital/python/qa_constellation.py
new file mode 100755
index 000000000..72b9e99bc
--- /dev/null
+++ b/gr-digital/python/qa_constellation.py
@@ -0,0 +1,205 @@
+#!/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.
+#
+
+import random
+from cmath import exp, pi, log
+
+from gnuradio import gr, gr_unittest, blks2
+from utils import mod_codes
+import digital_swig
+
+
+tested_mod_codes = (mod_codes.NO_CODE, mod_codes.GRAY_CODE)
+
+# A list of the constellations to test.
+# Each constellation is given by a 3-tuple.
+# First item is a function to generate the constellation
+# Second item is a dictionary of arguments for function with lists of
+# possible values.
+# Third item is whether differential encoding should be tested.
+# Fourth item is the name of the argument to constructor that specifices
+# whether differential encoding is used.
+
+def twod_constell():
+ """
+
+ """
+ points = ((1+0j), (0+1j),
+ (-1+0j), (0-1j))
+ rot_sym = 2
+ dim = 2
+ return gr.constellation_calcdist(points, [], rot_sym, dim)
+
+def threed_constell():
+ oned_points = ((1+0j), (0+1j), (-1+0j), (0-1j))
+ points = []
+ r4 = range(0, 4)
+ for ia in r4:
+ for ib in r4:
+ for ic in r4:
+ points += [oned_points[ia], oned_points[ib], oned_points[ic]]
+ rot_sym = 4
+ dim = 3
+ return gr.constellation_calcdist(points, [], rot_sym, dim)
+
+tested_constellation_info = (
+ (blks2.psk_constellation,
+ {'m': (2, 4, 8, 16, 32, 64),
+ 'mod_code': tested_mod_codes, },
+ True, None),
+ (blks2.qam_constellation,
+ {'constellation_points': (4, 16, 64),
+ 'mod_code': tested_mod_codes, },
+ True, 'differential'),
+ (blks2.bpsk_constellation, {}, 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.
+ (blks2.qpsk_constellation, {}, False, None),
+ (twod_constell, {}, True, None),
+ (threed_constell, {}, True, None),
+ )
+
+def tested_constellations():
+ """
+ Generator to produce (constellation, differential) tuples for testing purposes.
+ """
+ for constructor, poss_args, differential, diff_argname in tested_constellation_info:
+ if differential:
+ diff_poss = (True, False)
+ else:
+ diff_poss = (False,)
+ poss_args = [[argname, argvalues, 0] for argname, argvalues in poss_args.items()]
+ for current_diff in diff_poss:
+ # Add an index into args to keep track of current position in argvalues
+ while True:
+ current_args = dict([(argname, argvalues[argindex])
+ for argname, argvalues, argindex in poss_args])
+ if diff_argname is not None:
+ current_args[diff_argname] = current_diff
+ constellation = constructor(**current_args)
+ yield (constellation, current_diff)
+ for this_poss_arg in poss_args:
+ argname, argvalues, argindex = this_poss_arg
+ if argindex < len(argvalues) - 1:
+ this_poss_arg[2] += 1
+ break
+ else:
+ this_poss_arg[2] = 0
+ if sum([argindex for argname, argvalues, argindex in poss_args]) == 0:
+ break
+
+
+class test_constellation (gr_unittest.TestCase):
+
+ src_length = 256
+
+ def setUp(self):
+ # Generate a list of random bits.
+ self.src_data = tuple([random.randint(0,1) for i in range(0, self.src_length)])
+
+ def tearDown(self):
+ pass
+
+ def test_hard_decision(self):
+ for constellation, differential in tested_constellations():
+ if differential:
+ rs = constellation.rotational_symmetry()
+ rotations = [exp(i*2*pi*(0+1j)/rs) for i in range(0, rs)]
+ else:
+ rotations = [None]
+ for rotation in rotations:
+ src = gr.vector_source_b(self.src_data)
+ content = mod_demod(constellation, differential, rotation)
+ dst = gr.vector_sink_b()
+ self.tb = gr.top_block()
+ self.tb.connect(src, content, dst)
+ self.tb.run()
+ data = dst.data()
+ # Don't worry about cut off data for now.
+ first = constellation.bits_per_symbol()
+ self.assertEqual (self.src_data[first:len(data)], data[first:])
+
+
+class mod_demod(gr.hier_block2):
+ def __init__(self, constellation, differential, rotation):
+ if constellation.arity() > 256:
+ # If this becomes limiting some of the blocks should be generalised so that they can work
+ # with shorts and ints as well as chars.
+ raise ValueError("Constellation cannot contain more than 256 points.")
+
+ gr.hier_block2.__init__(self, "mod_demod",
+ gr.io_signature(1, 1, gr.sizeof_char), # Input signature
+ gr.io_signature(1, 1, gr.sizeof_char)) # Output signature
+
+ arity = constellation.arity()
+
+ # TX
+ self.constellation = constellation
+ self.differential = differential
+ self.blocks = [self]
+ # We expect a stream of unpacked bits.
+ # First step is to pack them.
+ self.blocks.append(
+ gr.unpacked_to_packed_bb(1, gr.GR_MSB_FIRST))
+ # Second step we unpack them such that we have k bits in each byte where
+ # each constellation symbol hold k bits.
+ self.blocks.append(
+ gr.packed_to_unpacked_bb(self.constellation.bits_per_symbol(),
+ gr.GR_MSB_FIRST))
+ # Apply any pre-differential coding
+ # Gray-coding is done here if we're also using differential coding.
+ if self.constellation.apply_pre_diff_code():
+ self.blocks.append(gr.map_bb(self.constellation.pre_diff_code()))
+ # Differential encoding.
+ 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()))
+ # CHANNEL
+ # Channel just consists of a rotation to check differential coding.
+ if rotation is not None:
+ self.blocks.append(gr.multiply_const_cc(rotation))
+
+ # RX
+ # Convert the constellation symbols back to binary values.
+ self.blocks.append(gr.constellation_decoder2_cb(self.constellation.base()))
+ # Differential decoding.
+ if self.differential:
+ self.blocks.append(gr.diff_decoder_bb(arity))
+ # Decode any pre-differential coding.
+ if self.constellation.apply_pre_diff_code():
+ self.blocks.append(gr.map_bb(
+ mod_codes.invert_code(self.constellation.pre_diff_code())))
+ # unpack the k bit vector into a stream of bits
+ self.blocks.append(gr.unpack_k_bits_bb(
+ self.constellation.bits_per_symbol()))
+ # connect to block output
+ check_index = len(self.blocks)
+ self.blocks = self.blocks[:check_index]
+ self.blocks.append(self)
+
+ self.connect(*self.blocks)
+
+
+if __name__ == '__main__':
+ gr_unittest.run(test_constellation, "test_constellation.xml")
diff --git a/gr-digital/python/qa_constellation_receiver.py b/gr-digital/python/qa_constellation_receiver.py
new file mode 100755
index 000000000..ebdbf3bfb
--- /dev/null
+++ b/gr-digital/python/qa_constellation_receiver.py
@@ -0,0 +1,133 @@
+#!/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.
+#
+
+import random
+
+from gnuradio import gr, blks2, packet_utils, gr_unittest
+from utils import mod_codes, alignment
+import digital_swig
+
+from qa_constellation import tested_constellations, twod_constell
+
+# Set a seed so that if errors turn up they are reproducible.
+# 1234 fails
+random.seed(1239)
+
+# TESTING PARAMETERS
+# The number of symbols to test with.
+# We need this many to let the frequency recovery block converge.
+DATA_LENGTH = 200000
+# Test fails if fraction of output that is correct is less than this.
+REQ_CORRECT = 0.8
+
+# CHANNEL PARAMETERS
+NOISE_VOLTAGE = 0.01
+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
+
+
+class test_constellation_receiver (gr_unittest.TestCase):
+
+ # We ignore the first half of the output data since often it takes
+ # a while for the receiver to lock on.
+ ignore_fraction = 0.8
+ seed = 1234
+ max_data_length = DATA_LENGTH * 6
+ max_num_samples = 1000
+
+ def test_basic(self):
+ """
+ Tests a bunch of different constellations by using generic
+ modulation, a channel, and generic demodulation. The generic
+ demodulation uses constellation_receiver which is what
+ we're really trying to test.
+ """
+ # Assumes not more than 64 points in a constellation
+ # Generates some random input data to use.
+ self.src_data = tuple(
+ [random.randint(0,1) for i in range(0, self.max_data_length)])
+ # Generates some random indices to use for comparing input and
+ # output data (a full comparison is too slow in python).
+ self.indices = alignment.random_sample(
+ self.max_data_length, self.max_num_samples, self.seed)
+
+ for constellation, differential in tested_constellations():
+ # The constellation_receiver doesn't work for constellations
+ # of multple dimensions (i.e. multiple complex numbers to a
+ # single symbol).
+ # That is not implemented since the receiver has no way of
+ # knowing where the beginning of a symbol is.
+ # It also doesn't work for non-differential modulation.
+ if constellation.dimensionality() != 1 or not differential:
+ continue
+ data_length = DATA_LENGTH * constellation.bits_per_symbol()
+ tb = rec_test_tb(constellation, differential,
+ src_data=self.src_data[:data_length])
+ tb.run()
+ data = tb.dst.data()
+ d1 = tb.src_data[:int(len(tb.src_data)*self.ignore_fraction)]
+ d2 = data[:int(len(data)*self.ignore_fraction)]
+ correct, overlap, offset, indices = alignment.align_sequences(
+ d1, d2, indices=self.indices)
+ self.assertTrue(correct > REQ_CORRECT)
+
+
+class rec_test_tb (gr.top_block):
+ """
+ Takes a constellation an runs a generic modulation, channel,
+ and generic demodulation.
+ """
+ def __init__(self, constellation, differential,
+ data_length=None, src_data=None):
+ """
+ constellation -- a constellation object
+ differential -- whether differential encoding is used
+ data_length -- the number of bits of data to use
+ src_data -- a list of the bits to use
+ """
+ super(rec_test_tb, self).__init__()
+ # Transmission Blocks
+ if src_data is None:
+ self.src_data = tuple([random.randint(0,1) for i in range(0, data_length)])
+ else:
+ self.src_data = src_data
+ packer = gr.unpacked_to_packed_bb(1, gr.GR_MSB_FIRST)
+ src = gr.vector_source_b(self.src_data)
+ mod = blks2.generic_mod(constellation, differential=differential)
+ # Channel
+ channel = gr.channel_model(NOISE_VOLTAGE, FREQUENCY_OFFSET, TIMING_OFFSET)
+ # Receiver Blocks
+ demod = blks2.generic_demod(constellation, differential=differential,
+ freq_alpha=FREQ_ALPHA,
+ phase_alpha=PHASE_ALPHA)
+ self.dst = gr.vector_sink_b()
+ self.connect(src, packer, mod, channel, demod, self.dst)
+
+if __name__ == '__main__':
+ gr_unittest.run(test_constellation_receiver, "test_constellation_receiver.xml")
diff --git a/gr-digital/python/qa_costas_loop_cc.py b/gr-digital/python/qa_costas_loop_cc.py
index 368704093..368704093 100644..100755
--- a/gr-digital/python/qa_costas_loop_cc.py
+++ b/gr-digital/python/qa_costas_loop_cc.py
diff --git a/gr-digital/python/utils/Makefile.am b/gr-digital/python/utils/Makefile.am
index c35951b44..6da4d61dd 100644
--- a/gr-digital/python/utils/Makefile.am
+++ b/gr-digital/python/utils/Makefile.am
@@ -1,5 +1,5 @@
#
-# Copyright 2007,2009 Free Software Foundation, Inc.
+# Copyright 2011 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -22,12 +22,11 @@
include $(top_srcdir)/Makefile.common
if PYTHON
-utilspythondir = $(grpythondir)/utils
+utilspythondir = $(grpythondir)/digital/utils
-TESTS = \
- run_tests
+TESTS =
-nobase_utilspython_PYTHON = \
+utilspython_PYTHON = \
__init__.py \
gray_code.py \
mod_codes.py \
diff --git a/gr-digital/python/utils/run_tests.in b/gr-digital/python/utils/run_tests.in
deleted file mode 100644
index adcbdfd21..000000000
--- a/gr-digital/python/utils/run_tests.in
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/sh
-
-# 1st parameter is absolute path to component source directory
-# 2nd parameter is absolute path to component build directory
-# 3rd parameter is path to Python QA directory
-
-# Note: calling master run_tests.sh in gnuradio core is not strictly
-# correct, as it will result in a partially bogus PYTHONPATH, but it
-# does make the correct paths in the second half so all is well.
-
-# Nothing in here at the moment.
diff --git a/gr-digital/swig/Makefile.am b/gr-digital/swig/Makefile.am
index 69adf2568..b9ebf4cc5 100644
--- a/gr-digital/swig/Makefile.am
+++ b/gr-digital/swig/Makefile.am
@@ -26,7 +26,8 @@ TESTS =
EXTRA_DIST += $(nobase_guile_DATA)
AM_CPPFLAGS = \
- -I$(top_srcdir)/gr-digital/lib \
+ -I$(abs_top_srcdir)/gr-digital/lib \
+ -I$(abs_top_builddir)/gr-digital/lib \
$(STD_DEFINES_AND_INCLUDES) \
$(PYTHON_CPPFLAGS) \
$(WITH_INCLUDES)
@@ -56,14 +57,17 @@ digital_swig_la_swig_libadd = \
$(abs_top_builddir)/gr-digital/lib/libgnuradio-digital.la
# additional SWIG files to be installed
-digital_swig_swiginclude_headers = \
- digital_constellation.i \
- digital_costas_loop_cc.i \
- digital_cma_equalizer_cc.i \
- digital_lms_dd_equalizer_cc.i \
+digital_swig_swiginclude_headers = \
+ digital_constellation.i \
+ digital_constellation_receiver_cb.i \
+ digital_constellation_decoder_cb.i \
+ digital_costas_loop_cc.i \
+ digital_cma_equalizer_cc.i \
+ digital_lms_dd_equalizer_cc.i \
digital_kurtotic_equalizer_cc.i
digital_swig_swig_args = \
+ -I$(abs_top_srcdir)/gr-digital/lib \
-I$(abs_top_builddir)/gr-digital/lib
if GUILE
diff --git a/gr-digital/swig/digital_constellation.i b/gr-digital/swig/digital_constellation.i
index 40dd28a2b..ae31d443e 100644
--- a/gr-digital/swig/digital_constellation.i
+++ b/gr-digital/swig/digital_constellation.i
@@ -24,7 +24,7 @@
%template(unsigned_int_vector) std::vector<unsigned int>;
// Make sure metric types get SWIGed.
-%include digital_metric_type.h
+%include "digital_metric_type.h"
class digital_constellation;
typedef boost::shared_ptr<digital_constellation> digital_constellation_sptr;
diff --git a/gr-digital/swig/digital_constellation_decoder_cb.i b/gr-digital/swig/digital_constellation_decoder_cb.i
new file mode 100644
index 000000000..53d3fe8e0
--- /dev/null
+++ b/gr-digital/swig/digital_constellation_decoder_cb.i
@@ -0,0 +1,38 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006, 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.
+ */
+
+GR_SWIG_BLOCK_MAGIC(digital,constellation_decoder_cb)
+
+digital_constellation_decoder_cb_sptr
+digital_make_constellation_decoder_cb (digital_constellation_sptr constellation);
+
+class digital_constellation_decoder_cb : public gr_sync_block
+{
+ private:
+ digital_constellation_decoder_cb (digital_constellation_sptr constellation);
+
+ friend digital_constellation_decoder_cb_sptr
+ gr_make_constellation_decoder_cb (digital_constellation_sptr constellation);
+
+ public:
+ ~digital_constellation_decoder_cb();
+};
diff --git a/gr-digital/swig/digital_constellation_receiver_cb.i b/gr-digital/swig/digital_constellation_receiver_cb.i
new file mode 100644
index 000000000..6ced92551
--- /dev/null
+++ b/gr-digital/swig/digital_constellation_receiver_cb.i
@@ -0,0 +1,47 @@
+/* -*- c++ -*- */
+/*
+ * 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.
+ */
+
+GR_SWIG_BLOCK_MAGIC(digital,constellation_receiver_cb);
+
+%import "digital_constellation.i"
+
+digital_constellation_receiver_cb_sptr
+digital_make_constellation_receiver_cb (digital_constellation_sptr constellation,
+ float alpha, float beta,
+ float fmin, float fmax);
+
+class digital_constellation_receiver_cb : public gr_block
+{
+ private:
+ digital_constellation_receiver_cb (digital_contellation_sptr constellation,
+ float alpha, float beta,
+ float fmin, float fmax);
+public:
+ float alpha() const { return d_alpha; }
+ float beta() const { return d_beta; }
+ float freq() const { return d_freq; }
+ float phase() const { return d_phase; }
+ void set_alpha(float alpha) { d_alpha = alpha; }
+ void set_beta(float beta) { d_beta = beta; }
+ void set_freq(float freq) { d_freq = freq; }
+ void set_phase(float phase) { d_phase = phase; }
+};
diff --git a/gr-digital/swig/digital_swig.i b/gr-digital/swig/digital_swig.i
index d87bdd852..26a9dd130 100644
--- a/gr-digital/swig/digital_swig.i
+++ b/gr-digital/swig/digital_swig.i
@@ -27,6 +27,8 @@
#include "digital_cma_equalizer_cc.h"
#include "digital_lms_dd_equalizer_cc.h"
#include "digital_kurtotic_equalizer_cc.h"
+#include "digital_constellation_receiver_cb.h"
+#include "digital_constellation_decoder_cb.h"
%}
%include "digital_constellation.i"
@@ -34,6 +36,8 @@
%include "digital_cma_equalizer_cc.i"
%include "digital_lms_dd_equalizer_cc.i"
%include "digital_kurtotic_equalizer_cc.i"
+%include "digital_constellation_receiver_cb.i"
+%include "digital_constellation_decoder_cb.i"
#if SWIGGUILE
%scheme %{