diff options
Diffstat (limited to 'gnuradio-core/src/lib')
5 files changed, 377 insertions, 2 deletions
diff --git a/gnuradio-core/src/lib/general/Makefile.am b/gnuradio-core/src/lib/general/Makefile.am index 3d8a42805..daa3c446e 100644 --- a/gnuradio-core/src/lib/general/Makefile.am +++ b/gnuradio-core/src/lib/general/Makefile.am @@ -100,6 +100,7 @@ libgeneral_la_SOURCES = \ gr_math.cc \ gr_misc.cc \ gr_mpsk_receiver_cc.cc \ + gr_constellation_receiver_cb.cc \ gr_nlog10_ff.cc \ gr_nop.cc \ gr_null_sink.cc \ @@ -256,7 +257,7 @@ grinclude_HEADERS = \ gr_map_bb.h \ gr_math.h \ gr_misc.h \ - gr_mpsk_receiver_cc.h \ + gr_constellation_receiver_cb.h \ gr_nco.h \ gr_nlog10_ff.h \ gr_nop.h \ @@ -418,7 +419,7 @@ swiginclude_HEADERS = \ gr_lms_dfe_cc.i \ gr_lms_dfe_ff.i \ gr_map_bb.i \ - gr_mpsk_receiver_cc.i \ + gr_constellation_receiver_cb.i \ gr_nlog10_ff.i \ gr_nop.i \ gr_null_sink.i \ diff --git a/gnuradio-core/src/lib/general/general.i b/gnuradio-core/src/lib/general/general.i index 68cafce2e..f758211cc 100644 --- a/gnuradio-core/src/lib/general/general.i +++ b/gnuradio-core/src/lib/general/general.i @@ -69,6 +69,7 @@ #include <gr_fake_channel_coder_pp.h> #include <gr_throttle.h> #include <gr_mpsk_receiver_cc.h> +#include <gr_constellation_receiver_cb.h> #include <gr_stream_mux.h> #include <gr_stream_to_streams.h> #include <gr_streams_to_stream.h> @@ -190,6 +191,7 @@ %include "gr_fake_channel_coder_pp.i" %include "gr_throttle.i" %include "gr_mpsk_receiver_cc.i" +%include "gr_constellation_receiver_cb.i" %include "gr_stream_mux.i" %include "gr_stream_to_streams.i" %include "gr_streams_to_stream.i" diff --git a/gnuradio-core/src/lib/general/gr_constellation_receiver_cb.cc b/gnuradio-core/src/lib/general/gr_constellation_receiver_cb.cc new file mode 100644 index 000000000..0a2309ac0 --- /dev/null +++ b/gnuradio-core/src/lib/general/gr_constellation_receiver_cb.cc @@ -0,0 +1,146 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005,2006,2007,2010 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gr_io_signature.h> +#include <gr_prefs.h> +#include <gr_constellation_receiver_cb.h> +#include <stdexcept> +#include <gr_math.h> +#include <gr_expj.h> +// For debugging +#include <iostream> + + +#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 + +gr_constellation_receiver_cb_sptr +gr_make_constellation_receiver_cb(gr_constellation constell, + float alpha, float beta, + float fmin, float fmax) +{ + return gnuradio::get_initial_sptr(new gr_constellation_receiver_cb (constell, + alpha, beta, + fmin, fmax)); +} + +gr_constellation_receiver_cb::gr_constellation_receiver_cb (gr_constellation 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_signature (1, 1, sizeof (unsigned char))), + 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) +{} + +void +gr_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.constellation()[d_current_const_point].real(), d_constellation.constellation()[d_current_const_point].imag()); +#endif +} + +int +gr_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, o=0; + + float phase_error; + unsigned int sym_value; + gr_complex sample; + + while((o < noutput_items) && (i < ninput_items[0])) { + sample = in[i]; + sym_value = d_constellation.decision_maker(sample); + //std::cout << "sym_value: " << sym_value << " sample: " << sample << std::endl; + phase_error = -arg(sample*conj(d_constellation.constellation()[sym_value])); + phase_error_tracking(phase_error); // corrects phase and frequency offsets + out[o++] = sym_value; + i++; + } + + #if 0 + printf("ninput_items: %d noutput_items: %d consuming: %d returning: %d\n", + ninput_items[0], noutput_items, i, o); + #endif + + consume_each(i); + return o; +} + +// Base Constellation Class + +gr_constellation::gr_constellation (std::vector<gr_complex> constellation) { + d_constellation = constellation; +} + +// Chooses points base on shortest distance. +// Inefficient. +unsigned int gr_constellation::decision_maker(gr_complex sample) +{ + unsigned int table_size = constellation().size(); + unsigned int min_index = 0; + float min_euclid_dist; + float euclid_dist; + + min_euclid_dist = norm(sample - constellation()[0]); + min_index = 0; + for (unsigned int j = 1; j < table_size; j++){ + euclid_dist = norm(sample - constellation()[j]); + if (euclid_dist < min_euclid_dist){ + min_euclid_dist = euclid_dist; + min_index = j; + } + } + return min_index; +} diff --git a/gnuradio-core/src/lib/general/gr_constellation_receiver_cb.h b/gnuradio-core/src/lib/general/gr_constellation_receiver_cb.h new file mode 100644 index 000000000..ba38bdad6 --- /dev/null +++ b/gnuradio-core/src/lib/general/gr_constellation_receiver_cb.h @@ -0,0 +1,172 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2007,2010 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_GR_CONSTELLATION_RECEIVER_CB_H +#define INCLUDED_GR_CONSTELLATION_RECEIVER_CB_H + +#include <gr_block.h> +#include <gr_complex.h> +#include <math.h> +#include <fstream> + +class gr_constellation +{ + public: + + gr_constellation (std::vector<gr_complex> constellation); + + //! Returns the set of points in this constellation. + std::vector<gr_complex> constellation() { return d_constellation;} + + //! Returns the constellation point that matches best. + //! Also calculates the phase error. + unsigned int decision_maker (gr_complex sample); + + unsigned int bits_per_symbol () { + return floor(log(d_constellation.size())/log(2)); + } + + private: + + std::vector<gr_complex> d_constellation; +}; + +class gri_mmse_fir_interpolator_cc; + +class gr_constellation_receiver_cb; +typedef boost::shared_ptr<gr_constellation_receiver_cb> gr_constellation_receiver_cb_sptr; + +// public constructor +gr_constellation_receiver_cb_sptr +gr_make_constellation_receiver_cb (gr_constellation 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 gr_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. + */ + gr_constellation_receiver_cb (gr_constellation 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; + + gr_constellation 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 gr_constellation_receiver_cb_sptr + gr_make_constellation_receiver_cb (gr_constellation constell, + float alpha, float beta, + float fmin, float fmax); +}; + +#endif diff --git a/gnuradio-core/src/lib/general/gr_constellation_receiver_cb.i b/gnuradio-core/src/lib/general/gr_constellation_receiver_cb.i new file mode 100644 index 000000000..b48322f45 --- /dev/null +++ b/gnuradio-core/src/lib/general/gr_constellation_receiver_cb.i @@ -0,0 +1,54 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 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(gr,constellation_receiver_cb); + +%template(gr_complex_vector) std::vector<gr_complex>; + +class gr_constellation +{ +public: + gr_constellation (std::vector<gr_complex> constellation); + std::vector<gr_complex> constellation(); + unsigned int decision_maker (gr_complex sample); + unsigned int bits_per_symbol (); +}; + +gr_constellation_receiver_cb_sptr gr_make_constellation_receiver_cb (gr_constellation constellation, + float alpha, float beta, + float fmin, float fmax); +class gr_constellation_receiver_cb : public gr_block +{ + private: + gr_constellation_receiver_cb (gr_contellation 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; } +}; |