summaryrefslogtreecommitdiff
path: root/gr-digital
diff options
context:
space:
mode:
authorTom Rondeau <trondeau@vt.edu>2011-07-30 15:59:44 -0400
committerTom Rondeau <trondeau@vt.edu>2011-07-30 15:59:44 -0400
commita6fa43a9075e5123c741090622c80598a7e84c3a (patch)
tree062d89de86bbee5837d5a0d28ce8977200a87a33 /gr-digital
parent6876cd276ed2e3f74161b2301f33941218fc7882 (diff)
digital: updated Costas loop again. The damping factor is now set by default and is no longer part of the constructor. All variables are exposed in gets and sets, though, for any purposes.
Diffstat (limited to 'gr-digital')
-rw-r--r--gr-digital/lib/digital_costas_loop_cc.cc138
-rw-r--r--gr-digital/lib/digital_costas_loop_cc.h148
-rwxr-xr-xgr-digital/python/qa_costas_loop_cc.py17
-rw-r--r--gr-digital/swig/digital_costas_loop_cc.i23
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 5d98bde4c4..be914486f2 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 9c112d3285..530a2e2a3d 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 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/swig/digital_costas_loop_cc.i b/gr-digital/swig/digital_costas_loop_cc.i
index 6d3d009f8a..f6e2765626 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;
};