[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Commit-gnuradio] [gnuradio] 01/02: gr-digital: Squashed commit containi
From: |
git |
Subject: |
[Commit-gnuradio] [gnuradio] 01/02: gr-digital: Squashed commit containing the MSK timing recovery block. |
Date: |
Wed, 15 Apr 2015 20:30:41 +0000 (UTC) |
This is an automated email from the git hooks/post-receive script.
jcorgan pushed a commit to branch master
in repository gnuradio.
commit a96e06b412bd2ac615bd233bd4e2460ec1f6d3a4
Author: Nick Foster <address@hidden>
Date: Wed Apr 15 12:40:28 2015 -0700
gr-digital: Squashed commit containing the MSK timing recovery block.
---
gr-digital/grc/digital_msk_timing_recovery_cc.xml | 49 +++++
gr-digital/include/gnuradio/digital/CMakeLists.txt | 1 +
.../gnuradio/digital/msk_timing_recovery_cc.h | 76 ++++++++
gr-digital/lib/CMakeLists.txt | 1 +
gr-digital/lib/msk_timing_recovery_cc_impl.cc | 210 +++++++++++++++++++++
gr-digital/lib/msk_timing_recovery_cc_impl.h | 72 +++++++
gr-digital/swig/digital_swig.i | 3 +
7 files changed, 412 insertions(+)
diff --git a/gr-digital/grc/digital_msk_timing_recovery_cc.xml
b/gr-digital/grc/digital_msk_timing_recovery_cc.xml
new file mode 100644
index 0000000..cda780d
--- /dev/null
+++ b/gr-digital/grc/digital_msk_timing_recovery_cc.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+<block>
+ <name>MSK Timing Recovery</name>
+ <key>digital_msk_timing_recovery_cc</key>
+ <import>from gnuradio import digital</import>
+ <make>digital.msk_timing_recovery_cc($sps, $gain, $limit, $osps)</make>
+ <callback>set_gain($gain)</callback>
+ <callback>set_sps($sps)</callback>
+ <callback>set_limit($limit)</callback>
+ <param>
+ <name>Gain</name>
+ <key>gain</key>
+ <type>float</type>
+ </param>
+ <param>
+ <name>Samples per symbol</name>
+ <key>sps</key>
+ <type>float</type>
+ </param>
+ <param>
+ <name>Error limit</name>
+ <key>limit</key>
+ <type>float</type>
+ </param>
+ <param>
+ <name>Output samples per symbol</name>
+ <key>osps</key>
+ <type>int</type>
+ </param>
+ <sink>
+ <name>in</name>
+ <type>complex</type>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>complex</type>
+ </source>
+ <source>
+ <name>err</name>
+ <type>float</type>
+ <optional>1</optional>
+ </source>
+ <source>
+ <name>omega</name>
+ <type>float</type>
+ <optional>1</optional>
+ </source>
+
+</block>
diff --git a/gr-digital/include/gnuradio/digital/CMakeLists.txt
b/gr-digital/include/gnuradio/digital/CMakeLists.txt
index 2993497..e85e5bc 100644
--- a/gr-digital/include/gnuradio/digital/CMakeLists.txt
+++ b/gr-digital/include/gnuradio/digital/CMakeLists.txt
@@ -74,6 +74,7 @@ install(FILES
mpsk_receiver_cc.h
mpsk_snr_est.h
mpsk_snr_est_cc.h
+ msk_timing_recovery_cc.h
ofdm_carrier_allocator_cvc.h
ofdm_chanest_vcvc.h
ofdm_cyclic_prefixer.h
diff --git a/gr-digital/include/gnuradio/digital/msk_timing_recovery_cc.h
b/gr-digital/include/gnuradio/digital/msk_timing_recovery_cc.h
new file mode 100644
index 0000000..770bd91
--- /dev/null
+++ b/gr-digital/include/gnuradio/digital/msk_timing_recovery_cc.h
@@ -0,0 +1,76 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2014 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_MSK_TIMING_RECOVERY_CC_H
+#define INCLUDED_DIGITAL_MSK_TIMING_RECOVERY_CC_H
+
+#include <gnuradio/digital/api.h>
+#include <gnuradio/block.h>
+
+namespace gr {
+ namespace digital {
+
+ /*!
+ * \brief MSK/GMSK timing recovery
+ * \ingroup synchronizers_blk
+ *
+ * This block performs timing synchronization on CPM modulations using a
+ * fourth-order nonlinearity feedback method which is non-data-aided. The
+ * block does not require prior phase synchronization but is relatively
+ * sensitive to frequency offset (keep offset to 0.1x symbol rate).
+ *
+ * For details on the algorithm, see:
+ * A.N. D'Andrea, U. Mengali, R. Reggiannini: A digital approach to clock
+ * recovery in generalized minimum shift keying. IEEE Transactions on
+ * Vehicular Technology, Vol. 39, Issue 3.
+ */
+ class DIGITAL_API msk_timing_recovery_cc : virtual public gr::block
+ {
+ public:
+ typedef boost::shared_ptr<msk_timing_recovery_cc> sptr;
+
+ /*!
+ * \brief Make an MSK timing recovery block.
+ *
+ * \param sps: Samples per symbol
+ * \param gain: Loop gain of timing error filter (try 0.05)
+ * \param limit: Relative limit of timing error (try 0.1 for 10% error
max)
+ * \param osps: Output samples per symbol
+ *
+ */
+ static sptr make(float sps, float gain, float limit, int osps);
+
+ virtual void set_gain(float gain)=0;
+ virtual float get_gain(void)=0;
+
+ virtual void set_limit(float limit)=0;
+ virtual float get_limit(void)=0;
+
+ virtual void set_sps(float sps)=0;
+ virtual float get_sps(void)=0;
+ };
+
+ } // namespace digital
+} // namespace gr
+
+#endif /* INCLUDED_DIGITAL_MSK_TIMING_RECOVERY_CC_H */
+
diff --git a/gr-digital/lib/CMakeLists.txt b/gr-digital/lib/CMakeLists.txt
index 0c213d7..c5591e8 100644
--- a/gr-digital/lib/CMakeLists.txt
+++ b/gr-digital/lib/CMakeLists.txt
@@ -90,6 +90,7 @@ list(APPEND digital_sources
mpsk_receiver_cc_impl.cc
mpsk_snr_est.cc
mpsk_snr_est_cc_impl.cc
+ msk_timing_recovery_cc_impl.cc
ofdm_carrier_allocator_cvc_impl.cc
ofdm_chanest_vcvc_impl.cc
ofdm_cyclic_prefixer_impl.cc
diff --git a/gr-digital/lib/msk_timing_recovery_cc_impl.cc
b/gr-digital/lib/msk_timing_recovery_cc_impl.cc
new file mode 100644
index 0000000..a567357
--- /dev/null
+++ b/gr-digital/lib/msk_timing_recovery_cc_impl.cc
@@ -0,0 +1,210 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2014 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 <gnuradio/io_signature.h>
+#include <gnuradio/math.h>
+#include "msk_timing_recovery_cc_impl.h"
+#include <gnuradio/filter/firdes.h>
+
+namespace gr {
+ namespace digital {
+
+ msk_timing_recovery_cc::sptr
+ msk_timing_recovery_cc::make(float sps, float gain, float limit, int
osps=1)
+ {
+ return gnuradio::get_initial_sptr
+ (new msk_timing_recovery_cc_impl(sps, gain, limit, osps));
+ }
+
+ /*
+ * The private constructor
+ */
+ msk_timing_recovery_cc_impl::msk_timing_recovery_cc_impl(float sps, float
gain, float limit, int osps)
+ : gr::block("msk_timing_recovery_cc",
+ gr::io_signature::make(1, 1, sizeof(gr_complex)),
+ gr::io_signature::make3(1, 3, sizeof(gr_complex), sizeof(float),
sizeof(float))),
+ d_limit(limit),
+ d_interp(new filter::mmse_fir_interpolator_cc()),
+ d_dly_conj_1(0),
+ d_dly_conj_2(0),
+ d_dly_diff_1(0),
+ d_mu(0.5),
+ d_div(0),
+ d_osps(osps)
+ {
+ set_sps(sps);
+ enable_update_rate(true); //fixes tag propagation through variable
rate blox
+ set_gain(gain);
+ if(d_osps != 1 && d_osps != 2) throw std::out_of_range("osps must be 1
or 2");
+ }
+
+ msk_timing_recovery_cc_impl::~msk_timing_recovery_cc_impl()
+ {
+ delete d_interp;
+ }
+
+ void msk_timing_recovery_cc_impl::set_sps(float sps) {
+ d_sps = sps/2.0; //loop runs at 2x sps
+ d_omega = d_sps;
+ set_relative_rate(d_osps/sps);
+// set_history(d_sps);
+ }
+
+ float msk_timing_recovery_cc_impl::get_sps(void) {
+ return d_sps;
+ }
+
+ void msk_timing_recovery_cc_impl::set_gain(float gain) {
+ d_gain = gain;
+ if(d_gain <= 0) throw std::out_of_range("Gain must be positive");
+ d_gain_omega = d_gain*d_gain*0.25;
+ }
+
+ float msk_timing_recovery_cc_impl::get_gain(void) {
+ return d_gain;
+ }
+
+ void msk_timing_recovery_cc_impl::set_limit(float limit) {
+ d_limit = limit;
+ }
+
+ float msk_timing_recovery_cc_impl::get_limit(void) {
+ return d_limit;
+ }
+
+ void
+ msk_timing_recovery_cc_impl::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_sps*2) +
3.0*d_sps + d_interp->ntaps());
+ }
+ }
+
+ int
+ msk_timing_recovery_cc_impl::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 *out2, *out3;
+ if(output_items.size() >= 2) out2 = (float *) output_items[1];
+ if(output_items.size() >= 3) out3 = (float *) output_items[2];
+ int oidx=0, iidx=0;
+ int ninp=ninput_items[0] - 3.0*d_sps;
+ if(ninp <= 0) {
+ consume_each(0);
+ return(0);
+ }
+
+ std::vector<tag_t> tags;
+ get_tags_in_range(tags,
+ 0,
+ nitems_read(0),
+ nitems_read(0)+ninp,
+ pmt::intern("time_est"));
+
+ gr_complex sq, //Squared input
+ dly_conj, //Input delayed sps and conjugated
+ nlin_out, //output of the nonlinearity
+ in_interp; //interpolated input
+ float err_out=0; //error output
+
+ while(oidx < noutput_items && iidx < ninp) {
+ //check to see if there's a tag to reset the timing estimate
+ if(tags.size() > 0) {
+ int offset = tags[0].offset - nitems_read(0);
+ if((offset >= iidx) && (offset < (iidx+d_sps))) {
+ float center = (float) pmt::to_double(tags[0].value);
+ if(center != center) { //test for NaN, it happens somehow
+ tags.erase(tags.begin());
+ goto out;
+ }
+ d_mu = center;
+ iidx = offset;
+ if(d_mu<0) {
+ d_mu++;
+ iidx--;
+ }
+ d_div = 0;
+ d_omega = d_sps;
+ d_dly_conj_2 = d_dly_conj_1;
+ //this keeps the block from outputting an odd number of
+ //samples and throwing off downstream blocks which depend
+ //on proper alignment -- for instance, a decimating FIR
+ //filter.
+// if(d_div == 0 and d_osps == 2) oidx++;
+ tags.erase(tags.begin());
+ }
+ }
+
+out:
+ //the actual equation for the nonlinearity is as follows:
+ //e(n) = in[n]^2 * in[n-sps].conj()^2
+ //we then differentiate the error by subtracting the sample
delayed by d_sps/2
+ in_interp = d_interp->interpolate(&in[iidx], d_mu);
+ sq = in_interp*in_interp;
+ //conjugation is distributive.
+ dly_conj = std::conj(d_dly_conj_2*d_dly_conj_2);
+ nlin_out = sq*dly_conj;
+ //TODO: paper argues that some improvement can be had
+ //if you either operate at >2sps or use a better numeric
+ //differentiation method.
+ err_out = std::real(nlin_out - d_dly_diff_1);
+ if(d_div % 2) { //error loop calc once per symbol
+ err_out = gr::branchless_clip(err_out, 3.0);
+ d_omega += d_gain_omega*err_out;
+ d_omega = d_sps + gr::branchless_clip(d_omega-d_sps, d_limit);
+ d_mu += d_gain*err_out;
+ }
+ //output every other d_sps by default.
+ if(!(d_div % 2) or d_osps==2) {
+ out[oidx] = in_interp;
+ if(output_items.size() >= 2) out2[oidx] = err_out;
+ if(output_items.size() >= 3) out3[oidx] = d_mu;
+ oidx++;
+ }
+ d_div++;
+
+ d_dly_conj_1 = in_interp;
+ d_dly_conj_2 = d_dly_conj_1;
+ d_dly_diff_1 = nlin_out;
+
+ //update interpolator twice per symbol
+ d_mu += d_omega;
+ iidx += (int)floor(d_mu);
+ d_mu -= floor(d_mu);
+ }
+
+ consume_each (iidx);
+ return oidx;
+ }
+
+ } /* namespace digital */
+} /* namespace gr */
+
diff --git a/gr-digital/lib/msk_timing_recovery_cc_impl.h
b/gr-digital/lib/msk_timing_recovery_cc_impl.h
new file mode 100644
index 0000000..02c29dc
--- /dev/null
+++ b/gr-digital/lib/msk_timing_recovery_cc_impl.h
@@ -0,0 +1,72 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2014 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_MSK_TIMING_RECOVERY_CC_IMPL_H
+#define INCLUDED_DIGITAL_MSK_TIMING_RECOVERY_CC_IMPL_H
+
+#include <gnuradio/digital/msk_timing_recovery_cc.h>
+#include <gnuradio/filter/mmse_fir_interpolator_cc.h>
+#include <boost/circular_buffer.hpp>
+#include <gnuradio/filter/fir_filter_with_buffer.h>
+
+namespace gr {
+ namespace digital {
+
+ class msk_timing_recovery_cc_impl : public msk_timing_recovery_cc
+ {
+ private:
+ float d_sps;
+ float d_gain;
+ float d_limit;
+ filter::mmse_fir_interpolator_cc *d_interp;
+ filter::kernel::fir_filter_with_buffer_fff *d_decim;
+ gr_complex d_dly_conj_1, d_dly_conj_2, d_dly_diff_1;
+ float d_mu, d_omega, d_gain_omega;
+ int d_div;
+ int d_osps;
+ int d_loop_rate;
+
+ public:
+ msk_timing_recovery_cc_impl(float sps, float gain, float limit, int
osps);
+ ~msk_timing_recovery_cc_impl();
+
+ // Where all the action really happens
+ 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);
+ void set_gain(float gain);
+ float get_gain(void);
+
+ void set_limit(float limit);
+ float get_limit(void);
+
+ void set_sps(float sps);
+ float get_sps(void);
+ };
+ } // namespace digital
+} // namespace gr
+
+#endif /* INCLUDED_DIGITAL_MSK_TIMING_RECOVERY_CC_IMPL_H */
+
diff --git a/gr-digital/swig/digital_swig.i b/gr-digital/swig/digital_swig.i
index 675c9b0..9797e79 100644
--- a/gr-digital/swig/digital_swig.i
+++ b/gr-digital/swig/digital_swig.i
@@ -83,6 +83,7 @@
#include "gnuradio/digital/mpsk_receiver_cc.h"
#include "gnuradio/digital/mpsk_snr_est.h"
#include "gnuradio/digital/mpsk_snr_est_cc.h"
+#include "gnuradio/digital/msk_timing_recovery_cc.h"
#include "gnuradio/digital/ofdm_carrier_allocator_cvc.h"
#include "gnuradio/digital/ofdm_chanest_vcvc.h"
#include "gnuradio/digital/ofdm_cyclic_prefixer.h"
@@ -161,6 +162,7 @@
%include "gnuradio/digital/mpsk_receiver_cc.h"
%include "gnuradio/digital/mpsk_snr_est.h"
%include "gnuradio/digital/mpsk_snr_est_cc.h"
+%include "gnuradio/digital/msk_timing_recovery_cc.h"
%include "gnuradio/digital/ofdm_carrier_allocator_cvc.h"
%include "gnuradio/digital/ofdm_chanest_vcvc.h"
%include "gnuradio/digital/ofdm_cyclic_prefixer.h"
@@ -229,6 +231,7 @@ GR_SWIG_BLOCK_MAGIC2(digital, lms_dd_equalizer_cc);
GR_SWIG_BLOCK_MAGIC2(digital, map_bb);
GR_SWIG_BLOCK_MAGIC2(digital, mpsk_receiver_cc);
GR_SWIG_BLOCK_MAGIC2(digital, mpsk_snr_est_cc);
+GR_SWIG_BLOCK_MAGIC2(digital, msk_timing_recovery_cc);
GR_SWIG_BLOCK_MAGIC2(digital, ofdm_carrier_allocator_cvc);
GR_SWIG_BLOCK_MAGIC2(digital, ofdm_chanest_vcvc);
GR_SWIG_BLOCK_MAGIC2(digital, ofdm_cyclic_prefixer);