summaryrefslogtreecommitdiff
path: root/gr-digital
diff options
context:
space:
mode:
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 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;
};