summaryrefslogtreecommitdiff
path: root/gnuradio-core/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'gnuradio-core/src/lib')
-rw-r--r--gnuradio-core/src/lib/general/Makefile.am5
-rw-r--r--gnuradio-core/src/lib/general/general.i2
-rw-r--r--gnuradio-core/src/lib/general/gr_constellation_receiver_cb.cc146
-rw-r--r--gnuradio-core/src/lib/general/gr_constellation_receiver_cb.h172
-rw-r--r--gnuradio-core/src/lib/general/gr_constellation_receiver_cb.i54
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; }
+};