diff options
Diffstat (limited to 'gr-digital')
-rw-r--r-- | gr-digital/lib/Makefile.am | 29 | ||||
-rw-r--r-- | gr-digital/lib/digital_constellation_decoder_cb.cc | 77 | ||||
-rw-r--r-- | gr-digital/lib/digital_constellation_decoder_cb.h | 64 | ||||
-rw-r--r-- | gr-digital/lib/digital_constellation_receiver_cb.cc | 131 | ||||
-rw-r--r-- | gr-digital/lib/digital_constellation_receiver_cb.h | 149 | ||||
-rw-r--r-- | gr-digital/python/Makefile.am | 1 | ||||
-rw-r--r-- | gr-digital/python/generic_mod_demod.py | 4 | ||||
-rwxr-xr-x | gr-digital/python/qa_constellation.py | 205 | ||||
-rwxr-xr-x | gr-digital/python/qa_constellation_receiver.py | 133 | ||||
-rwxr-xr-x[-rw-r--r--] | gr-digital/python/qa_costas_loop_cc.py | 0 | ||||
-rw-r--r-- | gr-digital/python/utils/Makefile.am | 9 | ||||
-rw-r--r-- | gr-digital/python/utils/run_tests.in | 11 | ||||
-rw-r--r-- | gr-digital/swig/Makefile.am | 16 | ||||
-rw-r--r-- | gr-digital/swig/digital_constellation.i | 2 | ||||
-rw-r--r-- | gr-digital/swig/digital_constellation_decoder_cb.i | 38 | ||||
-rw-r--r-- | gr-digital/swig/digital_constellation_receiver_cb.i | 47 | ||||
-rw-r--r-- | gr-digital/swig/digital_swig.i | 4 |
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 %{ |