From e1b4e60823c2b938500932b0868d88698e48d525 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Sat, 30 Jul 2011 11:28:47 -0400 Subject: core: made significant improvements in FLL algorithm. Now converges very nicely. --- .../src/lib/general/gr_fll_band_edge_cc.cc | 259 ++++++++++++++++----- .../src/lib/general/gr_fll_band_edge_cc.h | 195 ++++++++++++++-- .../src/lib/general/gr_fll_band_edge_cc.i | 23 +- 3 files changed, 384 insertions(+), 93 deletions(-) (limited to 'gnuradio-core/src/lib/general') 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 index c32398e6d..65e273e8a 100644 --- a/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.cc +++ b/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.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 * @@ -25,9 +25,6 @@ #endif #include -#include -#include -#include #include #include #include @@ -45,110 +42,246 @@ float sinc(float 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) +gr_fll_band_edge_cc_sptr +gr_make_fll_band_edge_cc (float samps_per_sym, float rolloff, + int filter_size, float bandwidth) { return gnuradio::get_initial_sptr(new gr_fll_band_edge_cc (samps_per_sym, rolloff, - filter_size, gain_alpha, gain_beta)); + filter_size, bandwidth)); } -static int ios[] = {sizeof(gr_complex), sizeof(float), sizeof(float), sizeof(gr_complex)}; +static int ios[] = {sizeof(gr_complex), sizeof(float), sizeof(float), sizeof(float)}; static std::vector 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) + 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_alpha(alpha), d_beta(beta), d_updated (false) + d_updated (false) { + // Initialize samples per symbol + if(samps_per_sym <= 0) { + throw std::out_of_range ("gr_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 ("gr_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 ("gr_fll_band_edge_cc: invalid filter size. Must be > 0."); + } + d_filter_size = filter_size; + + // Initialize loop bandwidth + if(bandwidth < 0) { + throw std::out_of_range ("gr_fll_band_edge_cc: invalid bandwidth. Must be >= 0."); + } + d_loop_bw = bandwidth; + // 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 = sqrt(2.0)/2.0; + + // 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; +} - set_alpha(alpha); +gr_fll_band_edge_cc::~gr_fll_band_edge_cc () +{ +} - design_filter(samps_per_sym, rolloff, filter_size); +void +gr_fll_band_edge_cc::set_loop_bandwidth(float bw) +{ + if(bw < 0) { + throw std::out_of_range ("gr_fll_band_edge_cc: invalid bandwidth. Must be >= 0."); + } + + d_loop_bw = bw; + update_gains(); } -gr_fll_band_edge_cc::~gr_fll_band_edge_cc () +void +gr_fll_band_edge_cc::set_damping_factor(float df) { - delete d_filter_lower; - delete d_filter_upper; + if(df < 0 || df > 1.0) { + throw std::out_of_range ("gr_fll_band_edge_cc: invalid damping factor. Must be in [0,1]."); + } + + d_damping = df; + update_gains(); } + 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); +gr_fll_band_edge_cc::set_alpha(float alpha) +{ + if(alpha < 0 || alpha > 1.0) { + throw std::out_of_range ("gr_fll_band_edge_cc: invalid alpha. Must be in [0,1]."); + } d_alpha = alpha; } +void +gr_fll_band_edge_cc::set_beta(float beta) +{ + if(beta < 0 || beta > 1.0) { + throw std::out_of_range ("gr_fll_band_edge_cc: invalid beta. Must be in [0,1]."); + } + d_beta = beta; +} + +void +gr_fll_band_edge_cc::set_samples_per_symbol(float sps) +{ + if(sps <= 0) { + throw std::out_of_range ("gr_fll_band_edge_cc: invalid number of sps. Must be > 0."); + } + d_sps = sps; + design_filter(d_sps, d_rolloff, d_filter_size); +} + +void +gr_fll_band_edge_cc::set_rolloff(float rolloff) +{ + if(rolloff < 0 || rolloff > 1.0) { + throw std::out_of_range ("gr_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 +gr_fll_band_edge_cc::set_filter_size(int filter_size) +{ + if(filter_size <= 0) { + throw std::out_of_range ("gr_fll_band_edge_cc: invalid filter size. Must be > 0."); + } + d_filter_size = filter_size; + design_filter(d_sps, d_rolloff, d_filter_size); +} + +float +gr_fll_band_edge_cc::get_loop_bandwidth() +{ + return d_loop_bw; +} + +float +gr_fll_band_edge_cc::get_damping_factor() +{ + return d_damping; +} + +float +gr_fll_band_edge_cc::get_alpha() +{ + return d_alpha; +} + +float +gr_fll_band_edge_cc::get_beta() +{ + return d_beta; +} + +float +gr_fll_band_edge_cc::get_samples_per_symbol() +{ + return d_sps; +} + +float +gr_fll_band_edge_cc::get_rolloff() +{ + return d_rolloff; +} + +int +gr_fll_band_edge_cc:: get_filter_size() +{ + return d_filter_size; +} + +void +gr_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 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; + + // Create the baseband filter by adding two sincs together std::vector 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; - std::vector taps_lower; - std::vector taps_upper; - for(unsigned int i = 0; i < bb_taps.size(); i++) { + 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(-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); + 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; } - - std::vector 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 taps_upper = d_filter_upper->get_taps(); - std::vector 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()); + 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 < taps_lower.size(); i++) { - printf(" %.4e + %.4ej,", taps_lower[i].real(), taps_lower[i].imag()); + 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"); } @@ -163,11 +296,11 @@ gr_fll_band_edge_cc::work (int noutput_items, float *frq = NULL; float *phs = NULL; - gr_complex *err = NULL; - if(output_items.size() > 2) { + float *err = NULL; + if(output_items.size() == 4) { frq = (float *) output_items[1]; phs = (float *) output_items[2]; - err = (gr_complex *) output_items[3]; + err = (float *) output_items[3]; } if (d_updated) { @@ -176,21 +309,24 @@ gr_fll_band_edge_cc::work (int noutput_items, } int i; + float error; 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 + 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 * d_error; - d_phase = d_phase + d_freq + d_alpha * d_error; + 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; @@ -202,13 +338,12 @@ gr_fll_band_edge_cc::work (int noutput_items, else if (d_freq < d_min_freq) d_freq = d_min_freq; - if(output_items.size() > 2) { + if(output_items.size() == 4) { frq[i] = d_freq; phs[i] = d_phase; - err[i] = d_error; + err[i] = 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 index db060793e..dba5e6e26 100644 --- a/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.h +++ b/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2009 Free Software Foundation, Inc. + * Copyright 2009,2011 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -29,10 +29,7 @@ class gr_fll_band_edge_cc; typedef boost::shared_ptr gr_fll_band_edge_cc_sptr; 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; + int filter_size, float bandwidth); /*! * \class gr_fll_band_edge_cc @@ -52,6 +49,9 @@ class gri_fft_complex; * 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). @@ -63,6 +63,10 @@ class gri_fft_complex; * * 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 gr_fll_band_edge_cc : public gr_sync_block @@ -73,58 +77,199 @@ class gr_fll_band_edge_cc : public gr_sync_block * \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 + * \param bandwdith (float) Loop bandwidth */ friend 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); + int filter_size, float bandwidth); - float d_alpha; - float d_beta; + float d_sps; + float d_rolloff; + int d_filter_size; float d_max_freq; float d_min_freq; - gr_fir_ccc* d_filter_upper; - gr_fir_ccc* d_filter_lower; + float d_loop_bw; + float d_damping; + float d_alpha; + float d_beta; + + std::vector d_taps_lower; + std::vector d_taps_upper; bool d_updated; - float d_error; + float d_freq; - float d_phase; + 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 + * \param bandwidth (float) Loop bandwidth */ gr_fll_band_edge_cc(float samps_per_sym, float rolloff, - int filter_size, float alpha, float beta); - -public: - ~gr_fll_band_edge_cc (); + 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: + ~gr_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); + /*! - * Set the alpha gainvalue - * \param alpha (float) new gain value + * \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); /*! - * Set the beta gain value - * \param beta (float) new gain value + * \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); + + /******************************************************************* + GET FUNCTIONS + *******************************************************************/ + + /*! + * \brief Returns the loop bandwidth + */ + float get_loop_bandwidth(); + + /*! + * \brief Returns the loop damping factor + */ + float get_damping_factor(); + + /*! + * \brief Returns the loop gain alpha + */ + float get_alpha(); + + /*! + * \brief Returns the loop gain beta + */ + float get_beta(); + + /*! + * \brief Returns the number of sampler per symbol used for the filter + */ + float get_samples_per_symbol(); + + /*! + * \brief Returns the rolloff factor used for the filter + */ + float get_rolloff(); + + /*! + * \brief Returns the number of taps of the filter */ - void set_beta(float beta) { d_beta = beta; } + int get_filter_size(); /*! * Print the taps to screen. 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 index c9c792c8a..3617dc395 100644 --- a/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.i +++ b/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.i @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2009 Free Software Foundation, Inc. + * Copyright 2009,2011 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -23,19 +23,30 @@ 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); + int filter_size, float bandwidth); 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); + int filter_size, float bandwidth); 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 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); + float get_loop_bandwidth(); + float get_damping_factor(); + float get_alpha(); + float get_beta(); + float get_samples_per_symbol(); + float get_rolloff(); + int get_filter_size(); void print_taps(); }; -- cgit From 0eb52f1683ea6c5869e1c8141a3f756e1dc8997a Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Sat, 30 Jul 2011 12:40:03 -0400 Subject: digital: moved fll_band_edge out of gnruadio-core. --- gnuradio-core/src/lib/general/Makefile.am | 3 - gnuradio-core/src/lib/general/general.i | 2 - .../src/lib/general/gr_fll_band_edge_cc.cc | 349 --------------------- .../src/lib/general/gr_fll_band_edge_cc.h | 284 ----------------- .../src/lib/general/gr_fll_band_edge_cc.i | 52 --- 5 files changed, 690 deletions(-) delete mode 100644 gnuradio-core/src/lib/general/gr_fll_band_edge_cc.cc delete mode 100644 gnuradio-core/src/lib/general/gr_fll_band_edge_cc.h delete mode 100644 gnuradio-core/src/lib/general/gr_fll_band_edge_cc.i (limited to 'gnuradio-core/src/lib/general') diff --git a/gnuradio-core/src/lib/general/Makefile.am b/gnuradio-core/src/lib/general/Makefile.am index e63d8930b..29f9d8d44 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 \ @@ -220,7 +219,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 \ @@ -382,7 +380,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 \ diff --git a/gnuradio-core/src/lib/general/general.i b/gnuradio-core/src/lib/general/general.i index c43622400..08b5ad98c 100644 --- a/gnuradio-core/src/lib/general/general.i +++ b/gnuradio-core/src/lib/general/general.i @@ -131,7 +131,6 @@ #include #include #include -#include #include #include #include @@ -248,7 +247,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 65e273e8a..000000000 --- a/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.cc +++ /dev/null @@ -1,349 +0,0 @@ -/* -*- 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 -#include -#include -#include -#include - -#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 bandwidth) -{ - return gnuradio::get_initial_sptr(new gr_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 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 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 ("gr_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 ("gr_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 ("gr_fll_band_edge_cc: invalid filter size. Must be > 0."); - } - d_filter_size = filter_size; - - // Initialize loop bandwidth - if(bandwidth < 0) { - throw std::out_of_range ("gr_fll_band_edge_cc: invalid bandwidth. Must be >= 0."); - } - d_loop_bw = bandwidth; - - // 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 = sqrt(2.0)/2.0; - - // 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; -} - -gr_fll_band_edge_cc::~gr_fll_band_edge_cc () -{ -} - -void -gr_fll_band_edge_cc::set_loop_bandwidth(float bw) -{ - if(bw < 0) { - throw std::out_of_range ("gr_fll_band_edge_cc: invalid bandwidth. Must be >= 0."); - } - - d_loop_bw = bw; - update_gains(); -} - -void -gr_fll_band_edge_cc::set_damping_factor(float df) -{ - if(df < 0 || df > 1.0) { - throw std::out_of_range ("gr_fll_band_edge_cc: invalid damping factor. Must be in [0,1]."); - } - - d_damping = df; - update_gains(); -} - - -void -gr_fll_band_edge_cc::set_alpha(float alpha) -{ - if(alpha < 0 || alpha > 1.0) { - throw std::out_of_range ("gr_fll_band_edge_cc: invalid alpha. Must be in [0,1]."); - } - d_alpha = alpha; -} - -void -gr_fll_band_edge_cc::set_beta(float beta) -{ - if(beta < 0 || beta > 1.0) { - throw std::out_of_range ("gr_fll_band_edge_cc: invalid beta. Must be in [0,1]."); - } - d_beta = beta; -} - -void -gr_fll_band_edge_cc::set_samples_per_symbol(float sps) -{ - if(sps <= 0) { - throw std::out_of_range ("gr_fll_band_edge_cc: invalid number of sps. Must be > 0."); - } - d_sps = sps; - design_filter(d_sps, d_rolloff, d_filter_size); -} - -void -gr_fll_band_edge_cc::set_rolloff(float rolloff) -{ - if(rolloff < 0 || rolloff > 1.0) { - throw std::out_of_range ("gr_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 -gr_fll_band_edge_cc::set_filter_size(int filter_size) -{ - if(filter_size <= 0) { - throw std::out_of_range ("gr_fll_band_edge_cc: invalid filter size. Must be > 0."); - } - d_filter_size = filter_size; - design_filter(d_sps, d_rolloff, d_filter_size); -} - -float -gr_fll_band_edge_cc::get_loop_bandwidth() -{ - return d_loop_bw; -} - -float -gr_fll_band_edge_cc::get_damping_factor() -{ - return d_damping; -} - -float -gr_fll_band_edge_cc::get_alpha() -{ - return d_alpha; -} - -float -gr_fll_band_edge_cc::get_beta() -{ - return d_beta; -} - -float -gr_fll_band_edge_cc::get_samples_per_symbol() -{ - return d_sps; -} - -float -gr_fll_band_edge_cc::get_rolloff() -{ - return d_rolloff; -} - -int -gr_fll_band_edge_cc:: get_filter_size() -{ - return d_filter_size; -} - -void -gr_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 -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; - - // Create the baseband filter by adding two sincs together - std::vector 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 -gr_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 -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; - 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/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 dba5e6e26..000000000 --- a/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.h +++ /dev/null @@ -1,284 +0,0 @@ -/* -*- 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_GR_FLL_BAND_EDGE_CC_H -#define INCLUDED_GR_FLL_BAND_EDGE_CC_H - -#include - -class gr_fll_band_edge_cc; -typedef boost::shared_ptr gr_fll_band_edge_cc_sptr; -gr_fll_band_edge_cc_sptr gr_make_fll_band_edge_cc (float samps_per_sym, float rolloff, - int filter_size, float bandwidth); - -/*! - * \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 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 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 bandwdith (float) Loop bandwidth - */ - friend gr_fll_band_edge_cc_sptr gr_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 d_taps_lower; - std::vector 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 - */ - gr_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: - ~gr_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); - - /******************************************************************* - GET FUNCTIONS - *******************************************************************/ - - /*! - * \brief Returns the loop bandwidth - */ - float get_loop_bandwidth(); - - /*! - * \brief Returns the loop damping factor - */ - float get_damping_factor(); - - /*! - * \brief Returns the loop gain alpha - */ - float get_alpha(); - - /*! - * \brief Returns the loop gain beta - */ - float get_beta(); - - /*! - * \brief Returns the number of sampler per symbol used for the filter - */ - float get_samples_per_symbol(); - - /*! - * \brief Returns the rolloff factor used for the filter - */ - float get_rolloff(); - - /*! - * \brief Returns the number of taps of the filter - */ - int get_filter_size(); - - /*! - * 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 3617dc395..000000000 --- a/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.i +++ /dev/null @@ -1,52 +0,0 @@ -/* -*- 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(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 bandwidth); - -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 bandwidth); - - public: - ~gr_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); - float get_loop_bandwidth(); - float get_damping_factor(); - float get_alpha(); - float get_beta(); - float get_samples_per_symbol(); - float get_rolloff(); - int get_filter_size(); - void print_taps(); -}; -- cgit From 6bd1605b265b5dff8cbdca0b20b0c5685c752ec7 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Sun, 14 Aug 2011 22:05:48 -0400 Subject: Adding a control_loop class that takes care of setting the loop gains and the standard loop advance function. This should be used as a parent class of any block that uses a 2nd order control loop (like the PLL, clock recovery, etc blocks). --- gnuradio-core/src/lib/general/Makefile.am | 3 + gnuradio-core/src/lib/general/general.i | 2 + gnuradio-core/src/lib/general/gri_control_loop.cc | 183 ++++++++++++++++++++ gnuradio-core/src/lib/general/gri_control_loop.h | 201 ++++++++++++++++++++++ gnuradio-core/src/lib/general/gri_control_loop.i | 57 ++++++ 5 files changed, 446 insertions(+) create mode 100644 gnuradio-core/src/lib/general/gri_control_loop.cc create mode 100644 gnuradio-core/src/lib/general/gri_control_loop.h create mode 100644 gnuradio-core/src/lib/general/gri_control_loop.i (limited to 'gnuradio-core/src/lib/general') diff --git a/gnuradio-core/src/lib/general/Makefile.am b/gnuradio-core/src/lib/general/Makefile.am index 29f9d8d44..f210cee39 100644 --- a/gnuradio-core/src/lib/general/Makefile.am +++ b/gnuradio-core/src/lib/general/Makefile.am @@ -153,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 \ @@ -312,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 \ @@ -460,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 08b5ad98c..f9adff3fa 100644 --- a/gnuradio-core/src/lib/general/general.i +++ b/gnuradio-core/src/lib/general/general.i @@ -22,6 +22,7 @@ %{ +#include #include #include #include @@ -138,6 +139,7 @@ #include %} +%include "gri_control_loop.i" %include "gr_nop.i" %include "gr_null_sink.i" %include "gr_null_source.i" 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 000000000..d84b47493 --- /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 +#include +#include + +#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 000000000..a85625bbd --- /dev/null +++ b/gnuradio-core/src/lib/general/gri_control_loop.h @@ -0,0 +1,201 @@ +/* -*- 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 + +class 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 000000000..67f8838cb --- /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; +}; -- cgit From 7e47bddafc6b27c623137c6d76f460e608952fcc Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Sun, 14 Aug 2011 22:07:43 -0400 Subject: Convering the PLL refout block to use the gri_control_loop class to take care of the internal loop. The error and what to do with the phase and freq are left to this block. It also changes the interface so that the PLL's gains are determined by the loop bandwidth. --- gnuradio-core/src/lib/general/gr_pll_refout_cc.cc | 23 ++++++++--------------- gnuradio-core/src/lib/general/gr_pll_refout_cc.h | 20 +++++++++----------- gnuradio-core/src/lib/general/gr_pll_refout_cc.i | 10 +++++----- 3 files changed, 22 insertions(+), 31 deletions(-) (limited to 'gnuradio-core/src/lib/general') 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 8a7fbf88b..8968cd3f1 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 3263c957f..226ca8f9e 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,18 +20,17 @@ * Boston, MA 02110-1301, USA. */ - - #ifndef INCLUDED_GR_PLL_REFOUT_CC_H #define INCLUDED_GR_PLL_REFOUT_CC_H #include +#include class gr_pll_refout_cc; typedef boost::shared_ptr gr_pll_refout_cc_sptr; -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); /*! * \brief Implements a PLL which locks to the input frequency and outputs a carrier * \ingroup sync_blk @@ -47,20 +46,19 @@ 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_pll_refout_cc : public gr_sync_block +class gr_pll_refout_cc : public gr_sync_block, public gri_control_loop { - friend gr_pll_refout_cc_sptr gr_make_pll_refout_cc (float alpha, float beta, - float max_freq, float min_freq); + friend 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 026a684ed..834ea1e36 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); }; -- cgit