summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gnuradio-core/src/guile/tests/general_ctors.test3
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.cc205
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h178
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.i23
-rw-r--r--gnuradio-core/src/lib/general/CMakeLists.txt4
-rw-r--r--gnuradio-core/src/lib/general/Makefile.am6
-rw-r--r--gnuradio-core/src/lib/general/general.i4
-rw-r--r--gnuradio-core/src/lib/general/gr_fll_band_edge_cc.cc214
-rw-r--r--gnuradio-core/src/lib/general/gr_fll_band_edge_cc.h140
-rw-r--r--gnuradio-core/src/lib/general/gr_fll_band_edge_cc.i41
-rw-r--r--gnuradio-core/src/lib/general/gr_pll_refout_cc.cc23
-rw-r--r--gnuradio-core/src/lib/general/gr_pll_refout_cc.h20
-rw-r--r--gnuradio-core/src/lib/general/gr_pll_refout_cc.i10
-rw-r--r--gnuradio-core/src/lib/general/gri_control_loop.cc183
-rw-r--r--gnuradio-core/src/lib/general/gri_control_loop.h203
-rw-r--r--gnuradio-core/src/lib/general/gri_control_loop.i57
-rw-r--r--gr-digital/examples/Makefile.am3
-rwxr-xr-xgr-digital/examples/benchmark_rx.py5
-rwxr-xr-xgr-digital/examples/benchmark_tx.py2
-rwxr-xr-xgr-digital/examples/example_costas.py116
-rwxr-xr-xgr-digital/examples/example_fll.py126
-rwxr-xr-xgr-digital/examples/example_timing.py211
-rw-r--r--gr-digital/examples/receive_path.py18
-rw-r--r--gr-digital/examples/transmit_path.py17
-rw-r--r--gr-digital/lib/CMakeLists.txt3
-rw-r--r--gr-digital/lib/Makefile.am2
-rw-r--r--gr-digital/lib/digital_clock_recovery_mm_cc.cc8
-rw-r--r--gr-digital/lib/digital_constellation_receiver_cb.cc135
-rw-r--r--gr-digital/lib/digital_constellation_receiver_cb.h159
-rw-r--r--gr-digital/lib/digital_costas_loop_cc.cc74
-rw-r--r--gr-digital/lib/digital_costas_loop_cc.h49
-rw-r--r--gr-digital/lib/digital_fll_band_edge_cc.cc390
-rw-r--r--gr-digital/lib/digital_fll_band_edge_cc.h323
-rw-r--r--gr-digital/python/Makefile.am1
-rw-r--r--gr-digital/python/bpsk.py81
-rw-r--r--gr-digital/python/generic_mod_demod.py146
-rw-r--r--gr-digital/python/modulation_utils2.py1
-rwxr-xr-xgr-digital/python/qa_constellation_receiver.py2
-rwxr-xr-xgr-digital/python/qa_costas_loop_cc.py17
-rw-r--r--gr-digital/python/qa_fll_band_edge.py83
-rw-r--r--gr-digital/python/qam.py4
-rw-r--r--gr-digital/python/qpsk.py17
-rw-r--r--gr-digital/swig/CMakeLists.txt1
-rw-r--r--gr-digital/swig/Makefile.am1
-rw-r--r--gr-digital/swig/digital_constellation_receiver_cb.i27
-rw-r--r--gr-digital/swig/digital_costas_loop_cc.i17
-rw-r--r--gr-digital/swig/digital_fll_band_edge_cc.i60
-rw-r--r--gr-digital/swig/digital_swig.i4
-rwxr-xr-xgr-utils/src/python/gr_plot_const.py27
49 files changed, 2621 insertions, 823 deletions
diff --git a/gnuradio-core/src/guile/tests/general_ctors.test b/gnuradio-core/src/guile/tests/general_ctors.test
index eb0e5876e6..813574bcad 100644
--- a/gnuradio-core/src/guile/tests/general_ctors.test
+++ b/gnuradio-core/src/guile/tests/general_ctors.test
@@ -147,9 +147,6 @@
(pass-if (true? (gr:fft-vfc 4 #t #(1.0 2.0 3.0 4.0))))
(pass-if-throw "confirm throw gr:fft-vfc" #t (true? (gr:fft-vfc 4 #f #(1.0 2.0 3.0 4.0))))
-;;; ./general/gr_fll_band_edge_cc.h
-(pass-if (true? (gr:fll-band-edge-cc 0 0 0 0 0)))
-
;; ;;; ./general/gr_float_to_char.h
(pass-if (true? (gr:float-to-char)))
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.cc b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.cc
index a52d1d9011..b5a5aed7d3 100644
--- a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.cc
+++ b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.cc
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2009,2010 Free Software Foundation, Inc.
+ * Copyright 2009-2011 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -33,14 +33,14 @@
#include <gr_io_signature.h>
#include <gr_math.h>
-gr_pfb_clock_sync_ccf_sptr gr_make_pfb_clock_sync_ccf (double sps, float gain,
+gr_pfb_clock_sync_ccf_sptr gr_make_pfb_clock_sync_ccf (double sps, float loop_bw,
const std::vector<float> &taps,
unsigned int filter_size,
float init_phase,
float max_rate_deviation,
int osps)
{
- return gnuradio::get_initial_sptr(new gr_pfb_clock_sync_ccf (sps, gain, taps,
+ return gnuradio::get_initial_sptr(new gr_pfb_clock_sync_ccf (sps, loop_bw, taps,
filter_size,
init_phase,
max_rate_deviation,
@@ -49,7 +49,7 @@ gr_pfb_clock_sync_ccf_sptr gr_make_pfb_clock_sync_ccf (double sps, float gain,
static int ios[] = {sizeof(gr_complex), sizeof(float), sizeof(float), sizeof(float)};
static std::vector<int> iosig(ios, ios+sizeof(ios)/sizeof(int));
-gr_pfb_clock_sync_ccf::gr_pfb_clock_sync_ccf (double sps, float gain,
+gr_pfb_clock_sync_ccf::gr_pfb_clock_sync_ccf (double sps, float loop_bw,
const std::vector<float> &taps,
unsigned int filter_size,
float init_phase,
@@ -65,11 +65,15 @@ gr_pfb_clock_sync_ccf::gr_pfb_clock_sync_ccf (double sps, float gain,
d_nfilters = filter_size;
d_sps = floor(sps);
+ // Set the damping factor for a critically damped system
+ d_damping = sqrtf(2.0f)/2.0f;
+
+ // Set the bandwidth, which will then call update_gains()
+ set_loop_bandwidth(loop_bw);
+
// Store the last filter between calls to work
// The accumulator keeps track of overflow to increment the stride correctly.
// set it here to the fractional difference based on the initial phaes
- set_alpha(gain);
- set_beta(0.25*gain*gain);
d_k = init_phase;
d_rate = (sps-floor(sps))*(double)d_nfilters;
d_rate_i = (int)floor(d_rate);
@@ -107,6 +111,94 @@ gr_pfb_clock_sync_ccf::check_topology(int ninputs, int noutputs)
return noutputs == 1 || noutputs == 4;
}
+
+
+/*******************************************************************
+ SET FUNCTIONS
+*******************************************************************/
+
+
+void
+gr_pfb_clock_sync_ccf::set_loop_bandwidth(float bw)
+{
+ if(bw < 0) {
+ throw std::out_of_range ("gr_pfb_clock_sync_cc: invalid bandwidth. Must be >= 0.");
+ }
+
+ d_loop_bw = bw;
+ update_gains();
+}
+
+void
+gr_pfb_clock_sync_ccf::set_damping_factor(float df)
+{
+ if(df < 0 || df > 1.0) {
+ throw std::out_of_range ("gr_pfb_clock_sync_cc: invalid damping factor. Must be in [0,1].");
+ }
+
+ d_damping = df;
+ update_gains();
+}
+
+void
+gr_pfb_clock_sync_ccf::set_alpha(float alpha)
+{
+ if(alpha < 0 || alpha > 1.0) {
+ throw std::out_of_range ("gr_pfb_clock_sync_cc: invalid alpha. Must be in [0,1].");
+ }
+ d_alpha = alpha;
+}
+
+void
+gr_pfb_clock_sync_ccf::set_beta(float beta)
+{
+ if(beta < 0 || beta > 1.0) {
+ throw std::out_of_range ("gr_pfb_clock_sync_cc: invalid beta. Must be in [0,1].");
+ }
+ d_beta = beta;
+}
+
+/*******************************************************************
+ GET FUNCTIONS
+*******************************************************************/
+
+
+float
+gr_pfb_clock_sync_ccf::get_loop_bandwidth() const
+{
+ return d_loop_bw;
+}
+
+float
+gr_pfb_clock_sync_ccf::get_damping_factor() const
+{
+ return d_damping;
+}
+
+float
+gr_pfb_clock_sync_ccf::get_alpha() const
+{
+ return d_alpha;
+}
+
+float
+gr_pfb_clock_sync_ccf::get_beta() const
+{
+ return d_beta;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+void
+gr_pfb_clock_sync_ccf::update_gains()
+{
+ float denom = (1.0 + 2.0*d_damping*d_loop_bw + d_loop_bw*d_loop_bw);
+ d_alpha = (4*d_damping*d_loop_bw) / denom;
+ d_beta = (4*d_loop_bw*d_loop_bw) / denom;
+}
+
+
void
gr_pfb_clock_sync_ccf::set_taps (const std::vector<float> &newtaps,
std::vector< std::vector<float> > &ourtaps,
@@ -131,13 +223,16 @@ gr_pfb_clock_sync_ccf::set_taps (const std::vector<float> &newtaps,
// Partition the filter
for(i = 0; i < d_nfilters; i++) {
// Each channel uses all d_taps_per_filter with 0's if not enough taps to fill out
- ourtaps[d_nfilters-1-i] = std::vector<float>(d_taps_per_filter, 0);
+ //ourtaps[d_nfilters-1-i] = std::vector<float>(d_taps_per_filter, 0);
+ ourtaps[i] = std::vector<float>(d_taps_per_filter, 0);
for(j = 0; j < d_taps_per_filter; j++) {
- ourtaps[d_nfilters - 1 - i][j] = tmp_taps[i + j*d_nfilters];
+ //ourtaps[d_nfilters - 1 - i][j] = tmp_taps[i + j*d_nfilters];
+ ourtaps[i][j] = tmp_taps[i + j*d_nfilters];
}
// Build a filter for each channel and add it's taps to it
- ourfilter[i]->set_taps(ourtaps[d_nfilters-1-i]);
+ //ourfilter[i]->set_taps(ourtaps[d_nfilters-1-i]);
+ ourfilter[i]->set_taps(ourtaps[i]);
}
// Set the history to ensure enough input items for each filter
@@ -150,58 +245,84 @@ void
gr_pfb_clock_sync_ccf::create_diff_taps(const std::vector<float> &newtaps,
std::vector<float> &difftaps)
{
- float maxtap = 1e-20;
- difftaps.clear();
- difftaps.push_back(0); //newtaps[0]);
- for(unsigned int i = 1; i < newtaps.size()-1; i++) {
- float tap = newtaps[i+1] - newtaps[i-1];
- difftaps.push_back(tap);
- if(tap > maxtap) {
- maxtap = tap;
+ std::vector<float> diff_filter(3);
+ diff_filter[0] = -1;
+ diff_filter[1] = 0;
+ diff_filter[2] = 1;
+
+ float pwr = 0;
+ difftaps.push_back(0);
+ for(unsigned int i = 0; i < newtaps.size()-2; i++) {
+ float tap = 0;
+ for(int j = 0; j < 3; j++) {
+ tap += diff_filter[j]*newtaps[i+j];
+ pwr += fabsf(tap);
}
+ difftaps.push_back(tap);
}
- difftaps.push_back(0);//-newtaps[newtaps.size()-1]);
+ difftaps.push_back(0);
- // Scale the differential taps; helps scale error term to better update state
- // FIXME: should this be scaled this way or use the same gain as the taps?
for(unsigned int i = 0; i < difftaps.size(); i++) {
- difftaps[i] /= maxtap;
+ difftaps[i] *= pwr;
}
}
-void
-gr_pfb_clock_sync_ccf::print_taps()
+std::string
+gr_pfb_clock_sync_ccf::get_taps_as_string()
{
int i, j;
- printf("[ ");
+ std::stringstream str;
+ str.precision(4);
+ str.setf(std::ios::scientific);
+
+ str << "[ ";
for(i = 0; i < d_nfilters; i++) {
- printf("[%.4e, ", d_taps[i][0]);
+ str << "[" << d_taps[i][0] << ", ";
for(j = 1; j < d_taps_per_filter-1; j++) {
- printf("%.4e,", d_taps[i][j]);
+ str << d_taps[i][j] << ", ";
}
- printf("%.4e],", d_taps[i][j]);
+ str << d_taps[i][j] << "],";
}
- printf(" ]\n");
+ str << " ]" << std::endl;
+
+ return str.str();
}
-void
-gr_pfb_clock_sync_ccf::print_diff_taps()
+std::string
+gr_pfb_clock_sync_ccf::get_diff_taps_as_string()
{
int i, j;
- printf("[ ");
+ std::stringstream str;
+ str.precision(4);
+ str.setf(std::ios::scientific);
+
+ str << "[ ";
for(i = 0; i < d_nfilters; i++) {
- printf("[%.4e, ", d_dtaps[i][0]);
+ str << "[" << d_dtaps[i][0] << ", ";
for(j = 1; j < d_taps_per_filter-1; j++) {
- printf("%.4e,", d_dtaps[i][j]);
+ str << d_dtaps[i][j] << ", ";
}
- printf("%.4e],", d_dtaps[i][j]);
+ str << d_dtaps[i][j] << "],";
}
- printf(" ]\n");
+ str << " ]" << std::endl;
+
+ return str.str();
}
+std::vector< std::vector<float> >
+gr_pfb_clock_sync_ccf::get_taps()
+{
+ return d_taps;
+}
+
+std::vector< std::vector<float> >
+gr_pfb_clock_sync_ccf::get_diff_taps()
+{
+ return d_dtaps;
+}
std::vector<float>
-gr_pfb_clock_sync_ccf::channel_taps(int channel)
+gr_pfb_clock_sync_ccf::get_channel_taps(int channel)
{
std::vector<float> taps;
for(int i = 0; i < d_taps_per_filter; i++) {
@@ -211,7 +332,7 @@ gr_pfb_clock_sync_ccf::channel_taps(int channel)
}
std::vector<float>
-gr_pfb_clock_sync_ccf::diff_channel_taps(int channel)
+gr_pfb_clock_sync_ccf::get_diff_channel_taps(int channel)
{
std::vector<float> taps;
for(int i = 0; i < d_taps_per_filter; i++) {
@@ -230,7 +351,7 @@ gr_pfb_clock_sync_ccf::general_work (int noutput_items,
gr_complex *in = (gr_complex *) input_items[0];
gr_complex *out = (gr_complex *) output_items[0];
- float *err = 0, *outrate = 0, *outk = 0;
+ float *err = NULL, *outrate = NULL, *outk = NULL;
if(output_items.size() == 4) {
err = (float *) output_items[1];
outrate = (float*)output_items[2];
@@ -271,13 +392,13 @@ gr_pfb_clock_sync_ccf::general_work (int noutput_items,
}
gr_complex diff = d_diff_filters[d_filtnum]->filter(&in[count]);
- error_r = out[i].real() * diff.real();
- error_i = out[i].imag() * diff.imag();
+ error_r = out[i].real() * diff.real();
+ error_i = out[i].imag() * diff.imag();
error = (error_i + error_r) / 2.0; // average error from I&Q channel
// Run the control loop to update the current phase (k) and tracking rate
- d_k = d_k + d_alpha*error + d_rate_i + d_rate_f;
d_rate_f = d_rate_f + d_beta*error;
+ d_k = d_k + d_alpha*error + d_rate_i + d_rate_f;
// Keep our rate within a good range
d_rate_f = gr_branchless_clip(d_rate_f, d_max_dev);
@@ -285,7 +406,7 @@ gr_pfb_clock_sync_ccf::general_work (int noutput_items,
if(output_items.size() == 4) {
// FIXME: don't really know what to do about d_osps>1
for(int k = 0; k < d_osps; k++) {
- err[i] = error;
+ err[i] = diff.real();
outrate[i] = d_rate_f;
outk[i] = d_k;
}
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h
index 6ce4c1a1e4..1f96b9000c 100644
--- a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h
+++ b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h
@@ -29,7 +29,7 @@
class gr_pfb_clock_sync_ccf;
typedef boost::shared_ptr<gr_pfb_clock_sync_ccf> gr_pfb_clock_sync_ccf_sptr;
-GR_CORE_API gr_pfb_clock_sync_ccf_sptr gr_make_pfb_clock_sync_ccf (double sps, float gain,
+GR_CORE_API gr_pfb_clock_sync_ccf_sptr gr_make_pfb_clock_sync_ccf (double sps, float loop_bw,
const std::vector<float> &taps,
unsigned int filter_size=32,
float init_phase=0,
@@ -118,45 +118,48 @@ class GR_CORE_API gr_pfb_clock_sync_ccf : public gr_block
/*!
* Build the polyphase filterbank timing synchronizer.
* \param sps (double) The number of samples per symbol in the incoming signal
- * \param gain (float) The alpha gain of the control loop; beta = (gain^2)/4 by default.
+ * \param loop_bw (float) The bandwidth of the control loop; set's alpha and beta.
* \param taps (vector<int>) The filter taps.
* \param filter_size (uint) The number of filters in the filterbank (default = 32).
* \param init_phase (float) The initial phase to look at, or which filter to start
* with (default = 0).
* \param max_rate_deviation (float) Distance from 0 d_rate can get (default = 1.5).
- * \parma osps (int) The number of output samples per symbol (default=1).
*
*/
- friend GR_CORE_API gr_pfb_clock_sync_ccf_sptr gr_make_pfb_clock_sync_ccf (double sps, float gain,
+ friend GR_CORE_API gr_pfb_clock_sync_ccf_sptr gr_make_pfb_clock_sync_ccf (double sps, float loop_bw,
const std::vector<float> &taps,
unsigned int filter_size,
float init_phase,
float max_rate_deviation,
int osps);
- bool d_updated;
- double d_sps;
- double d_sample_num;
- float d_alpha;
- float d_beta;
- int d_nfilters;
- std::vector<gr_fir_ccf*> d_filters;
- std::vector<gr_fir_ccf*> d_diff_filters;
+ bool d_updated;
+ double d_sps;
+ double d_sample_num;
+ float d_loop_bw;
+ float d_damping;
+ float d_alpha;
+ float d_beta;
+
+ int d_nfilters;
+ int d_taps_per_filter;
+ std::vector<gr_fir_ccf*> d_filters;
+ std::vector<gr_fir_ccf*> d_diff_filters;
std::vector< std::vector<float> > d_taps;
std::vector< std::vector<float> > d_dtaps;
- float d_k;
- float d_rate;
- float d_rate_i;
- float d_rate_f;
- float d_max_dev;
- int d_filtnum;
- int d_taps_per_filter;
- int d_osps;
+
+ float d_k;
+ float d_rate;
+ float d_rate_i;
+ float d_rate_f;
+ float d_max_dev;
+ int d_filtnum;
+ int d_osps;
/*!
* Build the polyphase filterbank timing synchronizer.
*/
- gr_pfb_clock_sync_ccf (double sps, float gain,
+ gr_pfb_clock_sync_ccf (double sps, float loop_bw,
const std::vector<float> &taps,
unsigned int filter_size,
float init_phase,
@@ -168,6 +171,15 @@ class GR_CORE_API gr_pfb_clock_sync_ccf : public gr_block
public:
~gr_pfb_clock_sync_ccf ();
+
+ /*! \brief update the system gains from omega and eta
+ *
+ * This function updates the system gains based on the loop
+ * bandwidth and damping factor of the system.
+ * These two factors can be set separately through their own
+ * set functions.
+ */
+ void update_gains();
/*!
* Resets the filterbank's filter taps with the new prototype filter
@@ -177,40 +189,97 @@ public:
std::vector<gr_fir_ccf*> &ourfilter);
/*!
- * Returns the taps of the matched filter
+ * Returns all of the taps of the matched filter
*/
- std::vector<float> channel_taps(int channel);
+ std::vector< std::vector<float> > get_taps();
/*!
- * Returns the taps in the derivative filter
+ * Returns all of the taps of the derivative filter
*/
- std::vector<float> diff_channel_taps(int channel);
+ std::vector< std::vector<float> > get_diff_taps();
/*!
- * Print all of the filterbank taps to screen.
+ * Returns the taps of the matched filter for a particular channel
*/
- void print_taps();
+ std::vector<float> get_channel_taps(int channel);
/*!
- * Print all of the filterbank taps of the derivative filter to screen.
+ * Returns the taps in the derivative filter for a particular channel
*/
- void print_diff_taps();
+ std::vector<float> get_diff_channel_taps(int channel);
/*!
- * Set the gain value alpha for the control loop
- */
- void set_alpha(float alpha)
- {
- d_alpha = alpha;
- }
+ * Return the taps as a formatted string for printing
+ */
+ std::string get_taps_as_string();
/*!
- * Set the gain value beta for the control loop
- */
- void set_beta(float beta)
- {
- d_beta = beta;
- }
+ * Return the derivative filter taps as a formatted string for printing
+ */
+ std::string get_diff_taps_as_string();
+
+
+ /*******************************************************************
+ SET FUNCTIONS
+ *******************************************************************/
+
+
+ /*!
+ * \brief Set the loop bandwidth
+ *
+ * Set the loop filter's bandwidth to \p bw. This should be between
+ * 2*pi/200 and 2*pi/100 (in rads/samp). It must also be a positive
+ * number.
+ *
+ * When a new damping factor is set, the gains, alpha and beta, of the loop
+ * are recalculated by a call to update_gains().
+ *
+ * \param bw (float) new bandwidth
+ *
+ */
+ void set_loop_bandwidth(float bw);
+
+ /*!
+ * \brief Set the loop damping factor
+ *
+ * Set the loop filter's damping factor to \p df. The damping factor
+ * should be sqrt(2)/2.0 for critically damped systems.
+ * Set it to anything else only if you know what you are doing. It must
+ * be a number between 0 and 1.
+ *
+ * When a new damping factor is set, the gains, alpha and beta, of the loop
+ * are recalculated by a call to update_gains().
+ *
+ * \param df (float) new damping factor
+ *
+ */
+ void set_damping_factor(float df);
+
+ /*!
+ * \brief Set the loop gain alpha
+ *
+ * Set's the loop filter's alpha gain parameter.
+ *
+ * This value should really only be set by adjusting the loop bandwidth
+ * and damping factor.
+ *
+ * \param alpha (float) new alpha gain
+ *
+ */
+ void set_alpha(float alpha);
+
+ /*!
+ * \brief Set the loop gain beta
+ *
+ * Set's the loop filter's beta gain parameter.
+ *
+ * This value should really only be set by adjusting the loop bandwidth
+ * and damping factor.
+ *
+ * \param beta (float) new beta gain
+ *
+ */
+ void set_beta(float beta);
/*!
* Set the maximum deviation from 0 d_rate can have
@@ -220,6 +289,33 @@ public:
d_max_dev = m;
}
+ /*******************************************************************
+ GET FUNCTIONS
+ *******************************************************************/
+
+ /*!
+ * \brief Returns the loop bandwidth
+ */
+ float get_loop_bandwidth() const;
+
+ /*!
+ * \brief Returns the loop damping factor
+ */
+ float get_damping_factor() const;
+
+ /*!
+ * \brief Returns the loop gain alpha
+ */
+ float get_alpha() const;
+
+ /*!
+ * \brief Returns the loop gain beta
+ */
+ float get_beta() const;
+
+ /*******************************************************************
+ *******************************************************************/
+
bool check_topology(int ninputs, int noutputs);
int general_work (int noutput_items,
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.i b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.i
index 343ed09121..78b9a65898 100644
--- a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.i
+++ b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.i
@@ -22,7 +22,7 @@
GR_SWIG_BLOCK_MAGIC(gr,pfb_clock_sync_ccf);
-gr_pfb_clock_sync_ccf_sptr gr_make_pfb_clock_sync_ccf (double sps, float gain,
+gr_pfb_clock_sync_ccf_sptr gr_make_pfb_clock_sync_ccf (double sps, float loop_bw,
const std::vector<float> &taps,
unsigned int filter_size=32,
float init_phase=0,
@@ -32,7 +32,7 @@ gr_pfb_clock_sync_ccf_sptr gr_make_pfb_clock_sync_ccf (double sps, float gain,
class gr_pfb_clock_sync_ccf : public gr_block
{
private:
- gr_pfb_clock_sync_ccf (double sps, float gain,
+ gr_pfb_clock_sync_ccf (double sps, float loop_bw,
const std::vector<float> &taps,
unsigned int filter_size,
float init_phase,
@@ -46,11 +46,22 @@ class gr_pfb_clock_sync_ccf : public gr_block
std::vector< std::vector<float> > &ourtaps,
std::vector<gr_fir_ccf*> &ourfilter);
- std::vector<float> channel_taps(int channel);
- std::vector<float> diff_channel_taps(int channel);
- void print_taps();
- void print_diff_taps();
+ std::vector< std::vector<float> > get_taps();
+ std::vector< std::vector<float> > get_diff_taps();
+ std::vector<float> get_channel_taps(int channel);
+ std::vector<float> get_diff_channel_taps(int channel);
+ std::string get_taps_as_string();
+ std::string get_diff_taps_as_string();
+
+ void set_loop_bandwidth(float bw);
+ void set_damping_factor(float df);
void set_alpha(float alpha);
void set_beta(float beta);
void set_max_rate_deviation(float m);
+
+ float get_loop_bandwidth() const;
+ float get_damping_factor() const;
+ float get_alpha() const;
+ float get_beta() const;
+
};
diff --git a/gnuradio-core/src/lib/general/CMakeLists.txt b/gnuradio-core/src/lib/general/CMakeLists.txt
index b2182eb904..1cd9c6bd14 100644
--- a/gnuradio-core/src/lib/general/CMakeLists.txt
+++ b/gnuradio-core/src/lib/general/CMakeLists.txt
@@ -77,6 +77,7 @@ LIST(APPEND gnuradio_core_sources
${CMAKE_CURRENT_SOURCE_DIR}/gr_reverse.cc
${CMAKE_CURRENT_SOURCE_DIR}/gri_add_const_ss_generic.cc
${CMAKE_CURRENT_SOURCE_DIR}/gri_char_to_float.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/gri_control_loop.cc
${CMAKE_CURRENT_SOURCE_DIR}/gri_debugger_hook.cc
${CMAKE_CURRENT_SOURCE_DIR}/gri_fft.cc
${CMAKE_CURRENT_SOURCE_DIR}/gri_float_to_char.cc
@@ -131,6 +132,7 @@ INSTALL(FILES
${CMAKE_CURRENT_SOURCE_DIR}/gri_agc2_cc.h
${CMAKE_CURRENT_SOURCE_DIR}/gri_agc2_ff.h
${CMAKE_CURRENT_SOURCE_DIR}/gri_char_to_float.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/gri_control_loop.h
${CMAKE_CURRENT_SOURCE_DIR}/gri_debugger_hook.h
${CMAKE_CURRENT_SOURCE_DIR}/gri_fft.h
${CMAKE_CURRENT_SOURCE_DIR}/gri_float_to_char.h
@@ -160,6 +162,7 @@ INSTALL(FILES
${CMAKE_CURRENT_SOURCE_DIR}/gri_agc_ff.i
${CMAKE_CURRENT_SOURCE_DIR}/gri_agc2_cc.i
${CMAKE_CURRENT_SOURCE_DIR}/gri_agc2_ff.i
+ ${CMAKE_CURRENT_SOURCE_DIR}/gri_control_loop.i
DESTINATION ${GR_INCLUDE_DIR}/gnuradio/swig
COMPONENT "core_swig"
)
@@ -201,7 +204,6 @@ SET(gr_core_general_triple_threats
gr_fft_vcc
gr_fft_vfc
gr_firdes
- gr_fll_band_edge_cc
gr_float_to_char
gr_float_to_complex
gr_float_to_short
diff --git a/gnuradio-core/src/lib/general/Makefile.am b/gnuradio-core/src/lib/general/Makefile.am
index e63d8930bc..f210cee393 100644
--- a/gnuradio-core/src/lib/general/Makefile.am
+++ b/gnuradio-core/src/lib/general/Makefile.am
@@ -72,7 +72,6 @@ libgeneral_la_SOURCES = \
gr_fft_vcc_fftw.cc \
gr_fft_vfc.cc \
gr_firdes.cc \
- gr_fll_band_edge_cc.cc \
gr_float_to_char.cc \
gr_float_to_complex.cc \
gr_float_to_short.cc \
@@ -154,6 +153,7 @@ libgeneral_la_SOURCES = \
gr_wvps_ff.cc \
gri_add_const_ss_generic.cc \
gri_char_to_float.cc \
+ gri_control_loop.cc \
gri_debugger_hook.cc \
gri_fft.cc \
gri_float_to_char.cc \
@@ -220,7 +220,6 @@ grinclude_HEADERS = \
gr_fft_vcc_fftw.h \
gr_fft_vfc.h \
gr_firdes.h \
- gr_fll_band_edge_cc.h \
gr_float_to_char.h \
gr_float_to_complex.h \
gr_float_to_short.h \
@@ -314,6 +313,7 @@ grinclude_HEADERS = \
gri_agc2_cc.h \
gri_agc2_ff.h \
gri_char_to_float.h \
+ gri_control_loop.h \
gri_debugger_hook.h \
gri_fft.h \
gri_float_to_char.h \
@@ -382,7 +382,6 @@ swiginclude_HEADERS = \
gr_fft_vcc.i \
gr_fft_vfc.i \
gr_firdes.i \
- gr_fll_band_edge_cc.i \
gr_float_to_char.i \
gr_float_to_complex.i \
gr_float_to_short.i \
@@ -463,6 +462,7 @@ swiginclude_HEADERS = \
gri_agc_ff.i \
gri_agc2_cc.i \
gri_agc2_ff.i \
+ gri_control_loop.i \
gr_descrambler_bb.i \
gr_scrambler_bb.i \
gr_probe_mpsk_snr_c.i \
diff --git a/gnuradio-core/src/lib/general/general.i b/gnuradio-core/src/lib/general/general.i
index c43622400b..f9adff3fa2 100644
--- a/gnuradio-core/src/lib/general/general.i
+++ b/gnuradio-core/src/lib/general/general.i
@@ -22,6 +22,7 @@
%{
+#include <gri_control_loop.h>
#include <gr_nop.h>
#include <gr_null_sink.h>
#include <gr_null_source.h>
@@ -131,7 +132,6 @@
#include <gr_wavelet_ff.h>
#include <gr_wvps_ff.h>
#include <gr_copy.h>
-#include <gr_fll_band_edge_cc.h>
#include <gr_additive_scrambler_bb.h>
#include <complex_vec_test.h>
#include <gr_annotator_alltoall.h>
@@ -139,6 +139,7 @@
#include <gr_burst_tagger.h>
%}
+%include "gri_control_loop.i"
%include "gr_nop.i"
%include "gr_null_sink.i"
%include "gr_null_source.i"
@@ -248,7 +249,6 @@
%include "gr_wavelet_ff.i"
%include "gr_wvps_ff.i"
%include "gr_copy.i"
-%include "gr_fll_band_edge_cc.i"
%include "gr_additive_scrambler_bb.i"
%include "complex_vec_test.i"
%include "gr_annotator_alltoall.i"
diff --git a/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.cc b/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.cc
deleted file mode 100644
index c32398e6d5..0000000000
--- a/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.cc
+++ /dev/null
@@ -1,214 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2009,2010 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <gr_fll_band_edge_cc.h>
-#include <gr_fir_ccc.h>
-#include <gr_fir_util.h>
-#include <gri_fft.h>
-#include <gr_io_signature.h>
-#include <gr_expj.h>
-#include <gr_math.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);
-}
-
-
-
-gr_fll_band_edge_cc_sptr gr_make_fll_band_edge_cc (float samps_per_sym, float rolloff,
- int filter_size, float gain_alpha, float gain_beta)
-{
- return gnuradio::get_initial_sptr(new gr_fll_band_edge_cc (samps_per_sym, rolloff,
- filter_size, gain_alpha, gain_beta));
-}
-
-
-static int ios[] = {sizeof(gr_complex), sizeof(float), sizeof(float), sizeof(gr_complex)};
-static std::vector<int> iosig(ios, ios+sizeof(ios)/sizeof(int));
-gr_fll_band_edge_cc::gr_fll_band_edge_cc (float samps_per_sym, float rolloff,
- int filter_size, float alpha, float beta)
- : gr_sync_block ("fll_band_edge_cc",
- gr_make_io_signature (1, 1, sizeof(gr_complex)),
- gr_make_io_signaturev (1, 4, iosig)),
- d_alpha(alpha), d_beta(beta), d_updated (false)
-{
- // base this on the number of samples per symbol
- d_max_freq = M_TWOPI * (2.0/samps_per_sym);
- d_min_freq = -M_TWOPI * (2.0/samps_per_sym);
-
- d_freq = 0;
- d_phase = 0;
-
- set_alpha(alpha);
-
- design_filter(samps_per_sym, rolloff, filter_size);
-}
-
-gr_fll_band_edge_cc::~gr_fll_band_edge_cc ()
-{
- delete d_filter_lower;
- delete d_filter_upper;
-}
-
-void
-gr_fll_band_edge_cc::set_alpha(float alpha)
-{
- //float eta = sqrt(2.0)/2.0;
- //float theta = alpha;
- //d_alpha = (4*eta*theta) / (1.0 + 2.0*eta*theta + theta*theta);
- //d_beta = (4*theta*theta) / (1.0 + 2.0*eta*theta + theta*theta);
- d_alpha = alpha;
-}
-
-void
-gr_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;
- 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);
- }
-
- int N = (bb_taps.size() - 1.0)/2.0;
- std::vector<gr_complex> taps_lower;
- std::vector<gr_complex> taps_upper;
- for(unsigned int i = 0; i < bb_taps.size(); i++) {
- float tap = bb_taps[i] / power;
-
- float k = (-N + (int)i)/(2.0*samps_per_sym);
-
- gr_complex t1 = tap * gr_expj(-2*M_PI*(1+rolloff)*k);
- gr_complex t2 = tap * gr_expj(2*M_PI*(1+rolloff)*k);
-
- taps_lower.push_back(t1);
- taps_upper.push_back(t2);
- }
-
- std::vector<gr_complex> vtaps(0, taps_lower.size());
- d_filter_upper = gr_fir_util::create_gr_fir_ccc(vtaps);
- d_filter_lower = gr_fir_util::create_gr_fir_ccc(vtaps);
-
- d_filter_lower->set_taps(taps_lower);
- d_filter_upper->set_taps(taps_upper);
-
- d_updated = true;
-
- // Set the history to ensure enough input items for each filter
- set_history(filter_size+1);
-
-}
-
-void
-gr_fll_band_edge_cc::print_taps()
-{
- unsigned int i;
- std::vector<gr_complex> taps_upper = d_filter_upper->get_taps();
- std::vector<gr_complex> taps_lower = d_filter_lower->get_taps();
-
- printf("Upper Band-edge: [");
- for(i = 0; i < taps_upper.size(); i++) {
- printf(" %.4e + %.4ej,", taps_upper[i].real(), taps_upper[i].imag());
- }
- printf("]\n\n");
-
- printf("Lower Band-edge: [");
- for(i = 0; i < taps_lower.size(); i++) {
- printf(" %.4e + %.4ej,", taps_lower[i].real(), taps_lower[i].imag());
- }
- printf("]\n\n");
-}
-
-int
-gr_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;
- gr_complex *err = NULL;
- if(output_items.size() > 2) {
- frq = (float *) output_items[1];
- phs = (float *) output_items[2];
- err = (gr_complex *) output_items[3];
- }
-
- if (d_updated) {
- d_updated = false;
- return 0; // history requirements may have changed.
- }
-
- int i;
- gr_complex nco_out;
- gr_complex out_upper, out_lower;
- float error;
- float avg_k = 0.1;
- for(i = 0; i < noutput_items; i++) {
- nco_out = gr_expj(d_phase);
- out[i] = in[i] * nco_out;
-
- out_upper = (d_filter_upper->filter(&out[i]));
- out_lower = (d_filter_lower->filter(&out[i]));
- error = -real((out_upper + out_lower) * conj(out_upper - out_lower));
- d_error = avg_k*error + avg_k*d_error; // average error
-
- d_freq = d_freq + d_beta * d_error;
- d_phase = d_phase + d_freq + d_alpha * d_error;
-
- if(d_phase > M_PI)
- d_phase -= M_TWOPI;
- else if(d_phase < -M_PI)
- d_phase += M_TWOPI;
-
- if (d_freq > d_max_freq)
- d_freq = d_max_freq;
- else if (d_freq < d_min_freq)
- d_freq = d_min_freq;
-
- if(output_items.size() > 2) {
- frq[i] = d_freq;
- phs[i] = d_phase;
- err[i] = d_error;
- }
- }
-
-
- return noutput_items;
-}
diff --git a/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.h b/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.h
deleted file mode 100644
index e3007b97a3..0000000000
--- a/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2009 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-
-#ifndef INCLUDED_GR_FLL_BAND_EDGE_CC_H
-#define INCLUDED_GR_FLL_BAND_EDGE_CC_H
-
-#include <gr_core_api.h>
-#include <gr_sync_block.h>
-
-class gr_fll_band_edge_cc;
-typedef boost::shared_ptr<gr_fll_band_edge_cc> gr_fll_band_edge_cc_sptr;
-GR_CORE_API gr_fll_band_edge_cc_sptr gr_make_fll_band_edge_cc (float samps_per_sym, float rolloff,
- int filter_size, float alpha, float beta);
-
-class gr_fir_ccc;
-class gri_fft_complex;
-
-/*!
- * \class gr_fll_band_edge_cc
- * \brief Frequency Lock Loop using band-edge filters
- *
- * \ingroup general
- *
- * The frequency lock loop derives a band-edge filter that covers the upper and lower bandwidths
- * of a digitally-modulated signal. The bandwidth range is determined by the excess bandwidth
- * (e.g., rolloff factor) of the modulated signal. The placement in frequency of the band-edges
- * is determined by the oversampling ratio (number of samples per symbol) and the excess bandwidth.
- * The size of the filters should be fairly large so as to average over a number of symbols.
- *
- * The FLL works by filtering the upper and lower band edges into x_u(t) and x_l(t), respectively.
- * These are combined to form cc(t) = x_u(t) + x_l(t) and ss(t) = x_u(t) - x_l(t). Combining
- * these to form the signal e(t) = Re{cc(t) \\times ss(t)^*} (where ^* is the complex conjugate)
- * provides an error signal at the DC term that is directly proportional to the carrier frequency.
- * We then make a second-order loop using the error signal that is the running average of e(t).
- *
- * In theory, the band-edge filter is the derivative of the matched filter in frequency,
- * (H_be(f) = \\frac{H(f)}{df}. In practice, this comes down to a quarter sine wave at the point
- * of the matched filter's rolloff (if it's a raised-cosine, the derivative of a cosine is a sine).
- * Extend this sine by another quarter wave to make a half wave around the band-edges is equivalent
- * in time to the sum of two sinc functions. The baseband filter fot the band edges is therefore
- * derived from this sum of sincs. The band edge filters are then just the baseband signal
- * modulated to the correct place in frequency. All of these calculations are done in the
- * 'design_filter' function.
- *
- * Note: We use FIR filters here because the filters have to have a flat phase response over the
- * entire frequency range to allow their comparisons to be valid.
- */
-
-class GR_CORE_API gr_fll_band_edge_cc : public gr_sync_block
-{
- private:
- /*!
- * Build the FLL
- * \param samps_per_sym (float) Number of samples per symbol of signal
- * \param rolloff (float) Rolloff factor of signal
- * \param filter_size (int) Size (in taps) of the filter
- * \param alpha (float) Loop gain 1
- * \param beta (float) Loop gain 2
- */
- friend GR_CORE_API gr_fll_band_edge_cc_sptr gr_make_fll_band_edge_cc (float samps_per_sym, float rolloff,
- int filter_size, float alpha, float beta);
-
- float d_alpha;
- float d_beta;
- float d_max_freq;
- float d_min_freq;
-
- gr_fir_ccc* d_filter_upper;
- gr_fir_ccc* d_filter_lower;
- bool d_updated;
- float d_error;
- float d_freq;
- float d_phase;
-
- /*!
- * Build the FLL
- * \param samps_per_sym (float) number of samples per symbol
- * \param rolloff (float) Rolloff (excess bandwidth) of signal filter
- * \param filter_size (int) number of filter taps to generate
- * \param alpha (float) Alpha gain in the control loop
- * \param beta (float) Beta gain in the control loop
- */
- gr_fll_band_edge_cc(float samps_per_sym, float rolloff,
- int filter_size, float alpha, float beta);
-
-public:
- ~gr_fll_band_edge_cc ();
-
- /*!
- * Design the band-edge filter based on the number of samples per symbol,
- * filter rolloff factor, and the filter size
- * \param samps_per_sym (float) Number of samples per symbol of signal
- * \param rolloff (float) Rolloff factor of signal
- * \param filter_size (int) Size (in taps) of the filter
- */
- void design_filter(float samps_per_sym, float rolloff, int filter_size);
-
- /*!
- * Set the alpha gainvalue
- * \param alpha (float) new gain value
- */
- void set_alpha(float alpha);
-
- /*!
- * Set the beta gain value
- * \param beta (float) new gain value
- */
- void set_beta(float beta) { d_beta = beta; }
-
- /*!
- * Print the taps to screen.
- */
- void print_taps();
-
- int work (int noutput_items,
- gr_vector_const_void_star &input_items,
- gr_vector_void_star &output_items);
-};
-
-#endif
diff --git a/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.i b/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.i
deleted file mode 100644
index c9c792c8a6..0000000000
--- a/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.i
+++ /dev/null
@@ -1,41 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2009 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-GR_SWIG_BLOCK_MAGIC(gr,fll_band_edge_cc);
-
-gr_fll_band_edge_cc_sptr gr_make_fll_band_edge_cc (float samps_per_sym, float rolloff,
- int filter_size, float alpha, float beta);
-
-class gr_fll_band_edge_cc : public gr_sync_block
-{
- private:
- gr_fll_band_edge_cc (float samps_per_sym, float rolloff,
- int filter_size, float alpha, float beta);
-
- public:
- ~gr_fll_band_edge_cc ();
-
- void set_alpha (float alpha);
- void set_beta (float beta);
- void design_filter(float samps_per_sym, float rolloff, int filter_size);
- void print_taps();
-};
diff --git a/gnuradio-core/src/lib/general/gr_pll_refout_cc.cc b/gnuradio-core/src/lib/general/gr_pll_refout_cc.cc
index 8a7fbf88ba..8968cd3f18 100644
--- a/gnuradio-core/src/lib/general/gr_pll_refout_cc.cc
+++ b/gnuradio-core/src/lib/general/gr_pll_refout_cc.cc
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2004,2010 Free Software Foundation, Inc.
+ * Copyright 2004,2010,2011 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -20,8 +20,6 @@
* Boston, MA 02110-1301, USA.
*/
-// WARNING: this file is machine generated. Edits will be over written
-
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@@ -35,18 +33,16 @@
#define M_TWOPI (2*M_PI)
gr_pll_refout_cc_sptr
-gr_make_pll_refout_cc (float alpha, float beta, float max_freq, float min_freq)
+gr_make_pll_refout_cc (float loop_bw, float max_freq, float min_freq)
{
- return gnuradio::get_initial_sptr(new gr_pll_refout_cc (alpha, beta, max_freq, min_freq));
+ return gnuradio::get_initial_sptr(new gr_pll_refout_cc (loop_bw, max_freq, min_freq));
}
-gr_pll_refout_cc::gr_pll_refout_cc (float alpha, float beta, float max_freq, float min_freq)
+gr_pll_refout_cc::gr_pll_refout_cc (float loop_bw, float max_freq, float min_freq)
: gr_sync_block ("pll_refout_cc",
gr_make_io_signature (1, 1, sizeof (gr_complex)),
gr_make_io_signature (1, 1, sizeof (gr_complex))),
- d_alpha(alpha), d_beta(beta),
- d_max_freq(max_freq), d_min_freq(min_freq),
- d_phase(0), d_freq((max_freq+min_freq)/2)
+ gri_control_loop(loop_bw, max_freq, min_freq)
{
}
@@ -84,13 +80,10 @@ gr_pll_refout_cc::work (int noutput_items,
while (size-- > 0) {
error = phase_detector(*iptr++,d_phase);
- d_freq = d_freq + d_beta * error;
- d_phase = mod_2pi(d_phase + d_freq + d_alpha * error);
+ advance_loop(error);
+ phase_wrap();
+ frequency_limit();
- if (d_freq > d_max_freq)
- d_freq = d_max_freq;
- else if (d_freq < d_min_freq)
- d_freq = d_min_freq;
gr_sincosf(d_phase,&t_imag,&t_real);
*optr++ = gr_complex(t_real,t_imag);
}
diff --git a/gnuradio-core/src/lib/general/gr_pll_refout_cc.h b/gnuradio-core/src/lib/general/gr_pll_refout_cc.h
index 833ed51cc7..11bce50464 100644
--- a/gnuradio-core/src/lib/general/gr_pll_refout_cc.h
+++ b/gnuradio-core/src/lib/general/gr_pll_refout_cc.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2004 Free Software Foundation, Inc.
+ * Copyright 2004,2011 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -20,19 +20,18 @@
* Boston, MA 02110-1301, USA.
*/
-
-
#ifndef INCLUDED_GR_PLL_REFOUT_CC_H
#define INCLUDED_GR_PLL_REFOUT_CC_H
#include <gr_core_api.h>
#include <gr_sync_block.h>
+#include <gri_control_loop.h>
class gr_pll_refout_cc;
typedef boost::shared_ptr<gr_pll_refout_cc> gr_pll_refout_cc_sptr;
-GR_CORE_API gr_pll_refout_cc_sptr gr_make_pll_refout_cc (float alpha, float beta,
- float max_freq, float min_freq);
+GR_CORE_API gr_pll_refout_cc_sptr gr_make_pll_refout_cc (float loop_bw,
+ float max_freq, float min_freq);
/*!
* \brief Implements a PLL which locks to the input frequency and outputs a carrier
* \ingroup sync_blk
@@ -48,20 +47,19 @@ GR_CORE_API gr_pll_refout_cc_sptr gr_make_pll_refout_cc (float alpha, float beta
* and beta is the frequency gain (second order, units of radians per sample per radian)
* \sa gr_pll_freqdet_cf, gr_pll_carriertracking_cc
*/
-class GR_CORE_API gr_pll_refout_cc : public gr_sync_block
+class GR_CORE_API gr_pll_refout_cc : public gr_sync_block, public gri_control_loop
{
- friend GR_CORE_API gr_pll_refout_cc_sptr gr_make_pll_refout_cc (float alpha, float beta,
- float max_freq, float min_freq);
+ friend GR_CORE_API gr_pll_refout_cc_sptr gr_make_pll_refout_cc (float loop_bw,
+ float max_freq, float min_freq);
- float d_alpha,d_beta,d_max_freq,d_min_freq,d_phase,d_freq;
- gr_pll_refout_cc (float alpha, float beta, float max_freq, float min_freq);
+ gr_pll_refout_cc (float loop_bw, float max_freq, float min_freq);
int work (int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items);
private:
float mod_2pi (float in);
- float phase_detector(gr_complex sample,float ref_phase);
+ float phase_detector(gr_complex sample, float ref_phase);
};
#endif
diff --git a/gnuradio-core/src/lib/general/gr_pll_refout_cc.i b/gnuradio-core/src/lib/general/gr_pll_refout_cc.i
index 026a684ed0..834ea1e36b 100644
--- a/gnuradio-core/src/lib/general/gr_pll_refout_cc.i
+++ b/gnuradio-core/src/lib/general/gr_pll_refout_cc.i
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2005 Free Software Foundation, Inc.
+ * Copyright 2005,2011 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -22,11 +22,11 @@
GR_SWIG_BLOCK_MAGIC(gr,pll_refout_cc)
- gr_pll_refout_cc_sptr gr_make_pll_refout_cc (float alpha, float beta,
- float max_freq, float min_freq);
+gr_pll_refout_cc_sptr gr_make_pll_refout_cc (float loop_bw,
+ float max_freq, float min_freq);
-class gr_pll_refout_cc : public gr_sync_block
+class gr_pll_refout_cc : public gr_sync_block, public gri_control_loop
{
private:
- gr_pll_refout_cc (float alpha, float beta, float max_freq, float min_freq);
+ gr_pll_refout_cc (float loop_bw, float max_freq, float min_freq);
};
diff --git a/gnuradio-core/src/lib/general/gri_control_loop.cc b/gnuradio-core/src/lib/general/gri_control_loop.cc
new file mode 100644
index 0000000000..d84b474935
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gri_control_loop.cc
@@ -0,0 +1,183 @@
+/* -*- 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.
+ */
+
+#include <gri_control_loop.h>
+#include <gr_math.h>
+#include <stdexcept>
+
+#define M_TWOPI (2.0f*M_PI)
+
+gri_control_loop::gri_control_loop(float loop_bw,
+ float max_freq, float min_freq)
+ : d_phase(0), d_freq(0), d_max_freq(max_freq), d_min_freq(min_freq)
+{
+ // Set the damping factor for a critically damped system
+ d_damping = sqrtf(2.0f)/2.0f;
+
+ // Set the bandwidth, which will then call update_gains()
+ set_loop_bandwidth(loop_bw);
+}
+
+gri_control_loop::~gri_control_loop()
+{
+}
+
+void
+gri_control_loop::update_gains()
+{
+ float denom = (1.0 + 2.0*d_damping*d_loop_bw + d_loop_bw*d_loop_bw);
+ d_alpha = (4*d_damping*d_loop_bw) / denom;
+ d_beta = (4*d_loop_bw*d_loop_bw) / denom;
+}
+
+void
+gri_control_loop::advance_loop(float error)
+{
+ d_freq = d_freq + d_beta * error;
+ d_phase = d_phase + d_freq + d_alpha * error;
+}
+
+
+void
+gri_control_loop::phase_wrap()
+{
+ while(d_phase>M_TWOPI)
+ d_phase -= M_TWOPI;
+ while(d_phase<-M_TWOPI)
+ d_phase += M_TWOPI;
+}
+
+void
+gri_control_loop::frequency_limit()
+{
+ if (d_freq > d_max_freq)
+ d_freq = d_min_freq;
+ else if (d_freq < d_min_freq)
+ d_freq = d_max_freq;
+}
+
+/*******************************************************************
+ SET FUNCTIONS
+*******************************************************************/
+
+void
+gri_control_loop::set_loop_bandwidth(float bw)
+{
+ if(bw < 0) {
+ throw std::out_of_range ("gri_control_loop: invalid bandwidth. Must be >= 0.");
+ }
+
+ d_loop_bw = bw;
+ update_gains();
+}
+
+void
+gri_control_loop::set_damping_factor(float df)
+{
+ if(df < 0 || df > 1.0) {
+ throw std::out_of_range ("gri_control_loop: invalid damping factor. Must be in [0,1].");
+ }
+
+ d_damping = df;
+ update_gains();
+}
+
+void
+gri_control_loop::set_alpha(float alpha)
+{
+ if(alpha < 0 || alpha > 1.0) {
+ throw std::out_of_range ("gri_control_loop: invalid alpha. Must be in [0,1].");
+ }
+ d_alpha = alpha;
+}
+
+void
+gri_control_loop::set_beta(float beta)
+{
+ if(beta < 0 || beta > 1.0) {
+ throw std::out_of_range ("gri_control_loop: invalid beta. Must be in [0,1].");
+ }
+ d_beta = beta;
+}
+
+void
+gri_control_loop::set_frequency(float freq)
+{
+ if(freq > d_max_freq)
+ d_freq = d_min_freq;
+ else if(freq < d_min_freq)
+ d_freq = d_max_freq;
+ else
+ d_freq = freq;
+}
+
+void
+gri_control_loop::set_phase(float phase)
+{
+ d_phase = phase;
+ while(d_phase>M_TWOPI)
+ d_phase -= M_TWOPI;
+ while(d_phase<-M_TWOPI)
+ d_phase += M_TWOPI;
+}
+
+
+/*******************************************************************
+ GET FUNCTIONS
+*******************************************************************/
+
+
+float
+gri_control_loop::get_loop_bandwidth() const
+{
+ return d_loop_bw;
+}
+
+float
+gri_control_loop::get_damping_factor() const
+{
+ return d_damping;
+}
+
+float
+gri_control_loop::get_alpha() const
+{
+ return d_alpha;
+}
+
+float
+gri_control_loop::get_beta() const
+{
+ return d_beta;
+}
+
+float
+gri_control_loop::get_frequency() const
+{
+ return d_freq;
+}
+
+float
+gri_control_loop::get_phase() const
+{
+ return d_phase;
+}
diff --git a/gnuradio-core/src/lib/general/gri_control_loop.h b/gnuradio-core/src/lib/general/gri_control_loop.h
new file mode 100644
index 0000000000..3aeac58f78
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gri_control_loop.h
@@ -0,0 +1,203 @@
+/* -*- 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 GRI_CONTROL_LOOP
+#define GRI_CONTROL_LOOP
+
+#include <gr_core_api.h>
+
+class GR_CORE_API gri_control_loop
+{
+ protected:
+ float d_phase, d_freq;
+ float d_max_freq, d_min_freq;
+ float d_damping, d_loop_bw;
+ float d_alpha, d_beta;
+
+ public:
+ gri_control_loop(float loop_bw, float max_freq, float min_freq);
+ virtual ~gri_control_loop();
+
+ /*! \brief update the system gains from the loop bandwidth and damping factor
+ *
+ * This function updates the system gains based on the loop
+ * bandwidth and damping factor of the system.
+ * These two factors can be set separately through their own
+ * set functions.
+ */
+ void update_gains();
+
+ /*! \brief update the system gains from the loop bandwidth and damping factor
+ *
+ * This function updates the system gains based on the loop
+ * bandwidth and damping factor of the system.
+ * These two factors can be set separately through their own
+ * set functions.
+ */
+ void advance_loop(float error);
+
+ /*! \brief Keep the phase between -2pi and 2pi
+ *
+ * This function keeps the phase between -2pi and 2pi. If the phase
+ * is greater than 2pi by d, it wraps around to be -2pi+d; similarly if
+ * it is less than -2pi by d, it wraps around to 2pi-d.
+ *
+ * This function should be called after advance_loop to keep the phase
+ * in a good operating region. It is set as a separate method in case
+ * another way is desired as this is fairly heavy-handed.
+ */
+ void phase_wrap();
+
+ /*! \brief Keep the frequency between d_min_freq and d_max_freq
+ *
+ * This function keeps the frequency between d_min_freq and d_max_freq.
+ * If the frequency is greater than d_max_freq, it is set to d_max_freq.
+ * If the frequency is less than d_min_freq, it is set to d_min_freq.
+ *
+ * This function should be called after advance_loop to keep the frequency
+ * in the specified region. It is set as a separate method in case
+ * another way is desired as this is fairly heavy-handed.
+ */
+ void frequency_limit();
+
+ /*******************************************************************
+ SET FUNCTIONS
+ *******************************************************************/
+
+ /*!
+ * \brief Set the loop bandwidth
+ *
+ * Set the loop filter's bandwidth to \p bw. This should be between
+ * 2*pi/200 and 2*pi/100 (in rads/samp). It must also be a positive
+ * number.
+ *
+ * When a new damping factor is set, the gains, alpha and beta, of the loop
+ * are recalculated by a call to update_gains().
+ *
+ * \param bw (float) new bandwidth
+ *
+ */
+ void set_loop_bandwidth(float bw);
+
+ /*!
+ * \brief Set the loop damping factor
+ *
+ * Set the loop filter's damping factor to \p df. The damping factor
+ * should be sqrt(2)/2.0 for critically damped systems.
+ * Set it to anything else only if you know what you are doing. It must
+ * be a number between 0 and 1.
+ *
+ * When a new damping factor is set, the gains, alpha and beta, of the loop
+ * are recalculated by a call to update_gains().
+ *
+ * \param df (float) new damping factor
+ *
+ */
+ void set_damping_factor(float df);
+
+ /*!
+ * \brief Set the loop gain alpha
+ *
+ * Set's the loop filter's alpha gain parameter.
+ *
+ * This value should really only be set by adjusting the loop bandwidth
+ * and damping factor.
+ *
+ * \param alpha (float) new alpha gain
+ *
+ */
+ void set_alpha(float alpha);
+
+ /*!
+ * \brief Set the loop gain beta
+ *
+ * Set's the loop filter's beta gain parameter.
+ *
+ * This value should really only be set by adjusting the loop bandwidth
+ * and damping factor.
+ *
+ * \param beta (float) new beta gain
+ *
+ */
+ void set_beta(float beta);
+
+ /*!
+ * \brief Set the Costas loop's frequency.
+ *
+ * Set's the Costas Loop's frequency. While this is normally updated by the
+ * inner loop of the algorithm, it could be useful to manually initialize,
+ * set, or reset this under certain circumstances.
+ *
+ * \param freq (float) new frequency
+ *
+ */
+ void set_frequency(float freq);
+
+ /*!
+ * \brief Set the Costas loop's phase.
+ *
+ * Set's the Costas Loop's phase. While this is normally updated by the
+ * inner loop of the algorithm, it could be useful to manually initialize,
+ * set, or reset this under certain circumstances.
+ *
+ * \param phase (float) new phase
+ *
+ */
+ void set_phase(float phase);
+
+
+ /*******************************************************************
+ GET FUNCTIONS
+ *******************************************************************/
+
+ /*!
+ * \brief Returns the loop bandwidth
+ */
+ float get_loop_bandwidth() const;
+
+ /*!
+ * \brief Returns the loop damping factor
+ */
+ float get_damping_factor() const;
+
+ /*!
+ * \brief Returns the loop gain alpha
+ */
+ float get_alpha() const;
+
+ /*!
+ * \brief Returns the loop gain beta
+ */
+ float get_beta() const;
+
+ /*!
+ * \brief Get the Costas loop's frequency estimate
+ */
+ float get_frequency() const;
+
+ /*!
+ * \brief Get the Costas loop's phase estimate
+ */
+ float get_phase() const;
+};
+
+#endif /* GRI_CONTROL_LOOP */
diff --git a/gnuradio-core/src/lib/general/gri_control_loop.i b/gnuradio-core/src/lib/general/gri_control_loop.i
new file mode 100644
index 0000000000..67f8838cb1
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gri_control_loop.i
@@ -0,0 +1,57 @@
+/* -*- 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.
+ */
+
+
+class gri_control_loop
+{
+ public:
+ gri_control_loop(float loop_bw, float max_freq, float min_freq);
+ virtual ~gri_control_loop();
+
+ void update_gains();
+ void advance_loop(float error);
+ void phase_wrap();
+ void frequency_limit();
+
+ /*******************************************************************
+ SET FUNCTIONS
+ *******************************************************************/
+
+ void set_loop_bandwidth(float bw);
+ void set_damping_factor(float df);
+ void set_alpha(float alpha);
+ void set_beta(float beta);
+ void set_frequency(float freq);
+ void set_phase(float phase);
+
+
+ /*******************************************************************
+ GET FUNCTIONS
+ *******************************************************************/
+
+ float get_loop_bandwidth() const;
+ float get_damping_factor() const;
+ float get_alpha() const;
+ float get_beta() const;
+ float get_frequency() const;
+ float get_phase() const;
+};
diff --git a/gr-digital/examples/Makefile.am b/gr-digital/examples/Makefile.am
index 8ed53fe41c..ca36716fae 100644
--- a/gr-digital/examples/Makefile.am
+++ b/gr-digital/examples/Makefile.am
@@ -23,6 +23,9 @@ include $(top_srcdir)/Makefile.common
ourdatadir = $(exampledir)/digital
+noinst_PYTHON = \
+ example_fll.py
+
dist_ourdata_SCRIPTS = \
transmit_path.py \
receive_path.py
diff --git a/gr-digital/examples/benchmark_rx.py b/gr-digital/examples/benchmark_rx.py
index 9d8734e3de..9390540dd4 100755
--- a/gr-digital/examples/benchmark_rx.py
+++ b/gr-digital/examples/benchmark_rx.py
@@ -48,11 +48,14 @@ class my_top_block(gr.top_block):
self.rxpath = receive_path(demodulator, rx_callback, options)
if(options.from_file is not None):
+ self.thr = gr.throttle(gr.sizeof_gr_complex, 1e6)
self.source = gr.file_source(gr.sizeof_gr_complex, options.from_file)
+ self.connect(self.source, self.thr, self.rxpath)
else:
+ self.thr = gr.throttle(gr.sizeof_gr_complex, 1e6)
self.source = gr.null_source(gr.sizeof_gr_complex)
+ self.connect(self.source, self.thr, self.rxpath)
- self.connect(self.source, self.rxpath)
# /////////////////////////////////////////////////////////////////////////////
# main
diff --git a/gr-digital/examples/benchmark_tx.py b/gr-digital/examples/benchmark_tx.py
index 01902c0e37..e5d24915af 100755
--- a/gr-digital/examples/benchmark_tx.py
+++ b/gr-digital/examples/benchmark_tx.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
#
-# Copyright 2010 Free Software Foundation, Inc.
+# Copyright 2010,2011 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
diff --git a/gr-digital/examples/example_costas.py b/gr-digital/examples/example_costas.py
new file mode 100755
index 0000000000..aef0196cc0
--- /dev/null
+++ b/gr-digital/examples/example_costas.py
@@ -0,0 +1,116 @@
+#!/usr/bin/env python
+
+from gnuradio import gr, digital
+from gnuradio import eng_notation
+from gnuradio.eng_option import eng_option
+from optparse import OptionParser
+
+try:
+ import scipy
+except ImportError:
+ print "Error: could not import scipy (http://www.scipy.org/)"
+ sys.exit(1)
+
+try:
+ import pylab
+except ImportError:
+ print "Error: could not import pylab (http://matplotlib.sourceforge.net/)"
+ sys.exit(1)
+
+class example_costas(gr.top_block):
+ def __init__(self, N, sps, rolloff, ntaps, bw, noise, foffset, toffset, poffset):
+ gr.top_block.__init__(self)
+
+ rrc_taps = gr.firdes.root_raised_cosine(
+ sps, sps, 1.0, rolloff, ntaps)
+
+ data = 2.0*scipy.random.randint(0, 2, N) - 1.0
+ data = scipy.exp(1j*poffset) * data
+
+ self.src = gr.vector_source_c(data.tolist(), False)
+ self.rrc = gr.interp_fir_filter_ccf(sps, rrc_taps)
+ self.chn = gr.channel_model(noise, foffset, toffset)
+ self.cst = digital.costas_loop_cc(bw, 2)
+
+ self.vsnk_src = gr.vector_sink_c()
+ self.vsnk_cst = gr.vector_sink_c()
+ self.vsnk_frq = gr.vector_sink_f()
+
+ self.connect(self.src, self.rrc, self.chn, self.cst, self.vsnk_cst)
+ self.connect(self.rrc, self.vsnk_src)
+ self.connect((self.cst,1), self.vsnk_frq)
+
+def main():
+ parser = OptionParser(option_class=eng_option, conflict_handler="resolve")
+ parser.add_option("-N", "--nsamples", type="int", default=2000,
+ help="Set the number of samples to process [default=%default]")
+ parser.add_option("-S", "--sps", type="int", default=4,
+ help="Set the samples per symbol [default=%default]")
+ parser.add_option("-r", "--rolloff", type="eng_float", default=0.35,
+ help="Set the rolloff factor [default=%default]")
+ parser.add_option("-W", "--bandwidth", type="eng_float", default=2*scipy.pi/100.0,
+ help="Set the loop bandwidth [default=%default]")
+ parser.add_option("-n", "--ntaps", type="int", default=45,
+ help="Set the number of taps in the filters [default=%default]")
+ parser.add_option("", "--noise", type="eng_float", default=0.0,
+ help="Set the simulation noise voltage [default=%default]")
+ parser.add_option("-f", "--foffset", type="eng_float", default=0.0,
+ help="Set the simulation's normalized frequency offset (in Hz) [default=%default]")
+ parser.add_option("-t", "--toffset", type="eng_float", default=1.0,
+ help="Set the simulation's timing offset [default=%default]")
+ parser.add_option("-p", "--poffset", type="eng_float", default=0.707,
+ help="Set the simulation's phase offset [default=%default]")
+ (options, args) = parser.parse_args ()
+
+ # Adjust N for the interpolation by sps
+ options.nsamples = options.nsamples // options.sps
+
+ # Set up the program-under-test
+ put = example_costas(options.nsamples, options.sps, options.rolloff,
+ options.ntaps, options.bandwidth, options.noise,
+ options.foffset, options.toffset, options.poffset)
+ put.run()
+
+ data_src = scipy.array(put.vsnk_src.data())
+
+ # Convert the FLL's LO frequency from rads/sec to Hz
+ data_frq = scipy.array(put.vsnk_frq.data()) / (2.0*scipy.pi)
+
+ # adjust this to align with the data.
+ data_cst = scipy.array(3*[0,]+list(put.vsnk_cst.data()))
+
+ # Plot the Costas loop's LO frequency
+ f1 = pylab.figure(1, figsize=(12,10), facecolor='w')
+ s1 = f1.add_subplot(2,2,1)
+ s1.plot(data_frq)
+ s1.set_title("Costas LO")
+ s1.set_xlabel("Samples")
+ s1.set_ylabel("Frequency (normalized Hz)")
+
+ # Plot the IQ symbols
+ s3 = f1.add_subplot(2,2,2)
+ s3.plot(data_src.real, data_src.imag, "o")
+ s3.plot(data_cst.real, data_cst.imag, "rx")
+ s3.set_title("IQ")
+ s3.set_xlabel("Real part")
+ s3.set_ylabel("Imag part")
+ s3.set_xlim([-2, 2])
+ s3.set_ylim([-2, 2])
+
+ # Plot the symbols in time
+ s4 = f1.add_subplot(2,2,3)
+ s4.set_position([0.125, 0.05, 0.775, 0.4])
+ s4.plot(data_src.real, "o-")
+ s4.plot(data_cst.real, "rx-")
+ s4.set_title("Symbols")
+ s4.set_xlabel("Samples")
+ s4.set_ylabel("Real Part of Signals")
+
+ pylab.show()
+
+if __name__ == "__main__":
+ try:
+ main()
+ except KeyboardInterrupt:
+ pass
+
diff --git a/gr-digital/examples/example_fll.py b/gr-digital/examples/example_fll.py
new file mode 100755
index 0000000000..3b75b5a758
--- /dev/null
+++ b/gr-digital/examples/example_fll.py
@@ -0,0 +1,126 @@
+#!/usr/bin/env python
+
+from gnuradio import gr, digital
+from gnuradio import eng_notation
+from gnuradio.eng_option import eng_option
+from optparse import OptionParser
+
+try:
+ import scipy
+except ImportError:
+ print "Error: could not import scipy (http://www.scipy.org/)"
+ sys.exit(1)
+
+try:
+ import pylab
+except ImportError:
+ print "Error: could not import pylab (http://matplotlib.sourceforge.net/)"
+ sys.exit(1)
+
+class example_fll(gr.top_block):
+ def __init__(self, N, sps, rolloff, ntaps, bw, noise, foffset, toffset, poffset):
+ gr.top_block.__init__(self)
+
+ rrc_taps = gr.firdes.root_raised_cosine(
+ sps, sps, 1.0, rolloff, ntaps)
+
+ data = 2.0*scipy.random.randint(0, 2, N) - 1.0
+ data = scipy.exp(1j*poffset) * data
+
+ self.src = gr.vector_source_c(data.tolist(), False)
+ self.rrc = gr.interp_fir_filter_ccf(sps, rrc_taps)
+ self.chn = gr.channel_model(noise, foffset, toffset)
+ self.fll = digital.fll_band_edge_cc(sps, rolloff, ntaps, bw)
+
+ self.vsnk_src = gr.vector_sink_c()
+ self.vsnk_fll = gr.vector_sink_c()
+ self.vsnk_frq = gr.vector_sink_f()
+ self.vsnk_phs = gr.vector_sink_f()
+ self.vsnk_err = gr.vector_sink_f()
+
+ self.connect(self.src, self.rrc, self.chn, self.fll, self.vsnk_fll)
+ self.connect(self.rrc, self.vsnk_src)
+ self.connect((self.fll,1), self.vsnk_frq)
+ self.connect((self.fll,2), self.vsnk_phs)
+ self.connect((self.fll,3), self.vsnk_err)
+
+def main():
+ parser = OptionParser(option_class=eng_option, conflict_handler="resolve")
+ parser.add_option("-N", "--nsamples", type="int", default=2000,
+ help="Set the number of samples to process [default=%default]")
+ parser.add_option("-S", "--sps", type="int", default=4,
+ help="Set the samples per symbol [default=%default]")
+ parser.add_option("-r", "--rolloff", type="eng_float", default=0.35,
+ help="Set the rolloff factor [default=%default]")
+ parser.add_option("-W", "--bandwidth", type="eng_float", default=2*scipy.pi/100.0,
+ help="Set the loop bandwidth [default=%default]")
+ parser.add_option("-n", "--ntaps", type="int", default=45,
+ help="Set the number of taps in the filters [default=%default]")
+ parser.add_option("", "--noise", type="eng_float", default=0.0,
+ help="Set the simulation noise voltage [default=%default]")
+ parser.add_option("-f", "--foffset", type="eng_float", default=0.2,
+ help="Set the simulation's normalized frequency offset (in Hz) [default=%default]")
+ parser.add_option("-t", "--toffset", type="eng_float", default=1.0,
+ help="Set the simulation's timing offset [default=%default]")
+ parser.add_option("-p", "--poffset", type="eng_float", default=0.0,
+ help="Set the simulation's phase offset [default=%default]")
+ (options, args) = parser.parse_args ()
+
+ # Adjust N for the interpolation by sps
+ options.nsamples = options.nsamples // options.sps
+
+ # Set up the program-under-test
+ put = example_fll(options.nsamples, options.sps, options.rolloff,
+ options.ntaps, options.bandwidth, options.noise,
+ options.foffset, options.toffset, options.poffset)
+ put.run()
+
+ data_src = scipy.array(put.vsnk_src.data())
+ data_err = scipy.array(put.vsnk_err.data())
+
+ # Convert the FLL's LO frequency from rads/sec to Hz
+ data_frq = scipy.array(put.vsnk_frq.data()) / (2.0*scipy.pi)
+
+ # adjust this to align with the data. There are 2 filters of
+ # ntaps long and the channel introduces another 4 sample delay.
+ data_fll = scipy.array(put.vsnk_fll.data()[2*options.ntaps-4:])
+
+ # Plot the FLL's LO frequency
+ f1 = pylab.figure(1, figsize=(12,10))
+ s1 = f1.add_subplot(2,2,1)
+ s1.plot(data_frq)
+ s1.set_title("FLL LO")
+ s1.set_xlabel("Samples")
+ s1.set_ylabel("Frequency (normalized Hz)")
+
+ # Plot the FLL's error
+ s2 = f1.add_subplot(2,2,2)
+ s2.plot(data_err)
+ s2.set_title("FLL Error")
+ s2.set_xlabel("Samples")
+ s2.set_ylabel("FLL Loop error")
+
+ # Plot the IQ symbols
+ s3 = f1.add_subplot(2,2,3)
+ s3.plot(data_src.real, data_src.imag, "o")
+ s3.plot(data_fll.real, data_fll.imag, "rx")
+ s3.set_title("IQ")
+ s3.set_xlabel("Real part")
+ s3.set_ylabel("Imag part")
+
+ # Plot the symbols in time
+ s4 = f1.add_subplot(2,2,4)
+ s4.plot(data_src.real, "o-")
+ s4.plot(data_fll.real, "rx-")
+ s4.set_title("Symbols")
+ s4.set_xlabel("Samples")
+ s4.set_ylabel("Real Part of Signals")
+
+ pylab.show()
+
+if __name__ == "__main__":
+ try:
+ main()
+ except KeyboardInterrupt:
+ pass
+
diff --git a/gr-digital/examples/example_timing.py b/gr-digital/examples/example_timing.py
new file mode 100755
index 0000000000..fd86acfb16
--- /dev/null
+++ b/gr-digital/examples/example_timing.py
@@ -0,0 +1,211 @@
+#!/usr/bin/env python
+
+from gnuradio import gr, digital
+from gnuradio import eng_notation
+from gnuradio.eng_option import eng_option
+from optparse import OptionParser
+
+try:
+ import scipy
+except ImportError:
+ print "Error: could not import scipy (http://www.scipy.org/)"
+ sys.exit(1)
+
+try:
+ import pylab
+except ImportError:
+ print "Error: could not import pylab (http://matplotlib.sourceforge.net/)"
+ sys.exit(1)
+
+from scipy import fftpack
+
+class example_timing(gr.top_block):
+ def __init__(self, N, sps, rolloff, ntaps, bw, noise,
+ foffset, toffset, poffset, mode=0):
+ gr.top_block.__init__(self)
+
+ rrc_taps = gr.firdes.root_raised_cosine(
+ sps, sps, 1.0, rolloff, ntaps)
+
+ gain = 2*scipy.pi/100.0
+ nfilts = 32
+ rrc_taps_rx = gr.firdes.root_raised_cosine(
+ nfilts, sps*nfilts, 1.0, rolloff, ntaps*nfilts)
+
+ data = 2.0*scipy.random.randint(0, 2, N) - 1.0
+ data = scipy.exp(1j*poffset) * data
+
+ self.src = gr.vector_source_c(data.tolist(), False)
+ self.rrc = gr.interp_fir_filter_ccf(sps, rrc_taps)
+ self.chn = gr.channel_model(noise, foffset, toffset)
+ self.off = gr.fractional_interpolator_cc(0.20, 1.0)
+
+ if mode == 0:
+ self.clk = gr.pfb_clock_sync_ccf(sps, gain, rrc_taps_rx,
+ nfilts, nfilts//2, 3.5)
+ self.taps = self.clk.get_taps()
+ self.dtaps = self.clk.get_diff_taps()
+
+ self.vsnk_err = gr.vector_sink_f()
+ self.vsnk_rat = gr.vector_sink_f()
+ self.vsnk_phs = gr.vector_sink_f()
+
+ self.connect((self.clk,1), self.vsnk_err)
+ self.connect((self.clk,2), self.vsnk_rat)
+ self.connect((self.clk,3), self.vsnk_phs)
+
+ else: # mode == 1
+ mu = 0.5
+ gain_mu = 0.1
+ gain_omega = 0.25*gain_mu*gain_mu
+ omega_rel_lim = 0.02
+ self.clk = digital.clock_recovery_mm_cc(sps, gain_omega,
+ mu, gain_mu,
+ omega_rel_lim)
+
+ self.vsnk_err = gr.vector_sink_f()
+
+ self.connect((self.clk,1), self.vsnk_err)
+
+ self.vsnk_src = gr.vector_sink_c()
+ self.vsnk_clk = gr.vector_sink_c()
+
+ self.connect(self.src, self.rrc, self.chn, self.off, self.clk, self.vsnk_clk)
+ self.connect(self.off, self.vsnk_src)
+
+
+def main():
+ parser = OptionParser(option_class=eng_option, conflict_handler="resolve")
+ parser.add_option("-N", "--nsamples", type="int", default=2000,
+ help="Set the number of samples to process [default=%default]")
+ parser.add_option("-S", "--sps", type="int", default=4,
+ help="Set the samples per symbol [default=%default]")
+ parser.add_option("-r", "--rolloff", type="eng_float", default=0.35,
+ help="Set the rolloff factor [default=%default]")
+ parser.add_option("-W", "--bandwidth", type="eng_float", default=2*scipy.pi/100.0,
+ help="Set the loop bandwidth [default=%default]")
+ parser.add_option("-n", "--ntaps", type="int", default=45,
+ help="Set the number of taps in the filters [default=%default]")
+ parser.add_option("", "--noise", type="eng_float", default=0.0,
+ help="Set the simulation noise voltage [default=%default]")
+ parser.add_option("-f", "--foffset", type="eng_float", default=0.0,
+ help="Set the simulation's normalized frequency offset (in Hz) [default=%default]")
+ parser.add_option("-t", "--toffset", type="eng_float", default=1.0,
+ help="Set the simulation's timing offset [default=%default]")
+ parser.add_option("-p", "--poffset", type="eng_float", default=0.0,
+ help="Set the simulation's phase offset [default=%default]")
+ parser.add_option("-M", "--mode", type="int", default=0,
+ help="Set the recovery mode (0: polyphase, 1: M&M) [default=%default]")
+ (options, args) = parser.parse_args ()
+
+ # Adjust N for the interpolation by sps
+ options.nsamples = options.nsamples // options.sps
+
+ # Set up the program-under-test
+ put = example_timing(options.nsamples, options.sps, options.rolloff,
+ options.ntaps, options.bandwidth, options.noise,
+ options.foffset, options.toffset, options.poffset,
+ options.mode)
+ put.run()
+
+ if options.mode == 0:
+ data_src = scipy.array(put.vsnk_src.data()[20:])
+ data_clk = scipy.array(put.vsnk_clk.data()[20:])
+
+ data_err = scipy.array(put.vsnk_err.data()[20:])
+ data_rat = scipy.array(put.vsnk_rat.data()[20:])
+ data_phs = scipy.array(put.vsnk_phs.data()[20:])
+
+ f1 = pylab.figure(1, figsize=(12,10), facecolor='w')
+
+ # Plot the IQ symbols
+ s1 = f1.add_subplot(2,2,1)
+ s1.plot(data_src.real, data_src.imag, "bo")
+ s1.plot(data_clk.real, data_clk.imag, "ro")
+ s1.set_title("IQ")
+ s1.set_xlabel("Real part")
+ s1.set_ylabel("Imag part")
+ s1.set_xlim([-2, 2])
+ s1.set_ylim([-2, 2])
+
+ # Plot the symbols in time
+ s2 = f1.add_subplot(2,2,2)
+ s2.plot(data_src.real, "bo-")
+ s2.plot(data_clk.real, "ro")
+ s2.set_title("Symbols")
+ s2.set_xlabel("Samples")
+ s2.set_ylabel("Real Part of Signals")
+
+ # Plot the clock recovery loop's error
+ s3 = f1.add_subplot(2,2,3)
+ s3.plot(data_err)
+ s3.set_title("Clock Recovery Loop Error")
+ s3.set_xlabel("Samples")
+ s3.set_ylabel("Error")
+
+ # Plot the clock recovery loop's error
+ s4 = f1.add_subplot(2,2,4)
+ s4.plot(data_phs)
+ s4.set_title("Clock Recovery Loop Filter Phase")
+ s4.set_xlabel("Samples")
+ s4.set_ylabel("Filter Phase")
+
+
+ diff_taps = put.dtaps
+ ntaps = len(diff_taps[0])
+ nfilts = len(diff_taps)
+ t = scipy.arange(0, ntaps*nfilts)
+
+ f3 = pylab.figure(3, figsize=(12,10), facecolor='w')
+ s31 = f3.add_subplot(2,1,1)
+ s32 = f3.add_subplot(2,1,2)
+ s31.set_title("Differential Filters")
+ s32.set_title("FFT of Differential Filters")
+
+ for i,d in enumerate(diff_taps):
+ D = 20.0*scipy.log10(abs(fftpack.fftshift(fftpack.fft(d, 10000))))
+ s31.plot(t[i::nfilts].real, d, "-o")
+ s32.plot(D)
+
+ # If testing the M&M clock recovery loop
+ else:
+ data_src = scipy.array(put.vsnk_src.data()[20:])
+ data_clk = scipy.array(put.vsnk_clk.data()[20:])
+
+ data_err = scipy.array(put.vsnk_err.data()[20:])
+
+ f1 = pylab.figure(1, figsize=(12,10), facecolor='w')
+
+ # Plot the IQ symbols
+ s1 = f1.add_subplot(2,2,1)
+ s1.plot(data_src.real, data_src.imag, "o")
+ s1.plot(data_clk.real, data_clk.imag, "ro")
+ s1.set_title("IQ")
+ s1.set_xlabel("Real part")
+ s1.set_ylabel("Imag part")
+ s1.set_xlim([-2, 2])
+ s1.set_ylim([-2, 2])
+
+ # Plot the symbols in time
+ s2 = f1.add_subplot(2,2,2)
+ s2.plot(data_src.real, "o-")
+ s2.plot(data_clk.real, "ro")
+ s2.set_title("Symbols")
+ s2.set_xlabel("Samples")
+ s2.set_ylabel("Real Part of Signals")
+
+ # Plot the clock recovery loop's error
+ s3 = f1.add_subplot(2,2,3)
+ s3.plot(data_err)
+ s3.set_title("Clock Recovery Loop Error")
+ s3.set_xlabel("Samples")
+ s3.set_ylabel("Error")
+
+ pylab.show()
+
+if __name__ == "__main__":
+ try:
+ main()
+ except KeyboardInterrupt:
+ pass
+
diff --git a/gr-digital/examples/receive_path.py b/gr-digital/examples/receive_path.py
index 9bc5f7b8f2..dd8eb1a0dd 100644
--- a/gr-digital/examples/receive_path.py
+++ b/gr-digital/examples/receive_path.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
#
-# Copyright 2005,2006,2007 Free Software Foundation, Inc.
+# Copyright 2005-2007,2011 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -42,7 +42,6 @@ class receive_path(gr.hier_block2):
self._verbose = options.verbose
self._bitrate = options.bitrate # desired bit rate
- self._samples_per_symbol = options.samples_per_symbol # desired samples/symbol
self._rx_callback = rx_callback # this callback is fired when there's a packet available
self._demod_class = demod_class # the demodulator_class we're using
@@ -50,10 +49,13 @@ class receive_path(gr.hier_block2):
# Get demod_kwargs
demod_kwargs = self._demod_class.extract_kwargs_from_options(options)
+ # Build the demodulator
+ self.demodulator = self._demod_class(**demod_kwargs)
+
# Design filter to get actual channel we want
sw_decim = 1
chan_coeffs = gr.firdes.low_pass (1.0, # gain
- sw_decim * self._samples_per_symbol, # sampling rate
+ sw_decim * self.samples_per_symbol(), # sampling rate
1.0, # midpoint of trans. band
0.5, # width of trans. band
gr.firdes.WIN_HANN) # filter type
@@ -61,7 +63,7 @@ class receive_path(gr.hier_block2):
# receiver
self.packet_receiver = \
- digital.demod_pkts(self._demod_class(**demod_kwargs),
+ digital.demod_pkts(self.demodulator,
access_code=None,
callback=self._rx_callback,
threshold=-1)
@@ -88,7 +90,10 @@ class receive_path(gr.hier_block2):
return self._bitrate
def samples_per_symbol(self):
- return self._samples_per_symbol
+ return self.demodulator._samples_per_symbol
+
+ def differential(self):
+ return self.demodulator._differential
def carrier_sensed(self):
"""
@@ -137,4 +142,5 @@ class receive_path(gr.hier_block2):
print "\nReceive Path:"
print "modulation: %s" % (self._demod_class.__name__)
print "bitrate: %sb/s" % (eng_notation.num_to_str(self._bitrate))
- print "samples/symbol: %.4f" % (self._samples_per_symbol)
+ print "samples/symbol: %.4f" % (self.samples_per_symbol())
+ print "Differential: %s" % (self.differential())
diff --git a/gr-digital/examples/transmit_path.py b/gr-digital/examples/transmit_path.py
index 91869ad9ad..f22ffb3278 100644
--- a/gr-digital/examples/transmit_path.py
+++ b/gr-digital/examples/transmit_path.py
@@ -44,17 +44,17 @@ class transmit_path(gr.hier_block2):
self._verbose = options.verbose
self._tx_amplitude = options.tx_amplitude # digital amplitude sent to USRP
self._bitrate = options.bitrate # desired bit rate
- self._samples_per_symbol = options.samples_per_symbol # desired samples/baud
self._modulator_class = modulator_class # the modulator_class we are using
# Get mod_kwargs
mod_kwargs = self._modulator_class.extract_kwargs_from_options(options)
-
+
# transmitter
- modulator = self._modulator_class(**mod_kwargs)
+ self.modulator = self._modulator_class(**mod_kwargs)
+
self.packet_transmitter = \
- digital.mod_pkts(modulator,
+ digital.mod_pkts(self.modulator,
access_code=None,
msgq_limit=4,
pad_for_usrp=True)
@@ -87,7 +87,10 @@ class transmit_path(gr.hier_block2):
return self._bitrate
def samples_per_symbol(self):
- return self._samples_per_symbol
+ return self.modulator._samples_per_symbol
+
+ def differential(self):
+ return self.modulator._differential
def add_options(normal, expert):
"""
@@ -115,5 +118,5 @@ class transmit_path(gr.hier_block2):
print "Tx amplitude %s" % (self._tx_amplitude)
print "modulation: %s" % (self._modulator_class.__name__)
print "bitrate: %sb/s" % (eng_notation.num_to_str(self._bitrate))
- print "samples/symbol: %.4f" % (self._samples_per_symbol)
-
+ print "samples/symbol: %.4f" % (self.samples_per_symbol())
+ print "Differential: %s" % (self.differential())
diff --git a/gr-digital/lib/CMakeLists.txt b/gr-digital/lib/CMakeLists.txt
index b7d93da6b2..30e1e3a400 100644
--- a/gr-digital/lib/CMakeLists.txt
+++ b/gr-digital/lib/CMakeLists.txt
@@ -42,6 +42,7 @@ LIST(APPEND gr_digital_sources
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_mpsk_receiver_cc.cc
@@ -67,6 +68,7 @@ INSTALL(TARGETS gnuradio-digital
# Install header files
########################################################################
INSTALL(FILES
+ digital_api.h
digital_binary_slicer_fb.h
digital_clock_recovery_mm_cc.h
digital_clock_recovery_mm_ff.h
@@ -77,6 +79,7 @@ INSTALL(FILES
digital_costas_loop_cc.h
digital_cma_equalizer_cc.h
digital_crc32.h
+ digital_fll_band_edge_cc.h
digital_lms_dd_equalizer_cc.h
digital_kurtotic_equalizer_cc.h
digital_metric_type.h
diff --git a/gr-digital/lib/Makefile.am b/gr-digital/lib/Makefile.am
index 6b14988ac0..4a9359fce2 100644
--- a/gr-digital/lib/Makefile.am
+++ b/gr-digital/lib/Makefile.am
@@ -36,6 +36,7 @@ grinclude_HEADERS = \
digital_costas_loop_cc.h \
digital_cma_equalizer_cc.h \
digital_crc32.h \
+ digital_fll_band_edge_cc.h \
digital_lms_dd_equalizer_cc.h \
digital_kurtotic_equalizer_cc.h \
digital_metric_type.h \
@@ -54,6 +55,7 @@ libgnuradio_digital_la_SOURCES = \
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_mpsk_receiver_cc.cc
diff --git a/gr-digital/lib/digital_clock_recovery_mm_cc.cc b/gr-digital/lib/digital_clock_recovery_mm_cc.cc
index 2984afd6cb..198eb4b890 100644
--- a/gr-digital/lib/digital_clock_recovery_mm_cc.cc
+++ b/gr-digital/lib/digital_clock_recovery_mm_cc.cc
@@ -52,7 +52,7 @@ digital_clock_recovery_mm_cc::digital_clock_recovery_mm_cc (float omega, float g
float omega_relative_limit)
: gr_block ("clock_recovery_mm_cc",
gr_make_io_signature (1, 1, sizeof (gr_complex)),
- gr_make_io_signature (1, 2, 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()),
@@ -121,7 +121,7 @@ digital_clock_recovery_mm_cc::general_work (int noutput_items,
{
const gr_complex *in = (const gr_complex *) input_items[0];
gr_complex *out = (gr_complex *) output_items[0];
- gr_complex *foptr = (gr_complex *) output_items[1];
+ float *foptr = (float *) output_items[1];
bool write_foptr = output_items.size() >= 2;
@@ -153,7 +153,7 @@ digital_clock_recovery_mm_cc::general_work (int noutput_items,
out[oo++] = d_p_0T;
// limit mm_val
- mm_val = gr_branchless_clip(mm_val,1.0);
+ 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
@@ -162,7 +162,7 @@ digital_clock_recovery_mm_cc::general_work (int noutput_items,
d_mu -= floor(d_mu);
// write the error signal to the second output
- foptr[oo-1] = gr_complex(d_mu,0);
+ foptr[oo-1] = mm_val;
if (ii < 0) // clamp it. This should only happen with bogus input
ii = 0;
diff --git a/gr-digital/lib/digital_constellation_receiver_cb.cc b/gr-digital/lib/digital_constellation_receiver_cb.cc
index 573c4e855e..e2b6bf1d80 100644
--- a/gr-digital/lib/digital_constellation_receiver_cb.cc
+++ b/gr-digital/lib/digital_constellation_receiver_cb.cc
@@ -40,28 +40,151 @@
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),
+ d_freq(0), d_max_freq(fmax), d_min_freq(fmin), d_phase(0),
d_constellation(constellation),
d_current_const_point(0)
{
if (d_constellation->dimensionality() != 1)
throw std::runtime_error ("This receiver only works with constellations of dimension 1.");
+
+ // Set the damping factor for a critically damped system
+ d_damping = sqrtf(2.0f)/2.0f;
+
+ // Set the bandwidth, which will then call update_gains()
+ set_loop_bandwidth(loop_bw);
+}
+
+
+/*******************************************************************
+ SET FUNCTIONS
+*******************************************************************/
+
+void
+digital_constellation_receiver_cb::set_loop_bandwidth(float bw)
+{
+ if(bw < 0) {
+ throw std::out_of_range ("digital_constellation_receiver_cb: invalid bandwidth. Must be >= 0.");
+ }
+
+ d_loop_bw = bw;
+ update_gains();
+}
+
+void
+digital_constellation_receiver_cb::set_damping_factor(float df)
+{
+ if(df < 0 || df > 1.0) {
+ throw std::out_of_range ("digital_constellation_receiver_cb: invalid damping factor. Must be in [0,1].");
+ }
+
+ d_damping = df;
+ update_gains();
+}
+
+void
+digital_constellation_receiver_cb::set_alpha(float alpha)
+{
+ if(alpha < 0 || alpha > 1.0) {
+ throw std::out_of_range ("digital_constellation_receiver_cb: invalid alpha. Must be in [0,1].");
+ }
+ d_alpha = alpha;
+}
+
+void
+digital_constellation_receiver_cb::set_beta(float beta)
+{
+ if(beta < 0 || beta > 1.0) {
+ throw std::out_of_range ("digital_constellation_receiver_cb: invalid beta. Must be in [0,1].");
+ }
+ d_beta = beta;
+}
+
+void
+digital_constellation_receiver_cb::set_frequency(float freq)
+{
+ if(freq > d_max_freq)
+ d_freq = d_min_freq;
+ else if(freq < d_min_freq)
+ d_freq = d_max_freq;
+ else
+ d_freq = freq;
+}
+
+void
+digital_constellation_receiver_cb::set_phase(float phase)
+{
+ d_phase = phase;
+ while(d_phase>M_TWOPI)
+ d_phase -= M_TWOPI;
+ while(d_phase<-M_TWOPI)
+ d_phase += M_TWOPI;
+}
+
+
+/*******************************************************************
+ GET FUNCTIONS
+*******************************************************************/
+
+
+float
+digital_constellation_receiver_cb::get_loop_bandwidth() const
+{
+ return d_loop_bw;
+}
+
+float
+digital_constellation_receiver_cb::get_damping_factor() const
+{
+ return d_damping;
+}
+
+float
+digital_constellation_receiver_cb::get_alpha() const
+{
+ return d_alpha;
+}
+
+float
+digital_constellation_receiver_cb::get_beta() const
+{
+ return d_beta;
+}
+
+float
+digital_constellation_receiver_cb::get_frequency() const
+{
+ return d_freq;
+}
+
+float
+digital_constellation_receiver_cb::get_phase() const
+{
+ return d_phase;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+void
+digital_constellation_receiver_cb::update_gains()
+{
+ float denom = (1.0 + 2.0*d_damping*d_loop_bw + d_loop_bw*d_loop_bw);
+ d_alpha = (4*d_damping*d_loop_bw) / denom;
+ d_beta = (4*d_loop_bw*d_loop_bw) / denom;
}
void
diff --git a/gr-digital/lib/digital_constellation_receiver_cb.h b/gr-digital/lib/digital_constellation_receiver_cb.h
index 36169d76b5..11eb96cda9 100644
--- a/gr-digital/lib/digital_constellation_receiver_cb.h
+++ b/gr-digital/lib/digital_constellation_receiver_cb.h
@@ -24,7 +24,6 @@
#define INCLUDED_DIGITAL_CONSTELLATION_RECEIVER_CB_H
#include <digital_api.h>
-#include <gruel/attributes.h>
#include <gr_block.h>
#include <digital_constellation.h>
#include <gr_complex.h>
@@ -37,8 +36,7 @@ typedef boost::shared_ptr<digital_constellation_receiver_cb> digital_constellati
// public constructor
DIGITAL_API digital_constellation_receiver_cb_sptr
digital_make_constellation_receiver_cb (digital_constellation_sptr constellation,
- float alpha, float beta,
- float fmin, float fmax);
+ float loop_bw, float fmin, float fmax);
/*!
* \brief This block takes care of receiving generic modulated signals through phase, frequency, and symbol
@@ -75,31 +73,124 @@ class DIGITAL_API digital_constellation_receiver_cb : public gr_block
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; }
+ /*******************************************************************
+ SET FUNCTIONS
+ *******************************************************************/
- //! (CL) Returns the current value of the frequency of the NCO in the Costas loop
- float freq() const { return d_freq; }
+ /*!
+ * \brief Set the loop bandwidth
+ *
+ * Set the loop filter's bandwidth to \p bw. This should be between
+ * 2*pi/200 and 2*pi/100 (in rads/samp). It must also be a positive
+ * number.
+ *
+ * When a new damping factor is set, the gains, alpha and beta, of the loop
+ * are recalculated by a call to update_gains().
+ *
+ * \param bw (float) new bandwidth
+ *
+ */
+ void set_loop_bandwidth(float bw);
- //! (CL) Returns the current value of the phase of the NCO in the Costal loop
- float phase() const { return d_phase; }
+ /*!
+ * \brief Set the loop damping factor
+ *
+ * Set the loop filter's damping factor to \p df. The damping factor
+ * should be sqrt(2)/2.0 for critically damped systems.
+ * Set it to anything else only if you know what you are doing. It must
+ * be a number between 0 and 1.
+ *
+ * When a new damping factor is set, the gains, alpha and beta, of the loop
+ * are recalculated by a call to update_gains().
+ *
+ * \param df (float) new damping factor
+ *
+ */
+ void set_damping_factor(float df);
- //! (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; }
+ /*!
+ * \brief Set the loop gain alpha
+ *
+ * Set's the loop filter's alpha gain parameter.
+ *
+ * This value should really only be set by adjusting the loop bandwidth
+ * and damping factor.
+ *
+ * \param alpha (float) new alpha gain
+ *
+ */
+ void set_alpha(float alpha);
- //! (CL) Sets the current value of the frequency of the NCO in the Costas loop
- void set_freq(float freq) { d_freq = freq; }
+ /*!
+ * \brief Set the loop gain beta
+ *
+ * Set's the loop filter's beta gain parameter.
+ *
+ * This value should really only be set by adjusting the loop bandwidth
+ * and damping factor.
+ *
+ * \param beta (float) new beta gain
+ *
+ */
+ void set_beta(float beta);
- //! (CL) Setss the current value of the phase of the NCO in the Costal loop
- void set_phase(float phase) { d_phase = phase; }
+ /*!
+ * \brief Set the phase/freq recovery loop's frequency.
+ *
+ * Set's the phase/freq recovery loop's frequency. While this is normally
+ * updated by the inner loop of the algorithm, it could be useful to
+ * manually initialize, set, or reset this under certain circumstances.
+ *
+ * \param freq (float) new frequency
+ *
+ */
+ void set_frequency(float freq);
+ /*!
+ * \brief Set the phase/freq recovery loop's phase.
+ *
+ * Set's the phase/freq recovery loop's phase. While this is normally
+ * updated by the inner loop of the algorithm, it could be useful to
+ * manually initialize, set, or reset this under certain circumstances.
+ *
+ * \param phase (float) new phase
+ *
+ */
+ void set_phase(float phase);
+
+ /*******************************************************************
+ GET FUNCTIONS
+ *******************************************************************/
+
+ /*!
+ * \brief Returns the loop bandwidth
+ */
+ float get_loop_bandwidth() const;
+
+ /*!
+ * \brief Returns the loop damping factor
+ */
+ float get_damping_factor() const;
+
+ /*!
+ * \brief Returns the loop gain alpha
+ */
+ float get_alpha() const;
+
+ /*!
+ * \brief Returns the loop gain beta
+ */
+ float get_beta() const;
+
+ /*!
+ * \brief Get the phase/freq recovery loop's frequency estimate
+ */
+ float get_frequency() const;
+
+ /*!
+ * \brief Get the phase/freq loop's phase estimate
+ */
+ float get_phase() const;
protected:
@@ -116,8 +207,7 @@ protected:
* work loop based on the value of M.
*/
digital_constellation_receiver_cb (digital_constellation_sptr constellation,
- float alpha, float beta,
- float fmin, float fmax);
+ float loop_bw, float fmin, float fmax);
void phase_error_tracking(float phase_error);
@@ -125,11 +215,14 @@ protected:
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;
+ float d_loop_bw;
+ float d_damping;
+ float d_alpha;
+ float d_beta;
+
digital_constellation_sptr d_constellation;
unsigned int d_current_const_point;
@@ -137,15 +230,23 @@ protected:
static const unsigned int DLLEN = 8;
//! delay line plus some length for overflow protection
- __GR_ATTR_ALIGNED(8) gr_complex d_dl[2*DLLEN];
+ gr_complex d_dl[2*DLLEN] __attribute__ ((aligned(8)));
//! index to delay line
unsigned int d_dl_idx;
+ /*! \brief update the system gains from the loop bandwidth and damping factor
+ *
+ * This function updates the system gains based on the loop
+ * bandwidth and damping factor of the system.
+ * These two factors can be set separately through their own
+ * set functions.
+ */
+ void update_gains();
+
friend DIGITAL_API 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);
};
#endif
diff --git a/gr-digital/lib/digital_costas_loop_cc.cc b/gr-digital/lib/digital_costas_loop_cc.cc
index 5d98bde4c4..370dc7e5c1 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
index 099fca3be2..c787263410 100644
--- a/gr-digital/lib/digital_costas_loop_cc.h
+++ b/gr-digital/lib/digital_costas_loop_cc.h
@@ -24,8 +24,8 @@
#ifndef INCLUDED_DIGITAL_COSTAS_LOOP_CC_H
#define INCLUDED_DIGITAL_COSTAS_LOOP_CC_H
-#include <digital_api.h>
#include <gr_sync_block.h>
+#include <gri_control_loop.h>
#include <stdexcept>
#include <fstream>
@@ -54,13 +54,15 @@
* \param min_freq the minimum frequency deviation (radians/sample) the loop can handle
* \param order the loop order, either 2 or 4
*/
+
+#include <digital_api.h>
+
class digital_costas_loop_cc;
typedef boost::shared_ptr<digital_costas_loop_cc> digital_costas_loop_cc_sptr;
DIGITAL_API 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);
@@ -74,34 +76,17 @@ digital_make_costas_loop_cc (float damping, float nat_freq,
*
* \p order must be 2 or 4.
*/
-class DIGITAL_API digital_costas_loop_cc : public gr_sync_block
+class DIGITAL_API digital_costas_loop_cc : public gr_sync_block, public gri_control_loop
{
friend DIGITAL_API 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);
- 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
+ digital_costas_loop_cc (float loop_bw, 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
@@ -125,27 +110,9 @@ class DIGITAL_API digital_costas_loop_cc : public gr_sync_block
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_fll_band_edge_cc.cc b/gr-digital/lib/digital_fll_band_edge_cc.cc
new file mode 100644
index 0000000000..70cb543519
--- /dev/null
+++ b/gr-digital/lib/digital_fll_band_edge_cc.cc
@@ -0,0 +1,390 @@
+/* -*- 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)),
+ 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;
+
+ // base this on the number of samples per symbol
+ d_max_freq = M_TWOPI * (2.0/samps_per_sym);
+ d_min_freq = -M_TWOPI * (2.0/samps_per_sym);
+
+ // Set the damping factor for a critically damped system
+ d_damping = sqrtf(2.0f)/2.0f;
+
+ // Set the bandwidth, which will then call update_gains()
+ set_loop_bandwidth(bandwidth);
+
+ // Build the band edge filters
+ design_filter(d_sps, d_rolloff, d_filter_size);
+
+ // Initialize loop values
+ d_freq = 0;
+ d_phase = 0;
+}
+
+digital_fll_band_edge_cc::~digital_fll_band_edge_cc ()
+{
+}
+
+
+/*******************************************************************
+ SET FUNCTIONS
+*******************************************************************/
+
+
+void
+digital_fll_band_edge_cc::set_loop_bandwidth(float bw)
+{
+ if(bw < 0) {
+ throw std::out_of_range ("digital_fll_band_edge_cc: invalid bandwidth. Must be >= 0.");
+ }
+
+ d_loop_bw = bw;
+ update_gains();
+}
+
+void
+digital_fll_band_edge_cc::set_damping_factor(float df)
+{
+ if(df < 0 || df > 1.0) {
+ throw std::out_of_range ("digital_fll_band_edge_cc: invalid damping factor. Must be in [0,1].");
+ }
+
+ d_damping = df;
+ update_gains();
+}
+
+void
+digital_fll_band_edge_cc::set_alpha(float alpha)
+{
+ if(alpha < 0 || alpha > 1.0) {
+ throw std::out_of_range ("digital_fll_band_edge_cc: invalid alpha. Must be in [0,1].");
+ }
+ d_alpha = alpha;
+}
+
+void
+digital_fll_band_edge_cc::set_beta(float beta)
+{
+ if(beta < 0 || beta > 1.0) {
+ throw std::out_of_range ("digital_fll_band_edge_cc: invalid beta. Must be in [0,1].");
+ }
+ d_beta = beta;
+}
+
+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);
+}
+
+void
+digital_fll_band_edge_cc::set_frequency(float freq)
+{
+ if(freq > d_max_freq)
+ d_freq = d_min_freq;
+ else if(freq < d_min_freq)
+ d_freq = d_max_freq;
+ else
+ d_freq = freq;
+}
+
+void
+digital_fll_band_edge_cc::set_phase(float phase)
+{
+ d_phase = phase;
+ while(d_phase>M_TWOPI)
+ d_phase -= M_TWOPI;
+ while(d_phase<-M_TWOPI)
+ d_phase += M_TWOPI;
+}
+
+
+/*******************************************************************
+ GET FUNCTIONS
+*******************************************************************/
+
+
+float
+digital_fll_band_edge_cc::get_loop_bandwidth() const
+{
+ return d_loop_bw;
+}
+
+float
+digital_fll_band_edge_cc::get_damping_factor() const
+{
+ return d_damping;
+}
+
+float
+digital_fll_band_edge_cc::get_alpha() const
+{
+ return d_alpha;
+}
+
+float
+digital_fll_band_edge_cc::get_beta() const
+{
+ return d_beta;
+}
+
+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;
+}
+
+float
+digital_fll_band_edge_cc::get_frequency() const
+{
+ return d_freq;
+}
+
+float
+digital_fll_band_edge_cc::get_phase() const
+{
+ return d_phase;
+}
+
+
+/*******************************************************************
+*******************************************************************/
+
+
+void
+digital_fll_band_edge_cc::update_gains()
+{
+ float denom = (1.0 + 2.0*d_damping*d_loop_bw + d_loop_bw*d_loop_bw);
+ d_alpha = (4*d_damping*d_loop_bw) / denom;
+ d_beta = (4*d_loop_bw*d_loop_bw) / denom;
+}
+
+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);
+
+ d_freq = d_freq + d_beta * error;
+ d_phase = d_phase + d_freq + d_alpha * error;
+
+ if(d_phase > M_PI)
+ d_phase -= M_TWOPI;
+ else if(d_phase < -M_PI)
+ d_phase += M_TWOPI;
+
+ if (d_freq > d_max_freq)
+ d_freq = d_max_freq;
+ else if (d_freq < d_min_freq)
+ d_freq = d_min_freq;
+
+ 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_fll_band_edge_cc.h b/gr-digital/lib/digital_fll_band_edge_cc.h
new file mode 100644
index 0000000000..c7a56a7c9c
--- /dev/null
+++ b/gr-digital/lib/digital_fll_band_edge_cc.h
@@ -0,0 +1,323 @@
+/* -*- 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.
+ */
+
+
+#ifndef INCLUDED_DIGITAL_FLL_BAND_EDGE_CC_H
+#define INCLUDED_DIGITAL_FLL_BAND_EDGE_CC_H
+
+#include <digital_api.h>
+#include <gr_sync_block.h>
+
+class digital_fll_band_edge_cc;
+typedef boost::shared_ptr<digital_fll_band_edge_cc> digital_fll_band_edge_cc_sptr;
+DIGITAL_API digital_fll_band_edge_cc_sptr digital_make_fll_band_edge_cc (float samps_per_sym,
+ float rolloff,
+ int filter_size,
+ float bandwidth);
+
+/*!
+ * \class digital_fll_band_edge_cc
+ * \brief Frequency Lock Loop using band-edge filters
+ *
+ * \ingroup general
+ *
+ * The frequency lock loop derives a band-edge filter that covers the upper and lower bandwidths
+ * of a digitally-modulated signal. The bandwidth range is determined by the excess bandwidth
+ * (e.g., rolloff factor) of the modulated signal. The placement in frequency of the band-edges
+ * is determined by the oversampling ratio (number of samples per symbol) and the excess bandwidth.
+ * The size of the filters should be fairly large so as to average over a number of symbols.
+ *
+ * The FLL works by filtering the upper and lower band edges into x_u(t) and x_l(t), respectively.
+ * These are combined to form cc(t) = x_u(t) + x_l(t) and ss(t) = x_u(t) - x_l(t). Combining
+ * these to form the signal e(t) = Re{cc(t) \\times ss(t)^*} (where ^* is the complex conjugate)
+ * provides an error signal at the DC term that is directly proportional to the carrier frequency.
+ * We then make a second-order loop using the error signal that is the running average of e(t).
+ *
+ * In practice, the above equation can be simplified by just comparing the absolute value squared
+ * of the output of both filters: abs(x_l(t))^2 - abs(x_u(t))^2 = norm(x_l(t)) - norm(x_u(t)).
+ *
+ * In theory, the band-edge filter is the derivative of the matched filter in frequency,
+ * (H_be(f) = \\frac{H(f)}{df}. In practice, this comes down to a quarter sine wave at the point
+ * of the matched filter's rolloff (if it's a raised-cosine, the derivative of a cosine is a sine).
+ * Extend this sine by another quarter wave to make a half wave around the band-edges is equivalent
+ * in time to the sum of two sinc functions. The baseband filter fot the band edges is therefore
+ * derived from this sum of sincs. The band edge filters are then just the baseband signal
+ * modulated to the correct place in frequency. All of these calculations are done in the
+ * 'design_filter' function.
+ *
+ * Note: We use FIR filters here because the filters have to have a flat phase response over the
+ * entire frequency range to allow their comparisons to be valid.
+ *
+ * It is very important that the band edge filters be the derivatives of the pulse shaping filter,
+ * and that they be linear phase. Otherwise, the variance of the error will be very large.
+ *
+ */
+
+class DIGITAL_API digital_fll_band_edge_cc : public gr_sync_block
+{
+ private:
+ /*!
+ * Build the FLL
+ * \param samps_per_sym (float) Number of samples per symbol of signal
+ * \param rolloff (float) Rolloff factor of signal
+ * \param filter_size (int) Size (in taps) of the filter
+ * \param bandwidth (float) Loop bandwidth
+ */
+ friend DIGITAL_API digital_fll_band_edge_cc_sptr digital_make_fll_band_edge_cc (float samps_per_sym,
+ float rolloff,
+ int filter_size,
+ float bandwidth);
+
+ float d_sps;
+ float d_rolloff;
+ int d_filter_size;
+ float d_max_freq;
+ float d_min_freq;
+
+ float d_loop_bw;
+ float d_damping;
+ float d_alpha;
+ float d_beta;
+
+ std::vector<gr_complex> d_taps_lower;
+ std::vector<gr_complex> d_taps_upper;
+ bool d_updated;
+
+ float d_freq;
+ float d_phase;
+
+ /*!
+ * Build the FLL
+ * \param samps_per_sym (float) number of samples per symbol
+ * \param rolloff (float) Rolloff (excess bandwidth) of signal filter
+ * \param filter_size (int) number of filter taps to generate
+ * \param bandwidth (float) Loop bandwidth
+ */
+ digital_fll_band_edge_cc(float samps_per_sym, float rolloff,
+ int filter_size, float bandwidth);
+
+ /*!
+ * \brief Update the gains, alpha and beta, of the loop filter.
+ */
+ void update_gains();
+
+ /*!
+ * Design the band-edge filter based on the number of samples per symbol,
+ * filter rolloff factor, and the filter size
+ *
+ * \param samps_per_sym (float) Number of samples per symbol of signal
+ * \param rolloff (float) Rolloff factor of signal
+ * \param filter_size (int) Size (in taps) of the filter
+ */
+ void design_filter(float samps_per_sym, float rolloff, int filter_size);
+
+public:
+ ~digital_fll_band_edge_cc ();
+
+ /*******************************************************************
+ SET FUNCTIONS
+ *******************************************************************/
+
+ /*!
+ * \brief Set the loop bandwidth
+ *
+ * Set the loop filter's bandwidth to \p bw. This should be between
+ * 2*pi/200 and 2*pi/100 (in rads/samp). It must also be a positive
+ * number.
+ *
+ * When a new damping factor is set, the gains, alpha and beta, of the loop
+ * are recalculated by a call to update_gains().
+ *
+ * \param bw (float) new bandwidth
+ *
+ */
+ void set_loop_bandwidth(float bw);
+
+ /*!
+ * \brief Set the loop damping factor
+ *
+ * Set the loop filter's damping factor to \p df. The damping factor
+ * should be sqrt(2)/2.0 for critically damped systems.
+ * Set it to anything else only if you know what you are doing. It must
+ * be a number between 0 and 1.
+ *
+ * When a new damping factor is set, the gains, alpha and beta, of the loop
+ * are recalculated by a call to update_gains().
+ *
+ * \param df (float) new damping factor
+ *
+ */
+ void set_damping_factor(float df);
+
+ /*!
+ * \brief Set the loop gain alpha
+ *
+ * Set's the loop filter's alpha gain parameter.
+ *
+ * This value should really only be set by adjusting the loop bandwidth
+ * and damping factor.
+ *
+ * \param alpha (float) new alpha gain
+ *
+ */
+ void set_alpha(float alpha);
+
+ /*!
+ * \brief Set the loop gain beta
+ *
+ * Set's the loop filter's beta gain parameter.
+ *
+ * This value should really only be set by adjusting the loop bandwidth
+ * and damping factor.
+ *
+ * \param beta (float) new beta gain
+ *
+ */
+ void set_beta(float beta);
+
+ /*!
+ * \brief Set the number of samples per symbol
+ *
+ * Set's the number of samples per symbol the system should use. This value
+ * is uesd to calculate the filter taps and will force a recalculation.
+ *
+ * \param sps (float) new samples per symbol
+ *
+ */
+ void set_samples_per_symbol(float sps);
+
+ /*!
+ * \brief Set the rolloff factor of the shaping filter
+ *
+ * This sets the rolloff factor that is used in the pulse shaping filter
+ * and is used to calculate the filter taps. Changing this will force a
+ * recalculation of the filter taps.
+ *
+ * This should be the same value that is used in the transmitter's pulse
+ * shaping filter. It must be between 0 and 1 and is usually between
+ * 0.2 and 0.5 (where 0.22 and 0.35 are commonly used values).
+ *
+ * \param rolloff (float) new shaping filter rolloff factor [0,1]
+ *
+ */
+ void set_rolloff(float rolloff);
+
+ /*!
+ * \brief Set the number of taps in the filter
+ *
+ * This sets the number of taps in the band-edge filters. Setting this will
+ * force a recalculation of the filter taps.
+ *
+ * This should be about the same number of taps used in the transmitter's
+ * shaping filter and also not very large. A large number of taps will
+ * result in a large delay between input and frequency estimation, and
+ * so will not be as accurate. Between 30 and 70 taps is usual.
+ *
+ * \param filter_size (float) number of taps in the filters
+ *
+ */
+ void set_filter_size(int filter_size);
+
+ /*!
+ * \brief Set the FLL's frequency.
+ *
+ * Set's the FLL's frequency. While this is normally updated by the
+ * inner loop of the algorithm, it could be useful to manually initialize,
+ * set, or reset this under certain circumstances.
+ *
+ * \param freq (float) new frequency
+ *
+ */
+ void set_frequency(float freq);
+
+ /*!
+ * \brief Set the FLL's phase.
+ *
+ * Set's the FLL's phase. While this is normally updated by the
+ * inner loop of the algorithm, it could be useful to manually initialize,
+ * set, or reset this under certain circumstances.
+ *
+ * \param phase (float) new phase
+ *
+ */
+ void set_phase(float phase);
+
+ /*******************************************************************
+ GET FUNCTIONS
+ *******************************************************************/
+
+ /*!
+ * \brief Returns the loop bandwidth
+ */
+ float get_loop_bandwidth() const;
+
+ /*!
+ * \brief Returns the loop damping factor
+ */
+ float get_damping_factor() const;
+
+ /*!
+ * \brief Returns the loop gain alpha
+ */
+ float get_alpha() const;
+
+ /*!
+ * \brief Returns the loop gain beta
+ */
+ float get_beta() const;
+
+ /*!
+ * \brief Returns the number of sampler per symbol used for the filter
+ */
+ float get_samples_per_symbol() const;
+
+ /*!
+ * \brief Returns the rolloff factor used for the filter
+ */
+ float get_rolloff() const;
+
+ /*!
+ * \brief Returns the number of taps of the filter
+ */
+ int get_filter_size() const;
+
+ /*!
+ * \brief Get the FLL's frequency estimate
+ */
+ float get_frequency() const;
+
+ /*!
+ * \brief Get the FLL's phase estimate
+ */
+ float get_phase() const;
+
+ /*!
+ * Print the taps to screen.
+ */
+ void print_taps();
+
+ int work (int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+};
+
+#endif
diff --git a/gr-digital/python/Makefile.am b/gr-digital/python/Makefile.am
index 87752e9ae0..6c61002f16 100644
--- a/gr-digital/python/Makefile.am
+++ b/gr-digital/python/Makefile.am
@@ -41,6 +41,7 @@ noinst_PYTHON = \
qa_correlate_access_code.py \
qa_costas_loop_cc.py \
qa_crc32.py \
+ qa_fll_band_edge.py \
qa_lms_equalizer.py \
qa_mpsk_receiver.py
diff --git a/gr-digital/python/bpsk.py b/gr-digital/python/bpsk.py
index 51de3ce084..58a8289a56 100644
--- a/gr-digital/python/bpsk.py
+++ b/gr-digital/python/bpsk.py
@@ -34,7 +34,7 @@ import modulation_utils2
# Default number of points in constellation.
_def_constellation_points = 2
# Whether differential coding is used.
-_def_differential = True
+_def_differential = False
# /////////////////////////////////////////////////////////////////////////////
# BPSK constellation
@@ -52,7 +52,7 @@ def bpsk_constellation(m=_def_constellation_points):
class bpsk_mod(generic_mod):
def __init__(self, constellation_points=_def_constellation_points,
- *args, **kwargs):
+ differential=False, *args, **kwargs):
"""
Hierarchical block for RRC-filtered BPSK modulation.
@@ -67,8 +67,9 @@ class bpsk_mod(generic_mod):
constellation = digital_swig.constellation_bpsk()
if constellation_points != 2:
raise ValueError('Number of constellation points must be 2 for BPSK.')
- super(bpsk_mod, self).__init__(constellation, *args, **kwargs)
-
+ super(bpsk_mod, self).__init__(constellation=constellation,
+ differential=differential, *args, **kwargs)
+
# /////////////////////////////////////////////////////////////////////////////
# BPSK demodulator
#
@@ -77,7 +78,7 @@ class bpsk_mod(generic_mod):
class bpsk_demod(generic_demod):
def __init__(self, constellation_points=_def_constellation_points,
- *args, **kwargs):
+ differential=False, *args, **kwargs):
"""
Hierarchical block for RRC-filtered BPSK modulation.
@@ -92,7 +93,72 @@ class bpsk_demod(generic_demod):
constellation = digital_swig.constellation_bpsk()
if constellation_points != 2:
raise ValueError('Number of constellation points must be 2 for BPSK.')
- super(bpsk_demod, self).__init__(constellation, *args, **kwargs)
+ super(bpsk_demod, self).__init__(constellation=constellation,
+ differential=differential, *args, **kwargs)
+
+
+
+# /////////////////////////////////////////////////////////////////////////////
+# DBPSK constellation
+# /////////////////////////////////////////////////////////////////////////////
+
+def dbpsk_constellation(m=_def_constellation_points):
+ if m != _def_constellation_points:
+ raise ValueError("DBPSK can only have 2 constellation points.")
+ return digital_swig.constellation_dbpsk()
+
+# /////////////////////////////////////////////////////////////////////////////
+# DBPSK modulator
+# /////////////////////////////////////////////////////////////////////////////
+
+class dbpsk_mod(generic_mod):
+
+ def __init__(self, constellation_points=_def_constellation_points,
+ differential=True, *args, **kwargs):
+
+ """
+ Hierarchical block for RRC-filtered DBPSK modulation.
+
+ The input is a byte stream (unsigned char) and the
+ output is the complex modulated signal at baseband.
+
+ See generic_mod block for list of parameters.
+ """
+
+ constellation_points = _def_constellation_points
+ constellation = digital_swig.constellation_bpsk()
+ if constellation_points != 2:
+ raise ValueError('Number of constellation points must be 2 for DBPSK.')
+ super(dbpsk_mod, self).__init__(constellation=constellation,
+ differential=True,
+ *args, **kwargs)
+
+# /////////////////////////////////////////////////////////////////////////////
+# DBPSK demodulator
+#
+# /////////////////////////////////////////////////////////////////////////////
+
+class dbpsk_demod(generic_demod):
+
+ def __init__(self, constellation_points=_def_constellation_points,
+ differential=True, *args, **kwargs):
+
+ """
+ Hierarchical block for RRC-filtered DBPSK modulation.
+
+ The input is a byte stream (unsigned char) and the
+ output is the complex modulated signal at baseband.
+
+ See generic_demod block for list of parameters.
+ """
+
+ constellation_points = _def_constellation_points
+ constellation = digital_swig.constellation_bpsk()
+ if constellation_points != 2:
+ raise ValueError('Number of constellation points must be 2 for DBPSK.')
+ super(dbpsk_demod, self).__init__(constellation=constellation,
+ differential=True,
+ *args, **kwargs)
#
# Add these to the mod/demod registry
@@ -100,3 +166,6 @@ class bpsk_demod(generic_demod):
modulation_utils2.add_type_1_mod('bpsk', bpsk_mod)
modulation_utils2.add_type_1_demod('bpsk', bpsk_demod)
modulation_utils2.add_type_1_constellation('bpsk', bpsk_constellation)
+modulation_utils2.add_type_1_mod('dbpsk', dbpsk_mod)
+modulation_utils2.add_type_1_demod('dbpsk', dbpsk_demod)
+modulation_utils2.add_type_1_constellation('dbpsk', dbpsk_constellation)
diff --git a/gr-digital/python/generic_mod_demod.py b/gr-digital/python/generic_mod_demod.py
index 1b8603fea6..da8e2cfd99 100644
--- a/gr-digital/python/generic_mod_demod.py
+++ b/gr-digital/python/generic_mod_demod.py
@@ -29,6 +29,7 @@ from gnuradio import gr
from modulation_utils2 import extract_kwargs_from_options_for_class
from utils import mod_codes
import digital_swig
+import math
# default values (used in __init__ and add_options)
_def_samples_per_symbol = 2
@@ -37,17 +38,16 @@ _def_verbose = False
_def_log = False
# Frequency correction
-_def_freq_alpha = 0.010
+_def_freq_bw = 2*math.pi/100.0
# Symbol timing recovery
-_def_timing_alpha = 0.100
-_def_timing_beta = 0.010
+_def_timing_bw = 2*math.pi/100.0
_def_timing_max_dev = 1.5
# Fine frequency / Phase correction
-_def_phase_alpha = 0.1
+_def_phase_bw = 2*math.pi/100.0
# Number of points in constellation
_def_constellation_points = 16
# Whether differential coding is used.
-_def_differential = True
+_def_differential = False
def add_common_options(parser):
"""
@@ -55,10 +55,12 @@ def add_common_options(parser):
"""
parser.add_option("-p", "--constellation-points", type="int", default=_def_constellation_points,
help="set the number of constellation points (must be a power of 2 (power of 4 for QAM) [default=%default]")
- parser.add_option("", "--differential", action="store_true", dest="differential", default=True,
- help="use differential encoding [default=%default]")
- parser.add_option("", "--not-differential", action="store_false", dest="differential",
+ parser.add_option("", "--non-differential", action="store_true",
+ dest="differential", default=False,
help="do not use differential encoding [default=%default]")
+ parser.add_option("", "--differential", action="store_false",
+ dest="differential",
+ help="use differential encoding [default=False]")
parser.add_option("", "--mod-code", type="choice", choices=mod_codes.codes,
default=mod_codes.NO_CODE,
help="Select modulation code from: %s [default=%%default]"
@@ -77,6 +79,7 @@ class generic_mod(gr.hier_block2):
differential=_def_differential,
samples_per_symbol=_def_samples_per_symbol,
excess_bw=_def_excess_bw,
+ gray_coded=True,
verbose=_def_verbose,
log=_def_log):
"""
@@ -88,9 +91,11 @@ class generic_mod(gr.hier_block2):
@param constellation: determines the modulation type
@type constellation: gnuradio.digital.gr_constellation
@param samples_per_symbol: samples per baud >= 2
- @type samples_per_symbol: integer
+ @type samples_per_symbol: float
@param excess_bw: Root-raised cosine filter excess bandwidth
@type excess_bw: float
+ @param gray_coded: turn gray coding on/off
+ @type gray_coded: bool
@param verbose: Print information about modulator?
@type verbose: bool
@param log: Log modulation data to files?
@@ -180,17 +185,17 @@ class generic_mod(gr.hier_block2):
def _setup_logging(self):
print "Modulation logging turned on."
self.connect(self.bytes2chunks,
- gr.file_sink(gr.sizeof_char, "tx_bytes2chunks.dat"))
+ gr.file_sink(gr.sizeof_char, "tx_bytes2chunks.8b"))
if self._constellation.apply_pre_diff_code():
self.connect(self.symbol_mapper,
- gr.file_sink(gr.sizeof_char, "tx_symbol_mapper.dat"))
+ gr.file_sink(gr.sizeof_char, "tx_symbol_mapper.8b"))
if self._differential:
self.connect(self.diffenc,
- gr.file_sink(gr.sizeof_char, "tx_diffenc.dat"))
+ gr.file_sink(gr.sizeof_char, "tx_diffenc.8b"))
self.connect(self.chunks2symbols,
- gr.file_sink(gr.sizeof_gr_complex, "tx_chunks2symbols.dat"))
+ gr.file_sink(gr.sizeof_gr_complex, "tx_chunks2symbols.32fc"))
self.connect(self.rrc_filter,
- gr.file_sink(gr.sizeof_gr_complex, "tx_rrc_filter.dat"))
+ gr.file_sink(gr.sizeof_gr_complex, "tx_rrc_filter.32fc"))
# /////////////////////////////////////////////////////////////////////////////
@@ -206,10 +211,9 @@ class generic_demod(gr.hier_block2):
samples_per_symbol=_def_samples_per_symbol,
differential=_def_differential,
excess_bw=_def_excess_bw,
- freq_alpha=_def_freq_alpha,
- timing_alpha=_def_timing_alpha,
- timing_max_dev=_def_timing_max_dev,
- phase_alpha=_def_phase_alpha,
+ freq_bw=_def_freq_bw,
+ timing_bw=_def_timing_bw,
+ phase_bw=_def_phase_bw,
verbose=_def_verbose,
log=_def_log):
"""
@@ -224,14 +228,12 @@ class generic_demod(gr.hier_block2):
@type samples_per_symbol: float
@param excess_bw: Root-raised cosine filter excess bandwidth
@type excess_bw: float
- @param freq_alpha: loop filter gain for frequency recovery
- @type freq_alpha: float
- @param timing_alpha: loop alpha gain for timing recovery
- @type timing_alpha: float
- @param timing_max_dev: timing loop maximum rate deviations
- @type timing_max_dev: float
- @param phase_alpha: loop filter gain in phase loop
- @type phase_alphas: float
+ @param freq_bw: loop filter lock-in bandwidth
+ @type freq_bw: float
+ @param timing_bw: timing recoery loop lock-in bandwidth
+ @type timing_bw: float
+ @param phase_bw: phase recovery loop bandwidth
+ @type phase_bw: float
@param verbose: Print information about modulator?
@type verbose: bool
@param debug: Print modualtion data to files?
@@ -245,12 +247,10 @@ class generic_demod(gr.hier_block2):
self._constellation = constellation.base()
self._samples_per_symbol = samples_per_symbol
self._excess_bw = excess_bw
- self._phase_alpha = phase_alpha
- self._freq_alpha = freq_alpha
- self._freq_beta = 0.10*self._freq_alpha
- self._timing_alpha = timing_alpha
- self._timing_beta = _def_timing_beta
- self._timing_max_dev=timing_max_dev
+ self._phase_bw = phase_bw
+ self._freq_bw = freq_bw
+ self._timing_bw = timing_bw
+ self._timing_max_dev= _def_timing_max_dev
self._differential = differential
if self._samples_per_symbol < 2:
@@ -258,32 +258,27 @@ class generic_demod(gr.hier_block2):
arity = pow(2,self.bits_per_symbol())
+ nfilts = 32
+ ntaps = 11 * int(self._samples_per_symbol*nfilts)
+
# Automatic gain control
self.agc = gr.agc2_cc(0.6e-1, 1e-3, 1, 1, 100)
# Frequency correction
- self.freq_recov = gr.fll_band_edge_cc(self._samples_per_symbol, self._excess_bw,
- 11*int(self._samples_per_symbol),
- self._freq_alpha, self._freq_beta)
+ self.freq_recov = digital_swig.fll_band_edge_cc(self._samples_per_symbol, self._excess_bw,
+ ntaps, self._freq_bw)
# symbol timing recovery with RRC data filter
- nfilts = 32
- ntaps = 11 * int(self._samples_per_symbol*nfilts)
- taps = gr.firdes.root_raised_cosine(nfilts, nfilts,
- 1.0/float(self._samples_per_symbol),
- self._excess_bw, ntaps)
+ taps = gr.firdes.root_raised_cosine(nfilts, nfilts*self._samples_per_symbol,
+ 1.0, self._excess_bw, ntaps)
self.time_recov = gr.pfb_clock_sync_ccf(self._samples_per_symbol,
- self._timing_alpha,
- taps, nfilts, nfilts/2, self._timing_max_dev)
- self.time_recov.set_beta(self._timing_beta)
+ self._timing_bw, taps,
+ nfilts, nfilts//2, self._timing_max_dev)
- self._phase_beta = 0.25 * self._phase_alpha * self._phase_alpha
fmin = -0.25
fmax = 0.25
-
self.receiver = digital_swig.constellation_receiver_cb(
- self._constellation,
- self._phase_alpha, self._phase_beta,
+ self._constellation, self._phase_bw,
fmin, fmax)
# Do differential decoding based on phase change of symbols
@@ -322,49 +317,46 @@ class generic_demod(gr.hier_block2):
print "\nDemodulator:"
print "bits per symbol: %d" % self.bits_per_symbol()
print "RRC roll-off factor: %.2f" % self._excess_bw
- print "FLL gain: %.2e" % self._freq_alpha
- print "Timing alpha gain: %.2e" % self._timing_alpha
- print "Timing beta gain: %.2e" % self._timing_beta
- print "Timing max dev: %.2f" % self._timing_max_dev
- print "Phase track alpha: %.2e" % self._phase_alpha
- print "Phase track beta: %.2e" % self._phase_beta
+ print "FLL bandwidth: %.2e" % self._freq_bw
+ print "Timing bandwidth: %.2e" % self._timing_bw
+ print "Phase bandwidth: %.2e" % self._phase_bw
def _setup_logging(self):
print "Modulation logging turned on."
self.connect(self.agc,
- gr.file_sink(gr.sizeof_gr_complex, "rx_agc.dat"))
+ gr.file_sink(gr.sizeof_gr_complex, "rx_agc.32fc"))
self.connect((self.freq_recov, 0),
- gr.file_sink(gr.sizeof_gr_complex, "rx_freq_recov.dat"))
+ gr.file_sink(gr.sizeof_gr_complex, "rx_freq_recov.32fc"))
self.connect((self.freq_recov, 1),
- gr.file_sink(gr.sizeof_float, "rx_freq_recov_freq.dat"))
+ gr.file_sink(gr.sizeof_float, "rx_freq_recov_freq.32f"))
self.connect((self.freq_recov, 2),
- gr.file_sink(gr.sizeof_float, "rx_freq_recov_phase.dat"))
+ gr.file_sink(gr.sizeof_float, "rx_freq_recov_phase.32f"))
self.connect((self.freq_recov, 3),
- gr.file_sink(gr.sizeof_gr_complex, "rx_freq_recov_error.dat"))
+ gr.file_sink(gr.sizeof_float, "rx_freq_recov_error.32f"))
self.connect((self.time_recov, 0),
- gr.file_sink(gr.sizeof_gr_complex, "rx_time_recov.dat"))
+ gr.file_sink(gr.sizeof_gr_complex, "rx_time_recov.32fc"))
self.connect((self.time_recov, 1),
- gr.file_sink(gr.sizeof_float, "rx_time_recov_error.dat"))
+ gr.file_sink(gr.sizeof_float, "rx_time_recov_error.32f"))
self.connect((self.time_recov, 2),
- gr.file_sink(gr.sizeof_float, "rx_time_recov_rate.dat"))
+ gr.file_sink(gr.sizeof_float, "rx_time_recov_rate.32f"))
self.connect((self.time_recov, 3),
- gr.file_sink(gr.sizeof_float, "rx_time_recov_phase.dat"))
+ gr.file_sink(gr.sizeof_float, "rx_time_recov_phase.32f"))
self.connect((self.receiver, 0),
- gr.file_sink(gr.sizeof_char, "rx_receiver.dat"))
+ gr.file_sink(gr.sizeof_char, "rx_receiver.8b"))
self.connect((self.receiver, 1),
- gr.file_sink(gr.sizeof_float, "rx_receiver_error.dat"))
+ gr.file_sink(gr.sizeof_float, "rx_receiver_error.32f"))
self.connect((self.receiver, 2),
- gr.file_sink(gr.sizeof_float, "rx_receiver_phase.dat"))
+ gr.file_sink(gr.sizeof_float, "rx_receiver_phase.32f"))
self.connect((self.receiver, 3),
- gr.file_sink(gr.sizeof_float, "rx_receiver_freq.dat"))
+ gr.file_sink(gr.sizeof_float, "rx_receiver_freq.32f"))
if self._differential:
self.connect(self.diffdec,
- gr.file_sink(gr.sizeof_char, "rx_diffdec.dat"))
+ gr.file_sink(gr.sizeof_char, "rx_diffdec.8b"))
if self._constellation.apply_pre_diff_code():
self.connect(self.symbol_mapper,
- gr.file_sink(gr.sizeof_char, "rx_symbol_mapper.dat"))
+ gr.file_sink(gr.sizeof_char, "rx_symbol_mapper.8b"))
self.connect(self.unpack,
- gr.file_sink(gr.sizeof_char, "rx_unpack.dat"))
+ gr.file_sink(gr.sizeof_char, "rx_unpack.8b"))
def add_options(parser):
"""
@@ -373,16 +365,12 @@ class generic_demod(gr.hier_block2):
# Add options shared with modulator.
add_common_options(parser)
# Add options specific to demodulator.
- parser.add_option("", "--freq-alpha", type="float", default=_def_freq_alpha,
- help="set frequency lock loop alpha gain value [default=%default]")
- parser.add_option("", "--phase-alpha", type="float", default=_def_phase_alpha,
- help="set phase tracking loop alpha value [default=%default]")
- parser.add_option("", "--timing-alpha", type="float", default=_def_timing_alpha,
- help="set timing symbol sync loop gain alpha value [default=%default]")
- parser.add_option("", "--timing-beta", type="float", default=_def_timing_beta,
- help="set timing symbol sync loop gain beta value [default=%default]")
- parser.add_option("", "--timing-max-dev", type="float", default=_def_timing_max_dev,
- help="set timing symbol sync loop maximum deviation [default=%default]")
+ parser.add_option("", "--freq-bw", type="float", default=_def_freq_bw,
+ help="set frequency lock loop lock-in bandwidth [default=%default]")
+ parser.add_option("", "--phase-bw", type="float", default=_def_phase_bw,
+ help="set phase tracking loop lock-in bandwidth [default=%default]")
+ parser.add_option("", "--timing-bw", type="float", default=_def_timing_bw,
+ help="set timing symbol sync loop gain lock-in bandwidth [default=%default]")
add_options=staticmethod(add_options)
def extract_kwargs_from_options(cls, options):
diff --git a/gr-digital/python/modulation_utils2.py b/gr-digital/python/modulation_utils2.py
index f30055f4ac..cb3a9812d4 100644
--- a/gr-digital/python/modulation_utils2.py
+++ b/gr-digital/python/modulation_utils2.py
@@ -80,6 +80,7 @@ def extract_kwargs_from_options(function, excluded_args, options):
@param options: result of command argument parsing
@type options: optparse.Values
"""
+
# Try this in C++ ;)
args, varargs, varkw, defaults = inspect.getargspec(function)
d = {}
diff --git a/gr-digital/python/qa_constellation_receiver.py b/gr-digital/python/qa_constellation_receiver.py
index cb4a0c10e7..79dded8ba3 100755
--- a/gr-digital/python/qa_constellation_receiver.py
+++ b/gr-digital/python/qa_constellation_receiver.py
@@ -37,7 +37,7 @@ random.seed(1239)
# TESTING PARAMETERS
# The number of symbols to test with.
# We need this many to let the frequency recovery block converge.
-DATA_LENGTH = 200000
+DATA_LENGTH = 10000
# Test fails if fraction of output that is correct is less than this.
REQ_CORRECT = 0.8
diff --git a/gr-digital/python/qa_costas_loop_cc.py b/gr-digital/python/qa_costas_loop_cc.py
index 3f5eaa141b..124159dbaa 100755
--- a/gr-digital/python/qa_costas_loop_cc.py
+++ b/gr-digital/python/qa_costas_loop_cc.py
@@ -34,10 +34,9 @@ class test_costas_loop_cc(gr_unittest.TestCase):
def test01 (self):
# test basic functionality by setting all gains to 0
- damp = 0.0
natfreq = 0.0
order = 2
- self.test = digital_swig.costas_loop_cc(damp, natfreq, order)
+ self.test = digital_swig.costas_loop_cc(natfreq, order)
data = 100*[complex(1,0),]
self.src = gr.vector_source_c(data, False)
@@ -52,10 +51,9 @@ class test_costas_loop_cc(gr_unittest.TestCase):
def test02 (self):
# Make sure it doesn't diverge given perfect data
- damp = 0.4
natfreq = 0.25
order = 2
- self.test = digital_swig.costas_loop_cc(damp, natfreq, order)
+ self.test = digital_swig.costas_loop_cc(natfreq, order)
data = [complex(2*random.randint(0,1)-1, 0) for i in xrange(100)]
self.src = gr.vector_source_c(data, False)
@@ -71,10 +69,9 @@ class test_costas_loop_cc(gr_unittest.TestCase):
def test03 (self):
# BPSK Convergence test with static rotation
- damp = 0.4
natfreq = 0.25
order = 2
- self.test = digital_swig.costas_loop_cc(damp, natfreq, order)
+ self.test = digital_swig.costas_loop_cc(natfreq, order)
rot = cmath.exp(0.2j) # some small rotation
data = [complex(2*random.randint(0,1)-1, 0) for i in xrange(100)]
@@ -97,10 +94,9 @@ class test_costas_loop_cc(gr_unittest.TestCase):
def test04 (self):
# QPSK Convergence test with static rotation
- damp = 0.4
natfreq = 0.25
order = 4
- self.test = digital_swig.costas_loop_cc(damp, natfreq, order)
+ self.test = digital_swig.costas_loop_cc(natfreq, order)
rot = cmath.exp(0.2j) # some small rotation
data = [complex(2*random.randint(0,1)-1, 2*random.randint(0,1)-1)
@@ -124,10 +120,9 @@ class test_costas_loop_cc(gr_unittest.TestCase):
def test05 (self):
# 8PSK Convergence test with static rotation
- damp = 0.5
- natfreq = 0.5
+ natfreq = 0.25
order = 8
- self.test = digital_swig.costas_loop_cc(damp, natfreq, order)
+ self.test = digital_swig.costas_loop_cc(natfreq, order)
rot = cmath.exp(-cmath.pi/8.0j) # rotate to match Costas rotation
const = psk2.psk_constellation(order)
diff --git a/gr-digital/python/qa_fll_band_edge.py b/gr-digital/python/qa_fll_band_edge.py
new file mode 100644
index 0000000000..088eb2b680
--- /dev/null
+++ b/gr-digital/python/qa_fll_band_edge.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env python
+#
+# Copyright 2011 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+from gnuradio import gr, gr_unittest
+import digital_swig
+import random, math
+
+class test_fll_band_edge_cc(gr_unittest.TestCase):
+
+ def setUp (self):
+ self.tb = gr.top_block ()
+
+ def tearDown (self):
+ self.tb = None
+
+ def test01 (self):
+ sps = 4
+ rolloff = 0.35
+ bw = 2*math.pi/100.0
+ ntaps = 45
+
+ # Create pulse shape filter
+ rrc_taps = gr.firdes.root_raised_cosine(
+ sps, sps, 1.0, rolloff, ntaps)
+
+ # The frequency offset to correct
+ foffset = 0.2 / (2.0*math.pi)
+
+ # Create a set of 1's and -1's, pulse shape and interpolate to sps
+ data = [2.0*random.randint(0, 2) - 1.0 for i in xrange(200)]
+ self.src = gr.vector_source_c(data, False)
+ self.rrc = gr.interp_fir_filter_ccf(sps, rrc_taps)
+
+ # Mix symbols with a complex sinusoid to spin them
+ self.nco = gr.sig_source_c(1, gr.GR_SIN_WAVE, foffset, 1)
+ self.mix = gr.multiply_cc()
+
+ # FLL will despin the symbols to an arbitrary phase
+ self.fll = digital_swig.fll_band_edge_cc(sps, rolloff, ntaps, bw)
+
+ # Create sinks for all outputs of the FLL
+ # we will only care about the freq and error outputs
+ self.vsnk_frq = gr.vector_sink_f()
+ self.nsnk_fll = gr.null_sink(gr.sizeof_gr_complex)
+ self.nsnk_phs = gr.null_sink(gr.sizeof_float)
+ self.nsnk_err = gr.null_sink(gr.sizeof_float)
+
+ # Connect the blocks
+ self.tb.connect(self.nco, (self.mix,1))
+ self.tb.connect(self.src, self.rrc, (self.mix,0))
+ self.tb.connect(self.mix, self.fll, self.nsnk_fll)
+ self.tb.connect((self.fll,1), self.vsnk_frq)
+ self.tb.connect((self.fll,2), self.nsnk_phs)
+ self.tb.connect((self.fll,3), self.nsnk_err)
+ self.tb.run()
+
+ N = 700
+ dst_data = self.vsnk_frq.data()[N:]
+
+ expected_result = len(dst_data)* [-0.20,]
+ self.assertComplexTuplesAlmostEqual (expected_result, dst_data, 4)
+
+if __name__ == '__main__':
+ gr_unittest.run(test_fll_band_edge_cc, "test_fll_band_edge_cc.xml")
diff --git a/gr-digital/python/qam.py b/gr-digital/python/qam.py
index f29291ce89..a5a2e6c2cf 100644
--- a/gr-digital/python/qam.py
+++ b/gr-digital/python/qam.py
@@ -113,7 +113,7 @@ def make_differential_constellation(m, gray_coded):
return const_map
-def make_not_differential_constellation(m, gray_coded):
+def make_non_differential_constellation(m, gray_coded):
side = int(pow(m, 0.5))
if (not isinstance(m, int) or m < 4 or not is_power_of_four(m)):
raise ValueError("m must be a power of 4 integer.")
@@ -158,7 +158,7 @@ def qam_constellation(constellation_points=_def_constellation_points,
if differential:
points = make_differential_constellation(constellation_points, gray_coded)
else:
- points = make_not_differential_constellation(constellation_points, gray_coded)
+ points = make_non_differential_constellation(constellation_points, gray_coded)
side = int(sqrt(constellation_points))
width = 2.0/(side-1)
# No pre-diff code
diff --git a/gr-digital/python/qpsk.py b/gr-digital/python/qpsk.py
index 91e8b196f4..76e5df2701 100644
--- a/gr-digital/python/qpsk.py
+++ b/gr-digital/python/qpsk.py
@@ -23,7 +23,6 @@
QPSK modulation.
Demodulation is not included since the generic_mod_demod
-doesn't work for non-differential encodings.
"""
from gnuradio import gr
@@ -33,8 +32,7 @@ import modulation_utils2
# Default number of points in constellation.
_def_constellation_points = 4
-# Whether differential coding is used.
-_def_differential = False
+# Whether gray coding is used.
_def_gray_coded = True
# /////////////////////////////////////////////////////////////////////////////
@@ -53,7 +51,6 @@ def qpsk_constellation(m=_def_constellation_points):
class qpsk_mod(generic_mod):
def __init__(self, constellation_points=_def_constellation_points,
- differential=_def_differential,
gray_coded=_def_gray_coded,
*args, **kwargs):
@@ -70,9 +67,11 @@ class qpsk_mod(generic_mod):
constellation = digital_swig.constellation_qpsk()
if constellation_points != 4:
raise ValueError("QPSK can only have 4 constellation points.")
- if differential or not gray_coded:
- raise ValueError("This QPSK mod/demod works only for gray-coded, non-differential.")
- super(qpsk_mod, self).__init__(constellation, differential, gray_coded, *args, **kwargs)
+ if not gray_coded:
+ raise ValueError("This QPSK mod/demod works only for gray-coded constellations.")
+ super(qpsk_mod, self).__init__(constellation=constellation,
+ gray_coded=gray_coded,
+ *args, **kwargs)
# /////////////////////////////////////////////////////////////////////////////
@@ -98,8 +97,8 @@ class qpsk_demod(generic_demod):
constellation = digital_swig.constellation_qpsk()
if constellation_points != 4:
raise ValueError('Number of constellation points must be 4 for QPSK.')
- super(qpsk_demod, self).__init__(constellation, *args, **kwargs)
-
+ super(qpsk_demod, self).__init__(constellation=constellation,
+ *args, **kwargs)
#
# Add these to the mod/demod registry
diff --git a/gr-digital/swig/CMakeLists.txt b/gr-digital/swig/CMakeLists.txt
index 037c0a3f19..b62c024e06 100644
--- a/gr-digital/swig/CMakeLists.txt
+++ b/gr-digital/swig/CMakeLists.txt
@@ -50,6 +50,7 @@ INSTALL(
digital_costas_loop_cc.i
digital_cma_equalizer_cc.i
digital_crc32.i
+ digital_fll_band_edge_cc.i
digital_lms_dd_equalizer_cc.i
digital_kurtotic_equalizer_cc.i
digital_mpsk_receiver_cc.i
diff --git a/gr-digital/swig/Makefile.am b/gr-digital/swig/Makefile.am
index 08fb140acd..c0d28c24c6 100644
--- a/gr-digital/swig/Makefile.am
+++ b/gr-digital/swig/Makefile.am
@@ -68,6 +68,7 @@ digital_swig_swiginclude_headers = \
digital_costas_loop_cc.i \
digital_cma_equalizer_cc.i \
digital_crc32.i \
+ digital_fll_band_edge_cc.i \
digital_lms_dd_equalizer_cc.i \
digital_kurtotic_equalizer_cc.i \
digital_mpsk_receiver_cc.i
diff --git a/gr-digital/swig/digital_constellation_receiver_cb.i b/gr-digital/swig/digital_constellation_receiver_cb.i
index ad17ef3713..e4be5f39f1 100644
--- a/gr-digital/swig/digital_constellation_receiver_cb.i
+++ b/gr-digital/swig/digital_constellation_receiver_cb.i
@@ -26,22 +26,25 @@ GR_SWIG_BLOCK_MAGIC(digital,constellation_receiver_cb);
digital_constellation_receiver_cb_sptr
digital_make_constellation_receiver_cb (digital_constellation_sptr constellation,
- float alpha, float beta,
- float fmin, float fmax);
+ float loop_bw, float fmin, float fmax);
class digital_constellation_receiver_cb : public gr_block
{
private:
digital_constellation_receiver_cb (digital_contellation_sptr constellation,
- float alpha, float beta,
- float fmin, float fmax);
+ float loop_bw, float fmin, float fmax);
public:
- float alpha() const { return d_alpha; }
- float beta() const { return d_beta; }
- float freq() const { return d_freq; }
- float phase() const { return d_phase; }
- void set_alpha(float alpha) { d_alpha = alpha; }
- void set_beta(float beta) { d_beta = beta; }
- void set_freq(float freq) { d_freq = freq; }
- void set_phase(float phase) { d_phase = phase; }
+ void set_loop_bandwidth(float bw);
+ void set_damping_factor(float df);
+ void set_alpha(float alpha);
+ void set_beta(float beta);
+ void set_frequency(float freq);
+ void set_phase(float phase);
+
+ float get_loop_bandwidth() const;
+ float get_damping_factor() const;
+ float get_alpha() const;
+ float get_beta() const;
+ float get_frequency() const;
+ float get_phase() const;
};
diff --git a/gr-digital/swig/digital_costas_loop_cc.i b/gr-digital/swig/digital_costas_loop_cc.i
index 6d3d009f8a..ab09200a0a 100644
--- a/gr-digital/swig/digital_costas_loop_cc.i
+++ b/gr-digital/swig/digital_costas_loop_cc.i
@@ -23,22 +23,11 @@
GR_SWIG_BLOCK_MAGIC(digital,costas_loop_cc);
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);
-
-class digital_costas_loop_cc : public gr_sync_block
+class digital_costas_loop_cc : public gr_sync_block, public gri_control_loop
{
private:
- digital_costas_loop_cc (float damping, float nat_freq,
- int order);
-
- public:
- float alpha();
- float beta();
- float freq();
-
- void set_natural_freq(float w);
- void set_damping_factor(float eta);
+ digital_costas_loop_cc (float loop_bw, int order);
};
diff --git a/gr-digital/swig/digital_fll_band_edge_cc.i b/gr-digital/swig/digital_fll_band_edge_cc.i
new file mode 100644
index 0000000000..f022bc7e18
--- /dev/null
+++ b/gr-digital/swig/digital_fll_band_edge_cc.i
@@ -0,0 +1,60 @@
+/* -*- 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.
+ */
+
+GR_SWIG_BLOCK_MAGIC(digital,fll_band_edge_cc);
+
+digital_fll_band_edge_cc_sptr digital_make_fll_band_edge_cc (float samps_per_sym,
+ float rolloff,
+ int filter_size,
+ float bandwidth);
+
+class digital_fll_band_edge_cc : public gr_sync_block
+{
+ private:
+ digital_fll_band_edge_cc (float samps_per_sym, float rolloff,
+ int filter_size, float bandwidth);
+
+ public:
+ ~digital_fll_band_edge_cc ();
+
+ void set_loop_bandwidth(float bw);
+ void set_damping_factor(float df);
+ void set_alpha(float alpha);
+ void set_beta(float beta);
+ void set_samples_per_symbol(float sps);
+ void set_rolloff(float rolloff);
+ void set_filter_size(int filter_size);
+ void set_frequency(float freq);
+ void set_phase(float phase);
+
+ float get_loop_bandwidth() const;
+ float get_damping_factor() const;
+ float get_alpha() const;
+ float get_beta() const;
+ float get_samples_per_symbol() const;
+ float get_rolloff() const;
+ int get_filter_size() const;
+ float get_frequency() const;
+ float get_phase() const;
+
+ void print_taps();
+};
diff --git a/gr-digital/swig/digital_swig.i b/gr-digital/swig/digital_swig.i
index cfaadcaea4..0328ca2fcc 100644
--- a/gr-digital/swig/digital_swig.i
+++ b/gr-digital/swig/digital_swig.i
@@ -21,6 +21,8 @@
%include "gnuradio.i"
+%include <gri_control_loop.i>
+
%{
#include "digital_binary_slicer_fb.h"
#include "digital_clock_recovery_mm_cc.h"
@@ -32,6 +34,7 @@
#include "digital_correlate_access_code_bb.h"
#include "digital_costas_loop_cc.h"
#include "digital_crc32.h"
+#include "digital_fll_band_edge_cc.h"
#include "digital_kurtotic_equalizer_cc.h"
#include "digital_lms_dd_equalizer_cc.h"
#include "digital_mpsk_receiver_cc.h"
@@ -47,6 +50,7 @@
%include "digital_correlate_access_code_bb.i"
%include "digital_costas_loop_cc.i"
%include "digital_crc32.i"
+%include "digital_fll_band_edge_cc.i"
%include "digital_kurtotic_equalizer_cc.i"
%include "digital_lms_dd_equalizer_cc.i"
%include "digital_mpsk_receiver_cc.i"
diff --git a/gr-utils/src/python/gr_plot_const.py b/gr-utils/src/python/gr_plot_const.py
index 5dd08c9a0d..0c52899b25 100755
--- a/gr-utils/src/python/gr_plot_const.py
+++ b/gr-utils/src/python/gr_plot_const.py
@@ -85,16 +85,23 @@ class draw_constellation:
except MemoryError:
print "End of File"
else:
- self.reals = scipy.array([r.real for r in iq])
- self.imags = scipy.array([i.imag for i in iq])
+ # retesting length here as newer version of scipy does not throw a MemoryError, just
+ # returns a zero-length array
+ if(len(iq) > 0):
+ self.reals = scipy.array([r.real for r in iq])
+ self.imags = scipy.array([i.imag for i in iq])
+
+ self.time = scipy.array([i*(1/self.sample_rate) for i in range(len(self.reals))])
+ return Tr
+ else:
+ print "End of File"
+ return False
- self.time = scipy.array([i*(1/self.sample_rate) for i in range(len(self.reals))])
-
def make_plots(self):
# if specified on the command-line, set file pointer
self.hfile.seek(self.sizeof_data*self.start, 1)
- self.get_data()
+ r = self.get_data()
# Subplot for real and imaginary parts of signal
self.sp_iq = self.fig.add_subplot(2,1,1, position=[0.075, 0.2, 0.4, 0.6])
@@ -175,8 +182,9 @@ class draw_constellation:
self.step_forward()
def step_forward(self):
- self.get_data()
- self.update_plots()
+ r = self.get_data()
+ if(r):
+ self.update_plots()
def step_backward(self):
# Step back in file position
@@ -184,8 +192,9 @@ class draw_constellation:
self.hfile.seek(-2*self.sizeof_data*self.block_length, 1)
else:
self.hfile.seek(-self.hfile.tell(),1)
- self.get_data()
- self.update_plots()
+ r = self.get_data()
+ if(r):
+ self.update_plots()
def mouse_button_callback(self, event):