diff options
Diffstat (limited to 'gr-digital')
-rw-r--r-- | gr-digital/lib/digital_costas_loop_cc.cc | 138 | ||||
-rw-r--r-- | gr-digital/lib/digital_costas_loop_cc.h | 148 | ||||
-rwxr-xr-x | gr-digital/python/qa_costas_loop_cc.py | 17 | ||||
-rw-r--r-- | gr-digital/swig/digital_costas_loop_cc.i | 23 |
4 files changed, 271 insertions, 55 deletions
diff --git a/gr-digital/lib/digital_costas_loop_cc.cc b/gr-digital/lib/digital_costas_loop_cc.cc index 5d98bde4c..be914486f 100644 --- a/gr-digital/lib/digital_costas_loop_cc.cc +++ b/gr-digital/lib/digital_costas_loop_cc.cc @@ -33,28 +33,29 @@ #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), + d_max_freq(1.0), d_min_freq(-1.0), + d_loop_bw(loop_bw), d_order(order), d_phase_detector(NULL) { - // initialize gains from the natural freq and damping factors - update_gains(); + // 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 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; @@ -72,6 +73,10 @@ digital_costas_loop_cc::digital_costas_loop_cc (float damping, float nat_freq, throw std::invalid_argument("order must be 2, 4, or 8"); break; } + + // Initialize loop values + d_freq = 0; + d_phase = 0; } float @@ -115,25 +120,124 @@ digital_costas_loop_cc::phase_detector_2(gr_complex sample) const return (sample.real()*sample.imag()); } +/******************************************************************* + SET FUNCTIONS +*******************************************************************/ + void -digital_costas_loop_cc::set_natural_freq(float w) +digital_costas_loop_cc::set_loop_bandwidth(float bw) { - d_nat_freq = w; + if(bw < 0) { + throw std::out_of_range ("digital_costas_loop_cc: invalid bandwidth. Must be >= 0."); + } + + d_loop_bw = bw; update_gains(); } void -digital_costas_loop_cc::set_damping_factor(float eta) +digital_costas_loop_cc::set_damping_factor(float df) { - d_damping = eta; + if(df < 0 || df > 1.0) { + throw std::out_of_range ("digital_costas_loop_cc: invalid damping factor. Must be in [0,1]."); + } + + d_damping = df; update_gains(); } void +digital_costas_loop_cc::set_alpha(float alpha) +{ + if(alpha < 0 || alpha > 1.0) { + throw std::out_of_range ("digital_costas_loop_cc: invalid alpha. Must be in [0,1]."); + } + d_alpha = alpha; +} + +void +digital_costas_loop_cc::set_beta(float beta) +{ + if(beta < 0 || beta > 1.0) { + throw std::out_of_range ("digital_costas_loop_cc: invalid beta. Must be in [0,1]."); + } + d_beta = beta; +} + +void +digital_costas_loop_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_costas_loop_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_costas_loop_cc::get_loop_bandwidth() const +{ + return d_loop_bw; +} + +float +digital_costas_loop_cc::get_damping_factor() const +{ + return d_damping; +} + +float +digital_costas_loop_cc::get_alpha() const +{ + return d_alpha; +} + +float +digital_costas_loop_cc::get_beta() const +{ + return d_beta; +} + +float +digital_costas_loop_cc::get_frequency() const +{ + return d_freq; +} + +float +digital_costas_loop_cc::get_phase() const +{ + return d_phase; +} + + +/******************************************************************* +*******************************************************************/ + + +void digital_costas_loop_cc::update_gains() { - d_beta = d_nat_freq*d_nat_freq; - d_alpha = 2*d_damping*d_nat_freq; + 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; } int diff --git a/gr-digital/lib/digital_costas_loop_cc.h b/gr-digital/lib/digital_costas_loop_cc.h index 9c112d328..530a2e2a3 100644 --- a/gr-digital/lib/digital_costas_loop_cc.h +++ b/gr-digital/lib/digital_costas_loop_cc.h @@ -58,8 +58,7 @@ typedef boost::shared_ptr<digital_costas_loop_cc> digital_costas_loop_cc_sptr; digital_costas_loop_cc_sptr -digital_make_costas_loop_cc (float damping, float nat_freq, - int order +digital_make_costas_loop_cc (float loop_bw, int order ) throw (std::invalid_argument); @@ -76,19 +75,24 @@ digital_make_costas_loop_cc (float damping, float nat_freq, class digital_costas_loop_cc : public gr_sync_block { friend digital_costas_loop_cc_sptr - digital_make_costas_loop_cc (float damping, float nat_freq, - int order + 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; + float d_max_freq; + float d_min_freq; int d_order; - digital_costas_loop_cc (float damping, float nat_freq, - int order + float d_loop_bw; + float d_damping; + float d_alpha; + float d_beta; + + float d_phase; + float d_freq; + + 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 @@ -124,18 +128,126 @@ class digital_costas_loop_cc : public gr_sync_block public: - void set_natural_freq(float w); - void set_damping_factor(float eta); + /******************************************************************* + 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 get the first order gain - * + /*! + * \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 + * */ - float alpha() const { return d_alpha; } - - /*! \brief get the second order gain - * + 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 + * */ - float beta() const { return d_beta; } + 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; + int work (int noutput_items, gr_vector_const_void_star &input_items, diff --git a/gr-digital/python/qa_costas_loop_cc.py b/gr-digital/python/qa_costas_loop_cc.py index 3f5eaa141..124159dba 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/swig/digital_costas_loop_cc.i b/gr-digital/swig/digital_costas_loop_cc.i index 6d3d009f8..f6e276562 100644 --- a/gr-digital/swig/digital_costas_loop_cc.i +++ b/gr-digital/swig/digital_costas_loop_cc.i @@ -23,22 +23,27 @@ 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 { private: - digital_costas_loop_cc (float damping, float nat_freq, - int order); + digital_costas_loop_cc (float loop_bw, int order); public: - float alpha(); - float beta(); - float freq(); + 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); - void set_natural_freq(float w); - void set_damping_factor(float eta); + 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; }; |