summaryrefslogtreecommitdiff
path: root/gr-digital/lib
diff options
context:
space:
mode:
Diffstat (limited to 'gr-digital/lib')
-rw-r--r--gr-digital/lib/Makefile.am25
-rw-r--r--gr-digital/lib/digital_binary_slicer_fb.cc59
-rw-r--r--gr-digital/lib/digital_clock_recovery_mm_cc.cc217
-rw-r--r--gr-digital/lib/digital_clock_recovery_mm_ff.cc139
-rw-r--r--gr-digital/lib/digital_cma_equalizer_cc.h101
-rw-r--r--gr-digital/lib/digital_constellation.cc86
-rw-r--r--gr-digital/lib/digital_constellation.h352
-rw-r--r--gr-digital/lib/digital_constellation_decoder_cb.h64
-rw-r--r--gr-digital/lib/digital_constellation_receiver_cb.cc28
-rw-r--r--gr-digital/lib/digital_constellation_receiver_cb.h149
-rw-r--r--gr-digital/lib/digital_correlate_access_code_bb.cc134
-rw-r--r--gr-digital/lib/digital_costas_loop_cc.cc74
-rw-r--r--gr-digital/lib/digital_costas_loop_cc.h150
-rw-r--r--gr-digital/lib/digital_cpmmod_bc.cc69
-rw-r--r--gr-digital/lib/digital_crc32.cc130
-rw-r--r--gr-digital/lib/digital_fll_band_edge_cc.cc259
-rw-r--r--gr-digital/lib/digital_gmskmod_bc.cc (renamed from gr-digital/lib/digital_metric_type.h)33
-rw-r--r--gr-digital/lib/digital_kurtotic_equalizer_cc.h111
-rw-r--r--gr-digital/lib/digital_lms_dd_equalizer_cc.h116
-rw-r--r--gr-digital/lib/digital_mpsk_receiver_cc.cc316
20 files changed, 1467 insertions, 1145 deletions
diff --git a/gr-digital/lib/Makefile.am b/gr-digital/lib/Makefile.am
index 4f67614d8..17baf2101 100644
--- a/gr-digital/lib/Makefile.am
+++ b/gr-digital/lib/Makefile.am
@@ -21,29 +21,28 @@
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_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
+AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(PYTHON_CPPFLAGS) \
+ $(GR_DIGITAL_INCLUDES) $(WITH_INCLUDES)
lib_LTLIBRARIES = libgnuradio-digital.la
libgnuradio_digital_la_SOURCES = \
+ digital_binary_slicer_fb.cc \
+ digital_clock_recovery_mm_cc.cc \
+ digital_clock_recovery_mm_ff.cc \
digital_constellation.cc \
digital_constellation_receiver_cb.cc \
digital_constellation_decoder_cb.cc \
+ digital_correlate_access_code_bb.cc \
digital_costas_loop_cc.cc \
digital_cma_equalizer_cc.cc \
+ digital_crc32.cc \
+ digital_fll_band_edge_cc.cc \
digital_lms_dd_equalizer_cc.cc \
- digital_kurtotic_equalizer_cc.cc
+ digital_kurtotic_equalizer_cc.cc \
+ digital_mpsk_receiver_cc.cc \
+ digital_gmskmod_bc.cc \
+ digital_cpmmod_bc.cc
libgnuradio_digital_la_LIBADD = \
$(GNURADIO_CORE_LA)
diff --git a/gr-digital/lib/digital_binary_slicer_fb.cc b/gr-digital/lib/digital_binary_slicer_fb.cc
new file mode 100644
index 000000000..fcdb4291f
--- /dev/null
+++ b/gr-digital/lib/digital_binary_slicer_fb.cc
@@ -0,0 +1,59 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006,2010,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_binary_slicer_fb.h>
+#include <gr_io_signature.h>
+#include <gr_math.h>
+#include <stdexcept>
+
+digital_binary_slicer_fb_sptr
+digital_make_binary_slicer_fb ()
+{
+ return gnuradio::get_initial_sptr(new digital_binary_slicer_fb ());
+}
+
+digital_binary_slicer_fb::digital_binary_slicer_fb ()
+ : gr_sync_block ("binary_slicer_fb",
+ gr_make_io_signature (1, 1, sizeof (float)),
+ gr_make_io_signature (1, 1, sizeof (unsigned char)))
+{
+}
+
+int
+digital_binary_slicer_fb::work (int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+ const float *in = (const float *) input_items[0];
+ unsigned char *out = (unsigned char *) output_items[0];
+
+
+ for (int i = 0; i < noutput_items; i++){
+ out[i] = gr_binary_slicer(in[i]);
+ }
+
+ return noutput_items;
+}
diff --git a/gr-digital/lib/digital_clock_recovery_mm_cc.cc b/gr-digital/lib/digital_clock_recovery_mm_cc.cc
new file mode 100644
index 000000000..198eb4b89
--- /dev/null
+++ b/gr-digital/lib/digital_clock_recovery_mm_cc.cc
@@ -0,0 +1,217 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2005,2006,2010,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_clock_recovery_mm_cc.h>
+#include <gri_mmse_fir_interpolator_cc.h>
+#include <stdexcept>
+#include <cstdio>
+
+
+// Public constructor
+static const int FUDGE = 16;
+
+digital_clock_recovery_mm_cc_sptr
+digital_make_clock_recovery_mm_cc(float omega, float gain_omega,
+ float mu, float gain_mu,
+ float omega_relative_limit)
+{
+ return gnuradio::get_initial_sptr(new digital_clock_recovery_mm_cc (omega,
+ gain_omega,
+ mu,
+ gain_mu,
+ omega_relative_limit));
+}
+
+digital_clock_recovery_mm_cc::digital_clock_recovery_mm_cc (float omega, float gain_omega,
+ float mu, float gain_mu,
+ float omega_relative_limit)
+ : gr_block ("clock_recovery_mm_cc",
+ gr_make_io_signature (1, 1, sizeof (gr_complex)),
+ gr_make_io_signature2 (1, 2, sizeof (gr_complex), sizeof(float))),
+ d_mu (mu), d_omega(omega), d_gain_omega(gain_omega),
+ d_omega_relative_limit(omega_relative_limit),
+ d_gain_mu(gain_mu), d_last_sample(0), d_interp(new gri_mmse_fir_interpolator_cc()),
+ d_verbose(gr_prefs::singleton()->get_bool("clock_recovery_mm_cc", "verbose", false)),
+ d_p_2T(0), d_p_1T(0), d_p_0T(0), d_c_2T(0), d_c_1T(0), d_c_0T(0)
+{
+ if (omega <= 0.0)
+ throw std::out_of_range ("clock rate must be > 0");
+ if (gain_mu < 0 || gain_omega < 0)
+ throw std::out_of_range ("Gains must be non-negative");
+
+ set_omega(omega); // also sets min and max omega
+ set_relative_rate (1.0 / omega);
+ set_history(3); // ensure 2 extra input sample is available
+}
+
+digital_clock_recovery_mm_cc::~digital_clock_recovery_mm_cc ()
+{
+ delete d_interp;
+}
+
+void
+digital_clock_recovery_mm_cc::forecast(int noutput_items, gr_vector_int &ninput_items_required)
+{
+ unsigned ninputs = ninput_items_required.size();
+ for (unsigned i=0; i < ninputs; i++)
+ ninput_items_required[i] =
+ (int) ceil((noutput_items * d_omega) + d_interp->ntaps()) + FUDGE;
+}
+
+gr_complex
+digital_clock_recovery_mm_cc::slicer_0deg (gr_complex sample)
+{
+ float real=0, imag=0;
+
+ if(sample.real() > 0)
+ real = 1;
+ if(sample.imag() > 0)
+ imag = 1;
+ return gr_complex(real,imag);
+}
+
+gr_complex
+digital_clock_recovery_mm_cc::slicer_45deg (gr_complex sample)
+{
+ float real= -1, imag = -1;
+ if(sample.real() > 0)
+ real=1;
+ if(sample.imag() > 0)
+ imag = 1;
+ return gr_complex(real,imag);
+}
+
+/*
+ Modified Mueller and Muller clock recovery circuit
+ Based:
+ 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.
+*/
+
+int
+digital_clock_recovery_mm_cc::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];
+ gr_complex *out = (gr_complex *) output_items[0];
+ float *foptr = (float *) output_items[1];
+
+ bool write_foptr = output_items.size() >= 2;
+
+ int ii = 0; // input index
+ int oo = 0; // output index
+ int ni = ninput_items[0] - d_interp->ntaps() - FUDGE; // don't use more input than this
+
+ assert(d_mu >= 0.0);
+ assert(d_mu <= 1.0);
+
+ float mm_val=0;
+ gr_complex u, x, y;
+
+ // This loop writes the error to the second output, if it exists
+ if (write_foptr) {
+ while(oo < noutput_items && ii < ni) {
+ d_p_2T = d_p_1T;
+ d_p_1T = d_p_0T;
+ d_p_0T = d_interp->interpolate (&in[ii], d_mu);
+
+ d_c_2T = d_c_1T;
+ d_c_1T = d_c_0T;
+ d_c_0T = slicer_0deg(d_p_0T);
+
+ x = (d_c_0T - d_c_2T) * conj(d_p_1T);
+ y = (d_p_0T - d_p_2T) * conj(d_c_1T);
+ u = y - x;
+ mm_val = u.real();
+ out[oo++] = d_p_0T;
+
+ // limit mm_val
+ mm_val = gr_branchless_clip(mm_val,4.0);
+ d_omega = d_omega + d_gain_omega * mm_val;
+ d_omega = d_omega_mid + gr_branchless_clip(d_omega-d_omega_mid, d_omega_relative_limit); // make sure we don't walk away
+
+ d_mu = d_mu + d_omega + d_gain_mu * mm_val;
+ ii += (int)floor(d_mu);
+ d_mu -= floor(d_mu);
+
+ // write the error signal to the second output
+ foptr[oo-1] = mm_val;
+
+ if (ii < 0) // clamp it. This should only happen with bogus input
+ ii = 0;
+ }
+ }
+ // This loop does not write to the second output (ugly, but faster)
+ else {
+ while(oo < noutput_items && ii < ni) {
+ d_p_2T = d_p_1T;
+ d_p_1T = d_p_0T;
+ d_p_0T = d_interp->interpolate (&in[ii], d_mu);
+
+ d_c_2T = d_c_1T;
+ d_c_1T = d_c_0T;
+ d_c_0T = slicer_0deg(d_p_0T);
+
+ x = (d_c_0T - d_c_2T) * conj(d_p_1T);
+ y = (d_p_0T - d_p_2T) * conj(d_c_1T);
+ u = y - x;
+ mm_val = u.real();
+ out[oo++] = d_p_0T;
+
+ // limit mm_val
+ mm_val = gr_branchless_clip(mm_val,1.0);
+
+ d_omega = d_omega + d_gain_omega * mm_val;
+ d_omega = d_omega_mid + gr_branchless_clip(d_omega-d_omega_mid, d_omega_relative_limit); // make sure we don't walk away
+
+ d_mu = d_mu + d_omega + d_gain_mu * mm_val;
+ ii += (int)floor(d_mu);
+ d_mu -= floor(d_mu);
+
+ if(d_verbose) {
+ printf("%f\t%f\n", d_omega, d_mu);
+ }
+
+ if (ii < 0) // clamp it. This should only happen with bogus input
+ ii = 0;
+ }
+ }
+
+ if (ii > 0){
+ if (ii > ninput_items[0]){
+ fprintf(stderr, "gr_clock_recovery_mm_cc: ii > ninput_items[0] (%d > %d)\n",
+ ii, ninput_items[0]);
+ assert(0);
+ }
+ consume_each (ii);
+ }
+
+ return oo;
+}
diff --git a/gr-digital/lib/digital_clock_recovery_mm_ff.cc b/gr-digital/lib/digital_clock_recovery_mm_ff.cc
new file mode 100644
index 000000000..04057f0e9
--- /dev/null
+++ b/gr-digital/lib/digital_clock_recovery_mm_ff.cc
@@ -0,0 +1,139 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2010,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 <digital_clock_recovery_mm_ff.h>
+#include <gri_mmse_fir_interpolator.h>
+#include <stdexcept>
+
+#define DEBUG_CR_MM_FF 0 // must be defined as 0 or 1
+
+// Public constructor
+
+digital_clock_recovery_mm_ff_sptr
+digital_make_clock_recovery_mm_ff(float omega, float gain_omega,
+ float mu, float gain_mu,
+ float omega_relative_limit)
+{
+ return gnuradio::get_initial_sptr(new digital_clock_recovery_mm_ff (omega,
+ gain_omega,
+ mu,
+ gain_mu,
+ omega_relative_limit));
+}
+
+digital_clock_recovery_mm_ff::digital_clock_recovery_mm_ff (float omega, float gain_omega,
+ float mu, float gain_mu,
+ float omega_relative_limit)
+ : gr_block ("clock_recovery_mm_ff",
+ gr_make_io_signature (1, 1, sizeof (float)),
+ gr_make_io_signature (1, 1, sizeof (float))),
+ d_mu (mu), d_gain_omega(gain_omega), d_gain_mu(gain_mu),
+ d_last_sample(0), d_interp(new gri_mmse_fir_interpolator()),
+ d_logfile(0), d_omega_relative_limit(omega_relative_limit)
+{
+ if (omega < 1)
+ throw std::out_of_range ("clock rate must be > 0");
+ if (gain_mu < 0 || gain_omega < 0)
+ throw std::out_of_range ("Gains must be non-negative");
+
+ set_omega(omega); // also sets min and max omega
+ set_relative_rate (1.0 / omega);
+
+ if (DEBUG_CR_MM_FF)
+ d_logfile = fopen("cr_mm_ff.dat", "wb");
+}
+
+digital_clock_recovery_mm_ff::~digital_clock_recovery_mm_ff ()
+{
+ delete d_interp;
+
+ if (DEBUG_CR_MM_FF && d_logfile){
+ fclose(d_logfile);
+ d_logfile = 0;
+ }
+}
+
+void
+digital_clock_recovery_mm_ff::forecast(int noutput_items, gr_vector_int &ninput_items_required)
+{
+ unsigned ninputs = ninput_items_required.size();
+ for (unsigned i=0; i < ninputs; i++)
+ ninput_items_required[i] =
+ (int) ceil((noutput_items * d_omega) + d_interp->ntaps());
+}
+
+static inline float
+slice(float x)
+{
+ return x < 0 ? -1.0F : 1.0F;
+}
+
+/*
+ * This implements the Mueller and Müller (M&M) discrete-time error-tracking synchronizer.
+ *
+ * See "Digital Communication Receivers: Synchronization, Channel
+ * Estimation and Signal Processing" by Heinrich Meyr, Marc Moeneclaey, & Stefan Fechtel.
+ * ISBN 0-471-50275-8.
+ */
+int
+digital_clock_recovery_mm_ff::general_work (int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+ const float *in = (const float *) input_items[0];
+ float *out = (float *) output_items[0];
+
+ int ii = 0; // input index
+ int oo = 0; // output index
+ int ni = ninput_items[0] - d_interp->ntaps(); // don't use more input than this
+ float mm_val;
+
+ while (oo < noutput_items && ii < ni ){
+
+ // produce output sample
+ out[oo] = d_interp->interpolate (&in[ii], d_mu);
+ mm_val = slice(d_last_sample) * out[oo] - slice(out[oo]) * d_last_sample;
+ d_last_sample = out[oo];
+
+ d_omega = d_omega + d_gain_omega * mm_val;
+ d_omega = d_omega_mid + gr_branchless_clip(d_omega-d_omega_mid, d_omega_relative_limit); // make sure we don't walk away
+ d_mu = d_mu + d_omega + d_gain_mu * mm_val;
+
+ ii += (int) floor(d_mu);
+ d_mu = d_mu - floor(d_mu);
+ oo++;
+
+ if (DEBUG_CR_MM_FF && d_logfile){
+ fwrite(&d_omega, sizeof(d_omega), 1, d_logfile);
+ }
+ }
+
+ consume_each (ii);
+
+ return oo;
+}
diff --git a/gr-digital/lib/digital_cma_equalizer_cc.h b/gr-digital/lib/digital_cma_equalizer_cc.h
deleted file mode 100644
index 0dd99debd..000000000
--- a/gr-digital/lib/digital_cma_equalizer_cc.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/* -*- 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_CMA_EQUALIZER_CC_H
-#define INCLUDED_DIGITAL_CMA_EQUALIZER_CC_H
-
-#include <gr_adaptive_fir_ccc.h>
-#include <gr_math.h>
-#include <iostream>
-
-class digital_cma_equalizer_cc;
-typedef boost::shared_ptr<digital_cma_equalizer_cc> digital_cma_equalizer_cc_sptr;
-
-digital_cma_equalizer_cc_sptr
-digital_make_cma_equalizer_cc(int num_taps, float modulus, float mu, int sps);
-
-/*!
- * \brief Implements constant modulus adaptive filter on complex stream
- * \ingroup eq_blk
- *
- * The error value and tap update equations (for p=2) can be found in:
- *
- * D. Godard, "Self-Recovering Equalization and Carrier Tracking in
- * Two-Dimensional Data Communication Systems," IEEE Transactions on
- * Communications, Vol. 28, No. 11, pp. 1867 - 1875, 1980,
- */
-class digital_cma_equalizer_cc : public gr_adaptive_fir_ccc
-{
-private:
- float d_modulus;
- float d_mu;
-
- friend digital_cma_equalizer_cc_sptr digital_make_cma_equalizer_cc(int num_taps,
- float modulus,
- float mu,
- int sps);
- digital_cma_equalizer_cc(int num_taps, float modulus, float mu, int sps);
-
-protected:
-
- virtual gr_complex error(const gr_complex &out)
- {
- gr_complex error = out*(norm(out) - d_modulus);
- float re = gr_clip(error.real(), 1.0);
- float im = gr_clip(error.imag(), 1.0);
- return gr_complex(re, im);
- }
-
- virtual void update_tap(gr_complex &tap, const gr_complex &in)
- {
- // Hn+1 = Hn - mu*conj(Xn)*zn*(|zn|^2 - 1)
- tap -= d_mu*conj(in)*d_error;
- }
-
-public:
- float get_gain()
- {
- return d_mu;
- }
-
- void set_gain(float mu)
- {
- if(mu < 0.0f || mu > 1.0f) {
- throw std::out_of_range("digital_cma_equalizer::set_gain: Gain value must be in [0,1]");
- }
- d_mu = mu;
- }
-
- float get_modulus()
- {
- return d_modulus;
- }
-
- void set_modulus(float mod)
- {
- if(mod < 0)
- throw std::out_of_range("digital_cma_equalizer::set_modulus: Modulus value must be >= 0");
- d_modulus = mod;
- }
-};
-
-#endif
diff --git a/gr-digital/lib/digital_constellation.cc b/gr-digital/lib/digital_constellation.cc
index d1f218439..0c100f38e 100644
--- a/gr-digital/lib/digital_constellation.cc
+++ b/gr-digital/lib/digital_constellation.cc
@@ -411,6 +411,20 @@ digital_constellation_qpsk::digital_constellation_qpsk ()
d_constellation[1] = gr_complex(SQRT_TWO, -SQRT_TWO);
d_constellation[2] = gr_complex(-SQRT_TWO, SQRT_TWO);
d_constellation[3] = gr_complex(SQRT_TWO, SQRT_TWO);
+
+ /*
+ d_constellation[0] = gr_complex(SQRT_TWO, SQRT_TWO);
+ d_constellation[1] = gr_complex(-SQRT_TWO, SQRT_TWO);
+ d_constellation[2] = gr_complex(SQRT_TWO, -SQRT_TWO);
+ d_constellation[3] = gr_complex(SQRT_TWO, -SQRT_TWO);
+ */
+
+ d_pre_diff_code.resize(4);
+ d_pre_diff_code[0] = 0x0;
+ d_pre_diff_code[1] = 0x2;
+ d_pre_diff_code[2] = 0x3;
+ d_pre_diff_code[3] = 0x1;
+
d_rotational_symmetry = 4;
d_dimensionality = 1;
calc_arity();
@@ -422,8 +436,80 @@ digital_constellation_qpsk::decision_maker(const gr_complex *sample)
// Real component determines small bit.
// Imag component determines big bit.
return 2*(imag(*sample)>0) + (real(*sample)>0);
+
+ /*
+ bool a = real(*sample) > 0;
+ bool b = imag(*sample) > 0;
+ if(a) {
+ if(b)
+ return 0x0;
+ else
+ return 0x1;
+ }
+ else {
+ if(b)
+ return 0x2;
+ else
+ return 0x3;
+ }
+ */
+}
+
+
+/********************************************************************/
+
+
+digital_constellation_dqpsk_sptr
+digital_make_constellation_dqpsk()
+{
+ return digital_constellation_dqpsk_sptr(new digital_constellation_dqpsk ());
}
+digital_constellation_dqpsk::digital_constellation_dqpsk ()
+{
+ // This constellation is not gray coded, which allows
+ // us to use differential encodings (through gr_diff_encode and
+ // gr_diff_decode) on the symbols.
+ d_constellation.resize(4);
+ d_constellation[0] = gr_complex(+SQRT_TWO, +SQRT_TWO);
+ d_constellation[1] = gr_complex(-SQRT_TWO, +SQRT_TWO);
+ d_constellation[2] = gr_complex(-SQRT_TWO, -SQRT_TWO);
+ d_constellation[3] = gr_complex(+SQRT_TWO, -SQRT_TWO);
+
+ // Use this mapping to convert to gray code before diff enc.
+ d_pre_diff_code.resize(4);
+ d_pre_diff_code[0] = 0x0;
+ d_pre_diff_code[1] = 0x1;
+ d_pre_diff_code[2] = 0x3;
+ d_pre_diff_code[3] = 0x2;
+ d_apply_pre_diff_code = true;
+
+ d_rotational_symmetry = 4;
+ d_dimensionality = 1;
+ calc_arity();
+}
+
+unsigned int
+digital_constellation_dqpsk::decision_maker(const gr_complex *sample)
+{
+ // Slower deicison maker as we can't slice along one axis.
+ // Maybe there's a better way to do this, still.
+
+ bool a = real(*sample) > 0;
+ bool b = imag(*sample) > 0;
+ if(a) {
+ if(b)
+ return 0x0;
+ else
+ return 0x3;
+ }
+ else {
+ if(b)
+ return 0x1;
+ else
+ return 0x2;
+ }
+}
digital_constellation_8psk_sptr
digital_make_constellation_8psk()
diff --git a/gr-digital/lib/digital_constellation.h b/gr-digital/lib/digital_constellation.h
deleted file mode 100644
index d345ebc10..000000000
--- a/gr-digital/lib/digital_constellation.h
+++ /dev/null
@@ -1,352 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2010, 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_H
-#define INCLUDED_DIGITAL_CONSTELLATION_H
-
-#include <vector>
-#include <math.h>
-#include <gr_complex.h>
-#include <boost/enable_shared_from_this.hpp>
-#include <digital_metric_type.h>
-
-/************************************************************/
-/* digital_constellation */
-/* */
-/* Base class defining interface. */
-/************************************************************/
-
-class digital_constellation;
-typedef boost::shared_ptr<digital_constellation> digital_constellation_sptr;
-
-class digital_constellation : public boost::enable_shared_from_this<digital_constellation>
-{
-public:
- digital_constellation (std::vector<gr_complex> constellation, std::vector<unsigned int> pre_diff_code,
- unsigned int rotational_symmetry, unsigned int dimensionality);
- digital_constellation ();
-
- //! Returns the constellation points for a symbol value
- void map_to_points(unsigned int value, gr_complex *points);
- std::vector<gr_complex> map_to_points_v(unsigned int value);
-
- //! Returns the constellation point that matches best.
- virtual unsigned int decision_maker (const gr_complex *sample) = 0;
- //! Takes a vector rather than a pointer. Better for SWIG wrapping.
- unsigned int decision_maker_v (std::vector<gr_complex> sample);
- //! Also calculates the phase error.
- unsigned int decision_maker_pe (const gr_complex *sample, float *phase_error);
- //! Calculates distance.
- unsigned int decision_maker_e (const gr_complex *sample, float *error);
-
- //! Calculates metrics for all points in the constellation.
- //! For use with the viterbi algorithm.
- virtual void calc_metric(const gr_complex *sample, float *metric, trellis_metric_type_t type);
- virtual void calc_euclidean_metric(const gr_complex *sample, float *metric);
- virtual void calc_hard_symbol_metric(const gr_complex *sample, float *metric);
-
- //! Returns the set of points in this constellation.
- std::vector<gr_complex> points() { return d_constellation;}
- //! Returns the vector of points in this constellation.
- //! Raise error if dimensionality is not one.
- std::vector<gr_complex> s_points();
- //! Returns a vector of vectors of points.
- std::vector<std::vector<gr_complex> > v_points();
- //! Whether to apply an encoding before doing differential encoding. (e.g. gray coding)
- bool apply_pre_diff_code() { return d_apply_pre_diff_code;}
- //! Returns the encoding to apply before differential encoding.
- std::vector<unsigned int> pre_diff_code() { return d_pre_diff_code;}
- //! Returns the order of rotational symmetry.
- unsigned int rotational_symmetry() { return d_rotational_symmetry;}
- //! Returns the number of complex numbers in a single symbol.
- unsigned int dimensionality() {return d_dimensionality;}
-
- unsigned int bits_per_symbol () {
- return floor(log(double(d_constellation.size()))/d_dimensionality/log(2.0));
- }
-
- unsigned int arity () {
- return d_arity;
- }
-
- digital_constellation_sptr base() {
- return shared_from_this();
- }
-
- protected:
-
- std::vector<gr_complex> d_constellation;
- std::vector<unsigned int> d_pre_diff_code;
- bool d_apply_pre_diff_code;
- unsigned int d_rotational_symmetry;
- unsigned int d_dimensionality;
- unsigned int d_arity;
-
- float get_distance(unsigned int index, const gr_complex *sample);
- unsigned int get_closest_point(const gr_complex *sample);
- void calc_arity ();
-};
-
-/************************************************************/
-/* digital_constellation_calcdist */
-/* */
-/* Constellation which calculates the distance to each */
-/* point in the constellation for decision making. */
-/* Inefficient for large constellations. */
-/************************************************************/
-
-class digital_constellation_calcdist;
-typedef boost::shared_ptr<digital_constellation_calcdist> digital_constellation_calcdist_sptr;
-
-// public constructor
-digital_constellation_calcdist_sptr
-digital_make_constellation_calcdist (std::vector<gr_complex> constellation, std::vector<unsigned int> pre_diff_code,
- unsigned int rotational_symmetry, unsigned int dimensionality);
-
-
-class digital_constellation_calcdist : public digital_constellation
-{
- public:
- digital_constellation_calcdist (std::vector<gr_complex> constellation,
- std::vector<unsigned int> pre_diff_code,
- unsigned int rotational_symmetry,
- unsigned int dimensionality);
- unsigned int decision_maker (const gr_complex *sample);
- // void calc_metric(gr_complex *sample, float *metric, trellis_metric_type_t type);
- // void calc_euclidean_metric(gr_complex *sample, float *metric);
- // void calc_hard_symbol_metric(gr_complex *sample, float *metric);
-
- private:
- friend digital_constellation_calcdist_sptr
- digital_make_constellation_calcdist (std::vector<gr_complex> constellation);
-};
-
-/************************************************************/
-/* digital_constellation_sector */
-/* */
-/* An abstract class. */
-/* Constellation space is divided into sectors. */
-/* Each sector is associated with the nearest constellation */
-/* point. */
-/************************************************************/
-
-class digital_constellation_sector : public digital_constellation
-{
- public:
-
- digital_constellation_sector (std::vector<gr_complex> constellation,
- std::vector<unsigned int> pre_diff_code,
- unsigned int rotational_symmetry,
- unsigned int dimensionality,
- unsigned int n_sectors);
-
- unsigned int decision_maker (const gr_complex *sample);
-
- protected:
-
- virtual unsigned int get_sector (const gr_complex *sample) = 0;
- virtual unsigned int calc_sector_value (unsigned int sector) = 0;
- void find_sector_values ();
-
- unsigned int n_sectors;
-
- private:
-
- std::vector<unsigned int> sector_values;
-
-};
-
-/************************************************************/
-/* digital_constellation_rect */
-/* */
-/* Only implemented for 1-(complex)dimensional */
-/* constellation. */
-/* Constellation space is divided into rectangular sectors. */
-/* Each sector is associated with the nearest constellation */
-/* point. */
-/* Works well for square QAM. */
-/* Works for any generic constellation provided sectors are */
-/* not too large. */
-/************************************************************/
-
-class digital_constellation_rect;
-typedef boost::shared_ptr<digital_constellation_rect> digital_constellation_rect_sptr;
-
-// public constructor
-digital_constellation_rect_sptr
-digital_make_constellation_rect (std::vector<gr_complex> constellation, std::vector<unsigned int> pre_diff_code,
- unsigned int rotational_symmetry,
- unsigned int real_sectors, unsigned int imag_sectors,
- float width_real_sectors, float width_imag_sectors);
-
-class digital_constellation_rect : public digital_constellation_sector
-{
- public:
-
- digital_constellation_rect (std::vector<gr_complex> constellation, std::vector<unsigned int> pre_diff_code,
- unsigned int rotational_symmetry,
- unsigned int real_sectors, unsigned int imag_sectors,
- float width_real_sectors, float width_imag_sectors);
-
- protected:
-
- unsigned int get_sector (const gr_complex *sample);
-
- unsigned int calc_sector_value (unsigned int sector);
-
- private:
-
- unsigned int n_real_sectors;
- unsigned int n_imag_sectors;
- float d_width_real_sectors;
- float d_width_imag_sectors;
-
- friend digital_constellation_rect_sptr
- digital_make_constellation_rect (std::vector<gr_complex> constellation, std::vector<unsigned int> pre_diff_code,
- unsigned int rotational_symmetry,
- unsigned int real_sectors, unsigned int imag_sectors,
- float width_real_sectors, float width_imag_sectors);
-
-};
-
-/************************************************************/
-/* digital_constellation_psk */
-/* */
-/* Constellation space is divided into pie slices sectors. */
-/* Each slice is associated with the nearest constellation */
-/* point. */
-/* Works well for PSK but nothing else. */
-/* Assumes that there is a constellation point at 1. */
-/************************************************************/
-
-class digital_constellation_psk;
-typedef boost::shared_ptr<digital_constellation_psk> digital_constellation_psk_sptr;
-
-// public constructor
-digital_constellation_psk_sptr
-digital_make_constellation_psk (std::vector<gr_complex> constellation,
- std::vector<unsigned int> pre_diff_code,
- unsigned int n_sectors);
-
-class digital_constellation_psk : public digital_constellation_sector
-{
- public:
-
- digital_constellation_psk (std::vector<gr_complex> constellation,
- std::vector<unsigned int> pre_diff_code,
- unsigned int n_sectors);
-
- protected:
-
- unsigned int get_sector (const gr_complex *sample);
-
- unsigned int calc_sector_value (unsigned int sector);
-
- private:
-
- friend digital_constellation_psk_sptr
- digital_make_constellation_psk (std::vector<gr_complex> constellation,
- std::vector<unsigned int> pre_diff_code,
- unsigned int n_sectors);
-
-};
-
-/************************************************************/
-/* digital_constellation_bpsk */
-/* */
-/* Only works for BPSK. */
-/* */
-/************************************************************/
-
-class digital_constellation_bpsk;
-typedef boost::shared_ptr<digital_constellation_bpsk> digital_constellation_bpsk_sptr;
-
-// public constructor
-digital_constellation_bpsk_sptr
-digital_make_constellation_bpsk ();
-
-class digital_constellation_bpsk : public digital_constellation
-{
- public:
-
- digital_constellation_bpsk ();
- unsigned int decision_maker (const gr_complex *sample);
-
- friend digital_constellation_bpsk_sptr
- digital_make_constellation_bpsk ();
-
-};
-
-/************************************************************/
-/* digital_constellation_qpsk */
-/* */
-/* Only works for QPSK. */
-/* */
-/************************************************************/
-
-class digital_constellation_qpsk;
-typedef boost::shared_ptr<digital_constellation_qpsk> digital_constellation_qpsk_sptr;
-
-// public constructor
-digital_constellation_qpsk_sptr
-digital_make_constellation_qpsk ();
-
-class digital_constellation_qpsk : public digital_constellation
-{
- public:
-
- digital_constellation_qpsk ();
- unsigned int decision_maker (const gr_complex *sample);
-
- friend digital_constellation_qpsk_sptr
- digital_make_constellation_qpsk ();
-
-};
-
-
-/************************************************************/
-/* digital_constellation_8psk */
-/* */
-/* Only works for 8PSK. */
-/* */
-/************************************************************/
-
-class digital_constellation_8psk;
-typedef boost::shared_ptr<digital_constellation_8psk> digital_constellation_8psk_sptr;
-
-// public constructor
-digital_constellation_8psk_sptr
-digital_make_constellation_8psk ();
-
-class digital_constellation_8psk : public digital_constellation
-{
- public:
-
- digital_constellation_8psk ();
- unsigned int decision_maker (const gr_complex *sample);
-
- friend digital_constellation_8psk_sptr
- digital_make_constellation_8psk ();
-
-};
-
-#endif
diff --git a/gr-digital/lib/digital_constellation_decoder_cb.h b/gr-digital/lib/digital_constellation_decoder_cb.h
deleted file mode 100644
index 022456733..000000000
--- a/gr-digital/lib/digital_constellation_decoder_cb.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/* -*- 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
- digital_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
index 573c4e855..b9239962a 100644
--- a/gr-digital/lib/digital_constellation_receiver_cb.cc
+++ b/gr-digital/lib/digital_constellation_receiver_cb.cc
@@ -40,23 +40,21 @@
digital_constellation_receiver_cb_sptr
digital_make_constellation_receiver_cb(digital_constellation_sptr constell,
- float alpha, float beta,
- float fmin, float fmax)
+ float loop_bw, float fmin, float fmax)
{
return gnuradio::get_initial_sptr(new digital_constellation_receiver_cb (constell,
- alpha, beta,
+ loop_bw,
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)
+ float loop_bw, 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_alpha(alpha), d_beta(beta), d_freq(0), d_max_freq(fmax), d_min_freq(fmin), d_phase(0),
+ gri_control_loop(loop_bw, fmax, fmin),
d_constellation(constellation),
d_current_const_point(0)
{
@@ -67,17 +65,9 @@ digital_constellation_receiver_cb::digital_constellation_receiver_cb (digital_co
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);
+ advance_loop(phase_error);
+ phase_wrap();
+ frequency_limit();
#if VERBOSE_COSTAS
printf("cl: phase_error: %f phase: %f freq: %f sample: %f+j%f constellation: %f+j%f\n",
@@ -113,10 +103,12 @@ digital_constellation_receiver_cb::general_work (int noutput_items,
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;
diff --git a/gr-digital/lib/digital_constellation_receiver_cb.h b/gr-digital/lib/digital_constellation_receiver_cb.h
deleted file mode 100644
index bf6fc51fa..000000000
--- a/gr-digital/lib/digital_constellation_receiver_cb.h
+++ /dev/null
@@ -1,149 +0,0 @@
-/* -*- 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/lib/digital_correlate_access_code_bb.cc b/gr-digital/lib/digital_correlate_access_code_bb.cc
new file mode 100644
index 000000000..f21b57d92
--- /dev/null
+++ b/gr-digital/lib/digital_correlate_access_code_bb.cc
@@ -0,0 +1,134 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2006,2010,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_correlate_access_code_bb.h>
+#include <gr_io_signature.h>
+#include <stdexcept>
+#include <gr_count_bits.h>
+#include <cstdio>
+
+
+#define VERBOSE 0
+
+
+digital_correlate_access_code_bb_sptr
+digital_make_correlate_access_code_bb (const std::string &access_code, int threshold)
+{
+ return gnuradio::get_initial_sptr(new digital_correlate_access_code_bb
+ (access_code, threshold));
+}
+
+
+digital_correlate_access_code_bb::digital_correlate_access_code_bb (
+ const std::string &access_code, int threshold)
+ : gr_sync_block ("correlate_access_code_bb",
+ gr_make_io_signature (1, 1, sizeof(char)),
+ gr_make_io_signature (1, 1, sizeof(char))),
+ d_data_reg(0), d_flag_reg(0), d_flag_bit(0), d_mask(0),
+ d_threshold(threshold)
+
+{
+ if (!set_access_code(access_code)){
+ fprintf(stderr, "digital_correlate_access_code_bb: access_code is > 64 bits\n");
+ throw std::out_of_range ("access_code is > 64 bits");
+ }
+}
+
+digital_correlate_access_code_bb::~digital_correlate_access_code_bb ()
+{
+}
+
+bool
+digital_correlate_access_code_bb::set_access_code(
+ const std::string &access_code)
+{
+ unsigned len = access_code.length(); // # of bytes in string
+ if (len > 64)
+ return false;
+
+ // set len top bits to 1.
+ d_mask = ((~0ULL) >> (64 - len)) << (64 - len);
+
+ d_flag_bit = 1LL << (64 - len); // Where we or-in new flag values.
+ // new data always goes in 0x0000000000000001
+ d_access_code = 0;
+ for (unsigned i=0; i < 64; i++){
+ d_access_code <<= 1;
+ if (i < len)
+ d_access_code |= access_code[i] & 1; // look at LSB only
+ }
+
+ return true;
+}
+
+int
+digital_correlate_access_code_bb::work (int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+ const unsigned char *in = (const unsigned char *) input_items[0];
+ unsigned char *out = (unsigned char *) output_items[0];
+
+ for (int i = 0; i < noutput_items; i++){
+
+ // compute output value
+ unsigned int t = 0;
+
+ t |= ((d_data_reg >> 63) & 0x1) << 0;
+ t |= ((d_flag_reg >> 63) & 0x1) << 1; // flag bit
+ out[i] = t;
+
+ // compute hamming distance between desired access code and current data
+ unsigned long long wrong_bits = 0;
+ unsigned int nwrong = d_threshold+1;
+ int new_flag = 0;
+
+ wrong_bits = (d_data_reg ^ d_access_code) & d_mask;
+ nwrong = gr_count_bits64(wrong_bits);
+
+ // test for access code with up to threshold errors
+ new_flag = (nwrong <= d_threshold);
+
+#if VERBOSE
+ if(new_flag) {
+ fprintf(stderr, "access code found: %llx\n", d_access_code);
+ }
+ else {
+ fprintf(stderr, "%llx ==> %llx\n", d_access_code, d_data_reg);
+ }
+#endif
+
+ // shift in new data and new flag
+ d_data_reg = (d_data_reg << 1) | (in[i] & 0x1);
+ d_flag_reg = (d_flag_reg << 1);
+ if (new_flag) {
+ d_flag_reg |= d_flag_bit;
+ }
+ }
+
+ return noutput_items;
+}
+
diff --git a/gr-digital/lib/digital_costas_loop_cc.cc b/gr-digital/lib/digital_costas_loop_cc.cc
index 5d98bde4c..370dc7e5c 100644
--- a/gr-digital/lib/digital_costas_loop_cc.cc
+++ b/gr-digital/lib/digital_costas_loop_cc.cc
@@ -30,31 +30,23 @@
#include <gr_sincos.h>
#include <gr_math.h>
-#define M_TWOPI (2*M_PI)
-
digital_costas_loop_cc_sptr
-digital_make_costas_loop_cc (float damping, float nat_freq,
- int order
+digital_make_costas_loop_cc (float loop_bw, int order
) throw (std::invalid_argument)
{
- return gnuradio::get_initial_sptr(new digital_costas_loop_cc (damping,
- nat_freq,
- order));
+ return gnuradio::get_initial_sptr(new digital_costas_loop_cc
+ (loop_bw, order));
}
-digital_costas_loop_cc::digital_costas_loop_cc (float damping, float nat_freq,
- int order
+digital_costas_loop_cc::digital_costas_loop_cc (float loop_bw, int order
) throw (std::invalid_argument)
: gr_sync_block ("costas_loop_cc",
gr_make_io_signature (1, 1, sizeof (gr_complex)),
gr_make_io_signature2 (1, 2, sizeof (gr_complex), sizeof(float))),
- d_max_freq(1.0), d_min_freq(-1.0), d_phase(0), d_freq(0.0),
- d_nat_freq(nat_freq), d_damping(damping),
+ gri_control_loop(loop_bw, 1.0, -1.0),
d_order(order), d_phase_detector(NULL)
{
- // initialize gains from the natural freq and damping factors
- update_gains();
-
+ // Set up the phase detector to use based on the constellation order
switch(d_order) {
case 2:
d_phase_detector = &digital_costas_loop_cc::phase_detector_2;
@@ -115,27 +107,6 @@ digital_costas_loop_cc::phase_detector_2(gr_complex sample) const
return (sample.real()*sample.imag());
}
-void
-digital_costas_loop_cc::set_natural_freq(float w)
-{
- d_nat_freq = w;
- update_gains();
-}
-
-void
-digital_costas_loop_cc::set_damping_factor(float eta)
-{
- d_damping = eta;
- update_gains();
-}
-
-void
-digital_costas_loop_cc::update_gains()
-{
- d_beta = d_nat_freq*d_nat_freq;
- d_alpha = 2*d_damping*d_nat_freq;
-}
-
int
digital_costas_loop_cc::work (int noutput_items,
gr_vector_const_void_star &input_items,
@@ -159,18 +130,9 @@ digital_costas_loop_cc::work (int noutput_items,
error = (*this.*d_phase_detector)(optr[i]);
error = gr_branchless_clip(error, 1.0);
- d_freq = d_freq + d_beta * error;
- d_phase = d_phase + d_freq + d_alpha * error;
-
- while(d_phase>M_TWOPI)
- d_phase -= M_TWOPI;
- while(d_phase<-M_TWOPI)
- d_phase += M_TWOPI;
-
- if (d_freq > d_max_freq)
- d_freq = d_min_freq;
- else if (d_freq < d_min_freq)
- d_freq = d_max_freq;
+ advance_loop(error);
+ phase_wrap();
+ frequency_limit();
foptr[i] = d_freq;
}
@@ -181,20 +143,10 @@ digital_costas_loop_cc::work (int noutput_items,
error = (*this.*d_phase_detector)(optr[i]);
error = gr_branchless_clip(error, 1.0);
-
- d_freq = d_freq + d_beta * error;
- d_phase = d_phase + d_freq + d_alpha * error;
-
- while(d_phase>M_TWOPI)
- d_phase -= M_TWOPI;
- while(d_phase<-M_TWOPI)
- d_phase += M_TWOPI;
-
- if (d_freq > d_max_freq)
- d_freq = d_min_freq;
- else if (d_freq < d_min_freq)
- d_freq = d_max_freq;
-
+
+ advance_loop(error);
+ phase_wrap();
+ frequency_limit();
}
}
return noutput_items;
diff --git a/gr-digital/lib/digital_costas_loop_cc.h b/gr-digital/lib/digital_costas_loop_cc.h
deleted file mode 100644
index 9c112d328..000000000
--- a/gr-digital/lib/digital_costas_loop_cc.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/* -*- 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.
- */
-
-
-#ifndef INCLUDED_DIGITAL_COSTAS_LOOP_CC_H
-#define INCLUDED_DIGITAL_COSTAS_LOOP_CC_H
-
-#include <gr_sync_block.h>
-#include <stdexcept>
-#include <fstream>
-
-
-/*! \brief A Costas loop carrier recovery module.
- * \ingroup sync_blk
- *
- * The Costas loop locks to the center frequency of a signal and
- * downconverts it to baseband. The second (order=2) order loop is
- * used for BPSK where the real part of the output signal is the
- * baseband BPSK signal and the imaginary part is the error
- * signal. When order=4, it can be used for quadrature modulations
- * where both I and Q (real and imaginary) are outputted.
- *
- * More details can be found online:
- *
- * J. Feigin, "Practical Costas loop design: Designing a simple and inexpensive
- * BPSK Costas loop carrier recovery circuit," RF signal processing, pp. 20-36,
- * 2002.
- *
- * http://rfdesign.com/images/archive/0102Feigin20.pdf
- *
- * \param alpha the loop gain used for phase adjustment
- * \param beta the loop gain for frequency adjustments
- * \param max_freq the maximum frequency deviation (radians/sample) the loop can handle
- * \param min_freq the minimum frequency deviation (radians/sample) the loop can handle
- * \param order the loop order, either 2 or 4
- */
-class digital_costas_loop_cc;
-typedef boost::shared_ptr<digital_costas_loop_cc> digital_costas_loop_cc_sptr;
-
-
-digital_costas_loop_cc_sptr
-digital_make_costas_loop_cc (float damping, float nat_freq,
- int order
- ) throw (std::invalid_argument);
-
-
-/*!
- * \brief Carrier tracking PLL for QPSK
- * \ingroup sync_blk
- * input: complex; output: complex
- * <br>The Costas loop can have two output streams:
- * stream 1 is the baseband I and Q;
- * stream 2 is the normalized frequency of the loop
- *
- * \p order must be 2 or 4.
- */
-class digital_costas_loop_cc : public gr_sync_block
-{
- friend digital_costas_loop_cc_sptr
- digital_make_costas_loop_cc (float damping, float nat_freq,
- int order
- ) throw (std::invalid_argument);
-
- float d_alpha, d_beta, d_max_freq, d_min_freq, d_phase, d_freq;
- float d_nat_freq, d_damping;
- int d_order;
-
- digital_costas_loop_cc (float damping, float nat_freq,
- int order
- ) throw (std::invalid_argument);
-
-
- /*! \brief update the system gains from omega and eta
- *
- * This function updates the system gains based on the natural
- * frequency (omega) and damping factor (eta) of the system.
- * These two factors can be set separately through their own
- * set functions.
- *
- * These equations are summarized nicely in this paper from Berkeley:
- * http://www.complextoreal.com/chapters/pll.pdf
- */
- void update_gains();
-
- /*! \brief the phase detector circuit for 8th-order PSK loops
- * \param sample complex sample
- * \return the phase error
- */
- float phase_detector_8(gr_complex sample) const; // for 8PSK
-
- /*! \brief the phase detector circuit for fourth-order loops
- * \param sample complex sample
- * \return the phase error
- */
- float phase_detector_4(gr_complex sample) const; // for QPSK
-
- /*! \brief the phase detector circuit for second-order loops
- * \param sample a complex sample
- * \return the phase error
- */
- float phase_detector_2(gr_complex sample) const; // for BPSK
-
-
- float (digital_costas_loop_cc::*d_phase_detector)(gr_complex sample) const;
-
-public:
-
- void set_natural_freq(float w);
- void set_damping_factor(float eta);
-
- /*! \brief get the first order gain
- *
- */
- float alpha() const { return d_alpha; }
-
- /*! \brief get the second order gain
- *
- */
- float beta() const { return d_beta; }
-
- int work (int noutput_items,
- gr_vector_const_void_star &input_items,
- gr_vector_void_star &output_items);
-
- /*! \brief returns the current NCO frequency in radians/sample
- *
- */
- float freq() const { return d_freq; }
-};
-
-#endif
diff --git a/gr-digital/lib/digital_cpmmod_bc.cc b/gr-digital/lib/digital_cpmmod_bc.cc
new file mode 100644
index 000000000..a95b604d1
--- /dev/null
+++ b/gr-digital/lib/digital_cpmmod_bc.cc
@@ -0,0 +1,69 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010 Free Software Foundation, Inc.
+ *
+ * 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_cpmmod_bc.h>
+#include <gr_io_signature.h>
+
+
+// Shared pointer constructor
+digital_cpmmod_bc_sptr
+digital_make_cpmmod_bc(int type, float h,
+ unsigned samples_per_sym,
+ unsigned L, double beta)
+{
+ return gnuradio::get_initial_sptr(new digital_cpmmod_bc((gr_cpm::cpm_type)type,
+ h, samples_per_sym,
+ L, beta));
+}
+
+
+digital_cpmmod_bc::digital_cpmmod_bc(gr_cpm::cpm_type type, float h,
+ unsigned samples_per_sym,
+ unsigned L, double beta)
+ : gr_hier_block2("digital_cpmmod_bc",
+ gr_make_io_signature(1, 1, sizeof(char)),
+ gr_make_io_signature2(1, 1, sizeof(gr_complex), sizeof(float))),
+ d_taps(gr_cpm::phase_response(type, samples_per_sym, L, beta)),
+ d_char_to_float(gr_make_char_to_float()),
+ d_pulse_shaper(gr_make_interp_fir_filter_fff(samples_per_sym, d_taps)),
+ d_fm(gr_make_frequency_modulator_fc(M_PI * h))
+{
+ switch (type) {
+ case gr_cpm::LRC:
+ case gr_cpm::LSRC:
+ case gr_cpm::LREC:
+ case gr_cpm::TFM:
+ case gr_cpm::GAUSSIAN:
+ break;
+
+ default:
+ throw std::invalid_argument("invalid CPM type");
+ }
+
+ connect(self(), 0, d_char_to_float, 0);
+ connect(d_char_to_float, 0, d_pulse_shaper, 0);
+ connect(d_pulse_shaper, 0, d_fm, 0);
+ connect(d_fm, 0, self(), 0);
+}
+
diff --git a/gr-digital/lib/digital_crc32.cc b/gr-digital/lib/digital_crc32.cc
new file mode 100644
index 000000000..8806d6e9c
--- /dev/null
+++ b/gr-digital/lib/digital_crc32.cc
@@ -0,0 +1,130 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2005,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.
+ */
+
+/*
+ * See also ISO 3309 [ISO-3309] or ITU-T V.42 [ITU-V42] for a formal specification.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <digital_crc32.h>
+
+
+// Automatically generated CRC function
+// polynomial: 0x104C11DB7
+unsigned int
+digital_update_crc32(unsigned int crc, const unsigned char *data, size_t len)
+{
+ static const unsigned int table[256] = {
+ 0x00000000U,0x04C11DB7U,0x09823B6EU,0x0D4326D9U,
+ 0x130476DCU,0x17C56B6BU,0x1A864DB2U,0x1E475005U,
+ 0x2608EDB8U,0x22C9F00FU,0x2F8AD6D6U,0x2B4BCB61U,
+ 0x350C9B64U,0x31CD86D3U,0x3C8EA00AU,0x384FBDBDU,
+ 0x4C11DB70U,0x48D0C6C7U,0x4593E01EU,0x4152FDA9U,
+ 0x5F15ADACU,0x5BD4B01BU,0x569796C2U,0x52568B75U,
+ 0x6A1936C8U,0x6ED82B7FU,0x639B0DA6U,0x675A1011U,
+ 0x791D4014U,0x7DDC5DA3U,0x709F7B7AU,0x745E66CDU,
+ 0x9823B6E0U,0x9CE2AB57U,0x91A18D8EU,0x95609039U,
+ 0x8B27C03CU,0x8FE6DD8BU,0x82A5FB52U,0x8664E6E5U,
+ 0xBE2B5B58U,0xBAEA46EFU,0xB7A96036U,0xB3687D81U,
+ 0xAD2F2D84U,0xA9EE3033U,0xA4AD16EAU,0xA06C0B5DU,
+ 0xD4326D90U,0xD0F37027U,0xDDB056FEU,0xD9714B49U,
+ 0xC7361B4CU,0xC3F706FBU,0xCEB42022U,0xCA753D95U,
+ 0xF23A8028U,0xF6FB9D9FU,0xFBB8BB46U,0xFF79A6F1U,
+ 0xE13EF6F4U,0xE5FFEB43U,0xE8BCCD9AU,0xEC7DD02DU,
+ 0x34867077U,0x30476DC0U,0x3D044B19U,0x39C556AEU,
+ 0x278206ABU,0x23431B1CU,0x2E003DC5U,0x2AC12072U,
+ 0x128E9DCFU,0x164F8078U,0x1B0CA6A1U,0x1FCDBB16U,
+ 0x018AEB13U,0x054BF6A4U,0x0808D07DU,0x0CC9CDCAU,
+ 0x7897AB07U,0x7C56B6B0U,0x71159069U,0x75D48DDEU,
+ 0x6B93DDDBU,0x6F52C06CU,0x6211E6B5U,0x66D0FB02U,
+ 0x5E9F46BFU,0x5A5E5B08U,0x571D7DD1U,0x53DC6066U,
+ 0x4D9B3063U,0x495A2DD4U,0x44190B0DU,0x40D816BAU,
+ 0xACA5C697U,0xA864DB20U,0xA527FDF9U,0xA1E6E04EU,
+ 0xBFA1B04BU,0xBB60ADFCU,0xB6238B25U,0xB2E29692U,
+ 0x8AAD2B2FU,0x8E6C3698U,0x832F1041U,0x87EE0DF6U,
+ 0x99A95DF3U,0x9D684044U,0x902B669DU,0x94EA7B2AU,
+ 0xE0B41DE7U,0xE4750050U,0xE9362689U,0xEDF73B3EU,
+ 0xF3B06B3BU,0xF771768CU,0xFA325055U,0xFEF34DE2U,
+ 0xC6BCF05FU,0xC27DEDE8U,0xCF3ECB31U,0xCBFFD686U,
+ 0xD5B88683U,0xD1799B34U,0xDC3ABDEDU,0xD8FBA05AU,
+ 0x690CE0EEU,0x6DCDFD59U,0x608EDB80U,0x644FC637U,
+ 0x7A089632U,0x7EC98B85U,0x738AAD5CU,0x774BB0EBU,
+ 0x4F040D56U,0x4BC510E1U,0x46863638U,0x42472B8FU,
+ 0x5C007B8AU,0x58C1663DU,0x558240E4U,0x51435D53U,
+ 0x251D3B9EU,0x21DC2629U,0x2C9F00F0U,0x285E1D47U,
+ 0x36194D42U,0x32D850F5U,0x3F9B762CU,0x3B5A6B9BU,
+ 0x0315D626U,0x07D4CB91U,0x0A97ED48U,0x0E56F0FFU,
+ 0x1011A0FAU,0x14D0BD4DU,0x19939B94U,0x1D528623U,
+ 0xF12F560EU,0xF5EE4BB9U,0xF8AD6D60U,0xFC6C70D7U,
+ 0xE22B20D2U,0xE6EA3D65U,0xEBA91BBCU,0xEF68060BU,
+ 0xD727BBB6U,0xD3E6A601U,0xDEA580D8U,0xDA649D6FU,
+ 0xC423CD6AU,0xC0E2D0DDU,0xCDA1F604U,0xC960EBB3U,
+ 0xBD3E8D7EU,0xB9FF90C9U,0xB4BCB610U,0xB07DABA7U,
+ 0xAE3AFBA2U,0xAAFBE615U,0xA7B8C0CCU,0xA379DD7BU,
+ 0x9B3660C6U,0x9FF77D71U,0x92B45BA8U,0x9675461FU,
+ 0x8832161AU,0x8CF30BADU,0x81B02D74U,0x857130C3U,
+ 0x5D8A9099U,0x594B8D2EU,0x5408ABF7U,0x50C9B640U,
+ 0x4E8EE645U,0x4A4FFBF2U,0x470CDD2BU,0x43CDC09CU,
+ 0x7B827D21U,0x7F436096U,0x7200464FU,0x76C15BF8U,
+ 0x68860BFDU,0x6C47164AU,0x61043093U,0x65C52D24U,
+ 0x119B4BE9U,0x155A565EU,0x18197087U,0x1CD86D30U,
+ 0x029F3D35U,0x065E2082U,0x0B1D065BU,0x0FDC1BECU,
+ 0x3793A651U,0x3352BBE6U,0x3E119D3FU,0x3AD08088U,
+ 0x2497D08DU,0x2056CD3AU,0x2D15EBE3U,0x29D4F654U,
+ 0xC5A92679U,0xC1683BCEU,0xCC2B1D17U,0xC8EA00A0U,
+ 0xD6AD50A5U,0xD26C4D12U,0xDF2F6BCBU,0xDBEE767CU,
+ 0xE3A1CBC1U,0xE760D676U,0xEA23F0AFU,0xEEE2ED18U,
+ 0xF0A5BD1DU,0xF464A0AAU,0xF9278673U,0xFDE69BC4U,
+ 0x89B8FD09U,0x8D79E0BEU,0x803AC667U,0x84FBDBD0U,
+ 0x9ABC8BD5U,0x9E7D9662U,0x933EB0BBU,0x97FFAD0CU,
+ 0xAFB010B1U,0xAB710D06U,0xA6322BDFU,0xA2F33668U,
+ 0xBCB4666DU,0xB8757BDAU,0xB5365D03U,0xB1F740B4U,
+ };
+
+ while (len > 0)
+ {
+ crc = table[*data ^ ((crc >> 24) & 0xff)] ^ (crc << 8);
+ data++;
+ len--;
+ }
+ return crc;
+}
+
+unsigned int
+digital_update_crc32(unsigned int crc, const std::string s)
+{
+ return digital_update_crc32(crc, (const unsigned char *) s.data(), s.size());
+}
+
+unsigned int
+digital_crc32(const unsigned char *buf, size_t len)
+{
+ return digital_update_crc32(0xffffffff, buf, len) ^ 0xffffffff;
+}
+
+unsigned int
+digital_crc32(const std::string s)
+{
+ return digital_crc32((const unsigned char *) s.data(), s.size());
+}
diff --git a/gr-digital/lib/digital_fll_band_edge_cc.cc b/gr-digital/lib/digital_fll_band_edge_cc.cc
new file mode 100644
index 000000000..05c092622
--- /dev/null
+++ b/gr-digital/lib/digital_fll_band_edge_cc.cc
@@ -0,0 +1,259 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009-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_fll_band_edge_cc.h>
+#include <gr_io_signature.h>
+#include <gr_expj.h>
+#include <cstdio>
+
+#define M_TWOPI (2*M_PI)
+
+float sinc(float x)
+{
+ if(x == 0)
+ return 1;
+ else
+ return sin(M_PI*x)/(M_PI*x);
+}
+
+digital_fll_band_edge_cc_sptr
+digital_make_fll_band_edge_cc (float samps_per_sym, float rolloff,
+ int filter_size, float bandwidth)
+{
+ return gnuradio::get_initial_sptr(new digital_fll_band_edge_cc (samps_per_sym, rolloff,
+ filter_size, bandwidth));
+}
+
+
+static int ios[] = {sizeof(gr_complex), sizeof(float), sizeof(float), sizeof(float)};
+static std::vector<int> iosig(ios, ios+sizeof(ios)/sizeof(int));
+digital_fll_band_edge_cc::digital_fll_band_edge_cc (float samps_per_sym, float rolloff,
+ int filter_size, float bandwidth)
+ : gr_sync_block ("fll_band_edge_cc",
+ gr_make_io_signature (1, 1, sizeof(gr_complex)),
+ gr_make_io_signaturev (1, 4, iosig)),
+ gri_control_loop(bandwidth, M_TWOPI*(2.0/samps_per_sym), -M_TWOPI*(2.0/samps_per_sym)),
+ d_updated (false)
+{
+ // Initialize samples per symbol
+ if(samps_per_sym <= 0) {
+ throw std::out_of_range ("digital_fll_band_edge_cc: invalid number of sps. Must be > 0.");
+ }
+ d_sps = samps_per_sym;
+
+ // Initialize rolloff factor
+ if(rolloff < 0 || rolloff > 1.0) {
+ throw std::out_of_range ("digital_fll_band_edge_cc: invalid rolloff factor. Must be in [0,1].");
+ }
+ d_rolloff = rolloff;
+
+ // Initialize filter length
+ if(filter_size <= 0) {
+ throw std::out_of_range ("digital_fll_band_edge_cc: invalid filter size. Must be > 0.");
+ }
+ d_filter_size = filter_size;
+
+ // Build the band edge filters
+ design_filter(d_sps, d_rolloff, d_filter_size);
+}
+
+digital_fll_band_edge_cc::~digital_fll_band_edge_cc ()
+{
+}
+
+
+/*******************************************************************
+ SET FUNCTIONS
+*******************************************************************/
+
+void
+digital_fll_band_edge_cc::set_samples_per_symbol(float sps)
+{
+ if(sps <= 0) {
+ throw std::out_of_range ("digital_fll_band_edge_cc: invalid number of sps. Must be > 0.");
+ }
+ d_sps = sps;
+ design_filter(d_sps, d_rolloff, d_filter_size);
+}
+
+void
+digital_fll_band_edge_cc::set_rolloff(float rolloff)
+{
+ if(rolloff < 0 || rolloff > 1.0) {
+ throw std::out_of_range ("digital_fll_band_edge_cc: invalid rolloff factor. Must be in [0,1].");
+ }
+ d_rolloff = rolloff;
+ design_filter(d_sps, d_rolloff, d_filter_size);
+}
+
+void
+digital_fll_band_edge_cc::set_filter_size(int filter_size)
+{
+ if(filter_size <= 0) {
+ throw std::out_of_range ("digital_fll_band_edge_cc: invalid filter size. Must be > 0.");
+ }
+ d_filter_size = filter_size;
+ design_filter(d_sps, d_rolloff, d_filter_size);
+}
+
+/*******************************************************************
+ GET FUNCTIONS
+*******************************************************************/
+
+float
+digital_fll_band_edge_cc::get_samples_per_symbol() const
+{
+ return d_sps;
+}
+
+float
+digital_fll_band_edge_cc::get_rolloff() const
+{
+ return d_rolloff;
+}
+
+int
+digital_fll_band_edge_cc:: get_filter_size() const
+{
+ return d_filter_size;
+}
+
+
+/*******************************************************************
+*******************************************************************/
+
+void
+digital_fll_band_edge_cc::design_filter(float samps_per_sym,
+ float rolloff, int filter_size)
+{
+ int M = rint(filter_size / samps_per_sym);
+ float power = 0;
+
+ // Create the baseband filter by adding two sincs together
+ std::vector<float> bb_taps;
+ for(int i = 0; i < filter_size; i++) {
+ float k = -M + i*2.0/samps_per_sym;
+ float tap = sinc(rolloff*k - 0.5) + sinc(rolloff*k + 0.5);
+ power += tap;
+
+ bb_taps.push_back(tap);
+ }
+
+ d_taps_lower.resize(filter_size);
+ d_taps_upper.resize(filter_size);
+
+ // Create the band edge filters by spinning the baseband
+ // filter up and down to the right places in frequency.
+ // Also, normalize the power in the filters
+ int N = (bb_taps.size() - 1.0)/2.0;
+ for(int i = 0; i < filter_size; i++) {
+ float tap = bb_taps[i] / power;
+
+ float k = (-N + (int)i)/(2.0*samps_per_sym);
+
+ gr_complex t1 = tap * gr_expj(-M_TWOPI*(1+rolloff)*k);
+ gr_complex t2 = tap * gr_expj(M_TWOPI*(1+rolloff)*k);
+
+ d_taps_lower[filter_size-i-1] = t1;
+ d_taps_upper[filter_size-i-1] = t2;
+ }
+
+ d_updated = true;
+
+ // Set the history to ensure enough input items for each filter
+ set_history(filter_size+1);
+}
+
+void
+digital_fll_band_edge_cc::print_taps()
+{
+ unsigned int i;
+
+ printf("Upper Band-edge: [");
+ for(i = 0; i < d_taps_upper.size(); i++) {
+ printf(" %.4e + %.4ej,", d_taps_upper[i].real(), d_taps_upper[i].imag());
+ }
+ printf("]\n\n");
+
+ printf("Lower Band-edge: [");
+ for(i = 0; i < d_taps_lower.size(); i++) {
+ printf(" %.4e + %.4ej,", d_taps_lower[i].real(), d_taps_lower[i].imag());
+ }
+ printf("]\n\n");
+}
+
+int
+digital_fll_band_edge_cc::work (int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+ const gr_complex *in = (const gr_complex *) input_items[0];
+ gr_complex *out = (gr_complex *) output_items[0];
+
+ float *frq = NULL;
+ float *phs = NULL;
+ float *err = NULL;
+ if(output_items.size() == 4) {
+ frq = (float *) output_items[1];
+ phs = (float *) output_items[2];
+ err = (float *) output_items[3];
+ }
+
+ if (d_updated) {
+ d_updated = false;
+ return 0; // history requirements may have changed.
+ }
+
+ int i;
+ float error;
+ gr_complex nco_out;
+ gr_complex out_upper, out_lower;
+ for(i = 0; i < noutput_items; i++) {
+ nco_out = gr_expj(d_phase);
+ out[i+d_filter_size-1] = in[i] * nco_out;
+
+ // Perform the dot product of the output with the filters
+ out_upper = 0;
+ out_lower = 0;
+ for(int k = 0; k < d_filter_size; k++) {
+ out_upper += d_taps_upper[k] * out[i+k];
+ out_lower += d_taps_lower[k] * out[i+k];
+ }
+ error = norm(out_lower) - norm(out_upper);
+
+ advance_loop(error);
+ phase_wrap();
+ frequency_limit();
+
+ if(output_items.size() == 4) {
+ frq[i] = d_freq;
+ phs[i] = d_phase;
+ err[i] = error;
+ }
+ }
+
+ return noutput_items;
+}
diff --git a/gr-digital/lib/digital_metric_type.h b/gr-digital/lib/digital_gmskmod_bc.cc
index 83de166f0..e53e90037 100644
--- a/gr-digital/lib/digital_metric_type.h
+++ b/gr-digital/lib/digital_gmskmod_bc.cc
@@ -1,31 +1,44 @@
/* -*- c++ -*- */
/*
- * Copyright 2004 Free Software Foundation, Inc.
- *
+ * Copyright 2010 Free Software Foundation, Inc.
+ *
* This file is part of GNU Radio
*
* GNU Radio is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
- *
+ *
* GNU Radio is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with GNU Radio; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
-#ifndef INCLUDED_DIGITAL_METRIC_TYPE_H
-#define INCLUDED_DIGITAL_METRIC_TYPE_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
-typedef enum {
- TRELLIS_EUCLIDEAN = 200, TRELLIS_HARD_SYMBOL, TRELLIS_HARD_BIT
-} trellis_metric_type_t;
+#include <digital_gmskmod_bc.h>
+#include <gr_io_signature.h>
-#endif
+// Shared pointer constructor
+digital_gmskmod_bc_sptr
+digital_make_gmskmod_bc(unsigned samples_per_sym,
+ double bt, unsigned L)
+{
+ return gnuradio::get_initial_sptr(new digital_gmskmod_bc(samples_per_sym, bt, L));
+}
+
+
+digital_gmskmod_bc::digital_gmskmod_bc(unsigned samples_per_sym,
+ double bt, unsigned L)
+ : digital_cpmmod_bc(gr_cpm::GAUSSIAN, 0.5, samples_per_sym, L, bt)
+{
+}
diff --git a/gr-digital/lib/digital_kurtotic_equalizer_cc.h b/gr-digital/lib/digital_kurtotic_equalizer_cc.h
deleted file mode 100644
index e01cbd6e6..000000000
--- a/gr-digital/lib/digital_kurtotic_equalizer_cc.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/* -*- 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_KURTOTIC_EQUALIZER_CC_H
-#define INCLUDED_DIGITAL_KURTOTIC_EQUALIZER_CC_H
-
-#include <gr_adaptive_fir_ccc.h>
-#include <gr_math.h>
-#include <iostream>
-
-class digital_kurtotic_equalizer_cc;
-typedef boost::shared_ptr<digital_kurtotic_equalizer_cc> digital_kurtotic_equalizer_cc_sptr;
-
-digital_kurtotic_equalizer_cc_sptr
-digital_make_kurtotic_equalizer_cc(int num_taps, float mu);
-
-/*!
- * \brief Implements a kurtosis-based adaptive equalizer on complex stream
- * \ingroup eq_blk
- *
- * Y. Guo, J. Zhao, Y. Sun, "Sign kurtosis maximization based blind
- * equalization algorithm," IEEE Conf. on Control, Automation,
- * Robotics and Vision, Vol. 3, Dec. 2004, pp. 2052 - 2057.
- */
-class digital_kurtotic_equalizer_cc : public gr_adaptive_fir_ccc
-{
-private:
- float d_mu;
- float d_p, d_m;
- gr_complex d_q, d_u;
- float d_alpha_p, d_alpha_q, d_alpha_m;
-
- friend digital_kurtotic_equalizer_cc_sptr digital_make_kurtotic_equalizer_cc(int num_taps,
- float mu);
- digital_kurtotic_equalizer_cc(int num_taps, float mu);
-
- gr_complex sign(gr_complex x)
- {
- float re = (float)(x.real() >= 0.0f);
- float im = (float)(x.imag() >= 0.0f);
- return gr_complex(re, im);
- }
-
-protected:
-
- virtual gr_complex error(const gr_complex &out)
- {
-
- // p = E[|z|^2]
- // q = E[z^2]
- // m = E[|z|^4]
- // u = E[kurtosis(z)]
-
- float nrm = norm(out);
- gr_complex cnj = conj(out);
- float epsilon_f = 1e-12;
- gr_complex epsilon_c = gr_complex(1e-12, 1e-12);
-
-
- d_p = (1-d_alpha_p)*d_p + (d_alpha_p)*nrm + epsilon_f;
- d_q = (1-d_alpha_q)*d_q + (d_alpha_q)*out*out + epsilon_c;
- d_m = (1-d_alpha_m)*d_m + (d_alpha_m)*nrm*nrm + epsilon_f;
- d_u = d_m - 2.0f*(d_p*d_p) - d_q*d_q;
-
- gr_complex F = (1.0f / (d_p*d_p*d_p)) *
- (sign(d_u) * (nrm*cnj - 2.0f*d_p*cnj - conj(d_q)*out) -
- abs(d_u)*cnj);
-
- //std::cout << "out: " << out << " p: " << d_p << " q: " << d_q;
- //std::cout << " m: " << d_m << " u: " << d_u << std::endl;
- //std::cout << "error: " << F << std::endl;
-
- float re = gr_clip(F.real(), 1.0);
- float im = gr_clip(F.imag(), 1.0);
- return gr_complex(re, im);
- }
-
- virtual void update_tap(gr_complex &tap, const gr_complex &in)
- {
- tap += d_mu*in*d_error;
- }
-
-public:
- void set_gain(float mu)
- {
- if(mu < 0)
- throw std::out_of_range("digital_kurtotic_equalizer::set_gain: Gain value must be >= 0");
- d_mu = mu;
- }
-};
-
-#endif
diff --git a/gr-digital/lib/digital_lms_dd_equalizer_cc.h b/gr-digital/lib/digital_lms_dd_equalizer_cc.h
deleted file mode 100644
index e3ad4bf4a..000000000
--- a/gr-digital/lib/digital_lms_dd_equalizer_cc.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/* -*- 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_LMS_DD_EQUALIZER_CC_H
-#define INCLUDED_DIGITAL_LMS_DD_EQUALIZER_CC_H
-
-#include <gr_adaptive_fir_ccc.h>
-#include <digital_constellation.h>
-
-class digital_lms_dd_equalizer_cc;
-typedef boost::shared_ptr<digital_lms_dd_equalizer_cc> digital_lms_dd_equalizer_cc_sptr;
-
-digital_lms_dd_equalizer_cc_sptr digital_make_lms_dd_equalizer_cc (int num_taps,
- float mu, int sps,
- digital_constellation_sptr cnst);
-
-/*!
- * \brief Least-Mean-Square Decision Directed Equalizer (complex in/out)
- * \ingroup eq_blk
- *
- * This block implements an LMS-based decision-directed equalizer.
- * It uses a set of weights, w, to correlate against the inputs, u,
- * and a decisions is then made from this output. The error
- * in the decision is used to update teh weight vector.
- *
- * y[n] = conj(w[n]) u[n]
- * d[n] = decision(y[n])
- * e[n] = d[n] - y[n]
- * w[n+1] = w[n] + mu u[n] conj(e[n])
- *
- * Where mu is a gain value (between 0 and 1 and usualy small,
- * around 0.001 - 0.01.
- *
- * This block uses the digital_constellation object for making
- * the decision from y[n]. Create the constellation object for
- * whatever constellation is to be used and pass in the object.
- * In Python, you can use something like:
- * self.constellation = digital.constellation_qpsk()
- * To create a QPSK constellation (see the digital_constellation
- * block for more details as to what constellations are available
- * or how to create your own). You then pass the object to this
- * block as an sptr, or using "self.constellation.base()".
- *
- * The theory for this algorithm can be found in Chapter 9 of:
- * S. Haykin, Adaptive Filter Theory, Upper Saddle River, NJ:
- * Prentice Hall, 1996.
- *
- */
-class digital_lms_dd_equalizer_cc : public gr_adaptive_fir_ccc
-{
-private:
- friend digital_lms_dd_equalizer_cc_sptr digital_make_lms_dd_equalizer_cc (int num_taps,
- float mu, int sps,
- digital_constellation_sptr cnst);
-
- float d_mu;
- std::vector<gr_complex> d_taps;
- digital_constellation_sptr d_cnst;
-
- digital_lms_dd_equalizer_cc (int num_taps,
- float mu, int sps,
- digital_constellation_sptr cnst);
-
-protected:
-
- virtual gr_complex error(const gr_complex &out)
- {
- gr_complex decision, error;
- d_cnst->map_to_points(d_cnst->decision_maker(&out), &decision);
- error = decision - out;
- return error;
- }
-
- virtual void update_tap(gr_complex &tap, const gr_complex &in)
- {
- tap += d_mu*conj(in)*d_error;
- }
-
-public:
- float get_gain()
- {
- return d_mu;
- }
-
- void set_gain(float mu)
- {
- if(mu < 0.0f || mu > 1.0f) {
- throw std::out_of_range("digital_lms_dd_equalizer::set_mu: Gain value must in [0, 1]");
- }
- else {
- d_mu = mu;
- }
- }
-
-};
-
-#endif
diff --git a/gr-digital/lib/digital_mpsk_receiver_cc.cc b/gr-digital/lib/digital_mpsk_receiver_cc.cc
new file mode 100644
index 000000000..363b86c9f
--- /dev/null
+++ b/gr-digital/lib/digital_mpsk_receiver_cc.cc
@@ -0,0 +1,316 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2005,2006,2007,2010,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_mpsk_receiver_cc.h>
+#include <stdexcept>
+#include <gr_math.h>
+#include <gr_expj.h>
+#include <gri_mmse_fir_interpolator_cc.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_mpsk_receiver_cc_sptr
+digital_make_mpsk_receiver_cc(unsigned int M, float theta,
+ float loop_bw,
+ float fmin, float fmax,
+ float mu, float gain_mu,
+ float omega, float gain_omega, float omega_rel)
+{
+ return gnuradio::get_initial_sptr(new digital_mpsk_receiver_cc (M, theta,
+ loop_bw,
+ fmin, fmax,
+ mu, gain_mu,
+ omega, gain_omega,
+ omega_rel));
+}
+
+digital_mpsk_receiver_cc::digital_mpsk_receiver_cc (unsigned int M, float theta,
+ float loop_bw,
+ float fmin, float fmax,
+ float mu, float gain_mu,
+ float omega, float gain_omega,
+ float omega_rel)
+ : gr_block ("mpsk_receiver_cc",
+ gr_make_io_signature (1, 1, sizeof (gr_complex)),
+ gr_make_io_signature (1, 1, sizeof (gr_complex))),
+ gri_control_loop(loop_bw, fmax, fmin),
+ d_M(M), d_theta(theta),
+ d_current_const_point(0),
+ d_mu(mu), d_gain_mu(gain_mu), d_gain_omega(gain_omega),
+ d_omega_rel(omega_rel), d_max_omega(0), d_min_omega(0),
+ d_p_2T(0), d_p_1T(0), d_p_0T(0), d_c_2T(0), d_c_1T(0), d_c_0T(0)
+{
+ d_interp = new gri_mmse_fir_interpolator_cc();
+ d_dl_idx = 0;
+
+ set_omega(omega);
+
+ if (omega <= 0.0)
+ throw std::out_of_range ("clock rate must be > 0");
+ if (gain_mu < 0 || gain_omega < 0)
+ throw std::out_of_range ("Gains must be non-negative");
+
+ assert(d_interp->ntaps() <= DLLEN);
+
+ // zero double length delay line.
+ for (unsigned int i = 0; i < 2 * DLLEN; i++)
+ d_dl[i] = gr_complex(0.0,0.0);
+
+ // build the constellation vector from M
+ make_constellation();
+
+ // Select a phase detector and a decision maker for the modulation order
+ switch(d_M) {
+ case 2: // optimized algorithms for BPSK
+ d_phase_error_detector = &digital_mpsk_receiver_cc::phase_error_detector_bpsk; //bpsk;
+ d_decision = &digital_mpsk_receiver_cc::decision_bpsk;
+ break;
+
+ case 4: // optimized algorithms for QPSK
+ d_phase_error_detector = &digital_mpsk_receiver_cc::phase_error_detector_qpsk; //qpsk;
+ d_decision = &digital_mpsk_receiver_cc::decision_qpsk;
+ break;
+
+ default: // generic algorithms for any M (power of 2?) but not pretty
+ d_phase_error_detector = &digital_mpsk_receiver_cc::phase_error_detector_generic;
+ d_decision = &digital_mpsk_receiver_cc::decision_generic;
+ break;
+ }
+}
+
+digital_mpsk_receiver_cc::~digital_mpsk_receiver_cc ()
+{
+ delete d_interp;
+}
+
+void
+digital_mpsk_receiver_cc::forecast(int noutput_items, gr_vector_int &ninput_items_required)
+{
+ unsigned ninputs = ninput_items_required.size();
+ for (unsigned i=0; i < ninputs; i++)
+ ninput_items_required[i] = (int) ceil((noutput_items * d_omega) + d_interp->ntaps());
+}
+
+// FIXME add these back in an test difference in performance
+float
+digital_mpsk_receiver_cc::phase_error_detector_qpsk(gr_complex sample) const
+{
+ float phase_error = 0;
+ if(fabsf(sample.real()) > fabsf(sample.imag())) {
+ if(sample.real() > 0)
+ phase_error = -sample.imag();
+ else
+ phase_error = sample.imag();
+ }
+ else {
+ if(sample.imag() > 0)
+ phase_error = sample.real();
+ else
+ phase_error = -sample.real();
+ }
+
+ return phase_error;
+}
+
+float
+digital_mpsk_receiver_cc::phase_error_detector_bpsk(gr_complex sample) const
+{
+ return -(sample.real()*sample.imag());
+}
+
+float digital_mpsk_receiver_cc::phase_error_detector_generic(gr_complex sample) const
+{
+ //return gr_fast_atan2f(sample*conj(d_constellation[d_current_const_point]));
+ return -arg(sample*conj(d_constellation[d_current_const_point]));
+}
+
+unsigned int
+digital_mpsk_receiver_cc::decision_bpsk(gr_complex sample) const
+{
+ return (gr_branchless_binary_slicer(sample.real()) ^ 1);
+ //return gr_binary_slicer(sample.real()) ^ 1;
+}
+
+unsigned int
+digital_mpsk_receiver_cc::decision_qpsk(gr_complex sample) const
+{
+ unsigned int index;
+
+ //index = gr_branchless_quad_0deg_slicer(sample);
+ index = gr_quad_0deg_slicer(sample);
+ return index;
+}
+
+unsigned int
+digital_mpsk_receiver_cc::decision_generic(gr_complex sample) const
+{
+ unsigned int min_m = 0;
+ float min_s = 65535;
+
+ // Develop all possible constellation points and find the one that minimizes
+ // the Euclidean distance (error) with the sample
+ for(unsigned int m=0; m < d_M; m++) {
+ gr_complex diff = norm(d_constellation[m] - sample);
+
+ if(fabs(diff.real()) < min_s) {
+ min_s = fabs(diff.real());
+ min_m = m;
+ }
+ }
+ // Return the index of the constellation point that minimizes the error
+ return min_m;
+}
+
+
+void
+digital_mpsk_receiver_cc::make_constellation()
+{
+ for(unsigned int m=0; m < d_M; m++) {
+ d_constellation.push_back(gr_expj((M_TWOPI/d_M)*m));
+ }
+}
+
+void
+digital_mpsk_receiver_cc::mm_sampler(const gr_complex symbol)
+{
+ gr_complex sample, nco;
+
+ d_mu--; // skip a number of symbols between sampling
+ d_phase += d_freq; // increment the phase based on the frequency of the rotation
+
+ // Keep phase clamped and not walk to infinity
+ while(d_phase > M_TWOPI)
+ d_phase -= M_TWOPI;
+ while(d_phase < -M_TWOPI)
+ d_phase += M_TWOPI;
+
+ nco = gr_expj(d_phase+d_theta); // get the NCO value for derotating the current sample
+ sample = nco*symbol; // get the downconverted symbol
+
+ // Fill up the delay line for the interpolator
+ d_dl[d_dl_idx] = sample;
+ d_dl[(d_dl_idx + DLLEN)] = sample; // put this in the second half of the buffer for overflows
+ d_dl_idx = (d_dl_idx+1) % DLLEN; // Keep the delay line index in bounds
+}
+
+void
+digital_mpsk_receiver_cc::mm_error_tracking(gr_complex sample)
+{
+ gr_complex u, x, y;
+ float mm_error = 0;
+
+ // Make sample timing corrections
+
+ // set the delayed samples
+ d_p_2T = d_p_1T;
+ d_p_1T = d_p_0T;
+ d_p_0T = sample;
+ d_c_2T = d_c_1T;
+ d_c_1T = d_c_0T;
+
+ d_current_const_point = (*this.*d_decision)(d_p_0T); // make a decision on the sample value
+ d_c_0T = d_constellation[d_current_const_point];
+
+ x = (d_c_0T - d_c_2T) * conj(d_p_1T);
+ y = (d_p_0T - d_p_2T) * conj(d_c_1T);
+ u = y - x;
+ mm_error = u.real(); // the error signal is in the real part
+ mm_error = gr_branchless_clip(mm_error, 1.0); // limit mm_val
+
+ d_omega = d_omega + d_gain_omega * mm_error; // update omega based on loop error
+ d_omega = d_omega_mid + gr_branchless_clip(d_omega-d_omega_mid, d_omega_rel); // make sure we don't walk away
+
+ d_mu += d_omega + d_gain_mu * mm_error; // update mu based on loop error
+
+#if VERBOSE_MM
+ printf("mm: mu: %f omega: %f mm_error: %f sample: %f+j%f constellation: %f+j%f\n",
+ d_mu, d_omega, mm_error, sample.real(), sample.imag(),
+ d_constellation[d_current_const_point].real(), d_constellation[d_current_const_point].imag());
+#endif
+}
+
+
+void
+digital_mpsk_receiver_cc::phase_error_tracking(gr_complex sample)
+{
+ float phase_error = 0;
+
+ // Make phase and frequency corrections based on sampled value
+ phase_error = (*this.*d_phase_error_detector)(sample);
+
+ advance_loop(phase_error);
+ phase_wrap();
+ frequency_limit();
+
+#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[d_current_const_point].real(), d_constellation[d_current_const_point].imag());
+#endif
+}
+
+int
+digital_mpsk_receiver_cc::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];
+ gr_complex *out = (gr_complex *) output_items[0];
+
+ int i=0, o=0;
+
+ while((o < noutput_items) && (i < ninput_items[0])) {
+ while((d_mu > 1) && (i < ninput_items[0])) {
+ mm_sampler(in[i]); // puts symbols into a buffer and adjusts d_mu
+ i++;
+ }
+
+ if(i < ninput_items[0]) {
+ gr_complex interp_sample = d_interp->interpolate(&d_dl[d_dl_idx], d_mu);
+
+ mm_error_tracking(interp_sample); // corrects M&M sample time
+ phase_error_tracking(interp_sample); // corrects phase and frequency offsets
+
+ out[o++] = interp_sample;
+ }
+ }
+
+ #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;
+}