summaryrefslogtreecommitdiff
path: root/gr-digital
diff options
context:
space:
mode:
authorTom Rondeau2011-08-30 16:36:13 -0400
committerTom Rondeau2011-08-30 16:36:13 -0400
commitea7cd530c1f9ba58c6d0582d6381b1ea1f104d6d (patch)
tree4fd01772f22205f37c0db6108a6bc333e3afb72b /gr-digital
parent317e8321472cb9e921757636b561897b12199195 (diff)
parentba3a3158456cfc866204071183ccdd773f0ab5a2 (diff)
downloadgnuradio-ea7cd530c1f9ba58c6d0582d6381b1ea1f104d6d.tar.gz
gnuradio-ea7cd530c1f9ba58c6d0582d6381b1ea1f104d6d.tar.bz2
gnuradio-ea7cd530c1f9ba58c6d0582d6381b1ea1f104d6d.zip
Merge branch 'digital' of github.com:trondeau/gnuradio into digital
Diffstat (limited to 'gr-digital')
-rw-r--r--gr-digital/lib/digital_fll_band_edge_cc.cc139
-rw-r--r--gr-digital/lib/digital_fll_band_edge_cc.h216
-rw-r--r--gr-digital/lib/digital_mpsk_receiver_cc.cc36
-rw-r--r--gr-digital/lib/digital_mpsk_receiver_cc.h167
-rwxr-xr-x[-rw-r--r--]gr-digital/python/qa_crc32.py0
-rwxr-xr-x[-rw-r--r--]gr-digital/python/qa_fll_band_edge.py0
-rwxr-xr-x[-rw-r--r--]gr-digital/python/qa_lms_equalizer.py0
-rwxr-xr-x[-rw-r--r--]gr-digital/python/qa_mpsk_receiver.py26
-rw-r--r--gr-digital/swig/digital_fll_band_edge_cc.i2
-rw-r--r--gr-digital/swig/digital_mpsk_receiver_cc.i14
10 files changed, 165 insertions, 435 deletions
diff --git a/gr-digital/lib/digital_fll_band_edge_cc.cc b/gr-digital/lib/digital_fll_band_edge_cc.cc
index 70cb54351..05c092622 100644
--- a/gr-digital/lib/digital_fll_band_edge_cc.cc
+++ b/gr-digital/lib/digital_fll_band_edge_cc.cc
@@ -55,6 +55,7 @@ digital_fll_band_edge_cc::digital_fll_band_edge_cc (float samps_per_sym, float r
: gr_sync_block ("fll_band_edge_cc",
gr_make_io_signature (1, 1, sizeof(gr_complex)),
gr_make_io_signaturev (1, 4, iosig)),
+ gri_control_loop(bandwidth, M_TWOPI*(2.0/samps_per_sym), -M_TWOPI*(2.0/samps_per_sym)),
d_updated (false)
{
// Initialize samples per symbol
@@ -75,22 +76,8 @@ digital_fll_band_edge_cc::digital_fll_band_edge_cc (float samps_per_sym, float r
}
d_filter_size = filter_size;
- // base this on the number of samples per symbol
- d_max_freq = M_TWOPI * (2.0/samps_per_sym);
- d_min_freq = -M_TWOPI * (2.0/samps_per_sym);
-
- // Set the damping factor for a critically damped system
- d_damping = sqrtf(2.0f)/2.0f;
-
- // Set the bandwidth, which will then call update_gains()
- set_loop_bandwidth(bandwidth);
-
// Build the band edge filters
design_filter(d_sps, d_rolloff, d_filter_size);
-
- // Initialize loop values
- d_freq = 0;
- d_phase = 0;
}
digital_fll_band_edge_cc::~digital_fll_band_edge_cc ()
@@ -102,47 +89,6 @@ digital_fll_band_edge_cc::~digital_fll_band_edge_cc ()
SET FUNCTIONS
*******************************************************************/
-
-void
-digital_fll_band_edge_cc::set_loop_bandwidth(float bw)
-{
- if(bw < 0) {
- throw std::out_of_range ("digital_fll_band_edge_cc: invalid bandwidth. Must be >= 0.");
- }
-
- d_loop_bw = bw;
- update_gains();
-}
-
-void
-digital_fll_band_edge_cc::set_damping_factor(float df)
-{
- if(df < 0 || df > 1.0) {
- throw std::out_of_range ("digital_fll_band_edge_cc: invalid damping factor. Must be in [0,1].");
- }
-
- d_damping = df;
- update_gains();
-}
-
-void
-digital_fll_band_edge_cc::set_alpha(float alpha)
-{
- if(alpha < 0 || alpha > 1.0) {
- throw std::out_of_range ("digital_fll_band_edge_cc: invalid alpha. Must be in [0,1].");
- }
- d_alpha = alpha;
-}
-
-void
-digital_fll_band_edge_cc::set_beta(float beta)
-{
- if(beta < 0 || beta > 1.0) {
- throw std::out_of_range ("digital_fll_band_edge_cc: invalid beta. Must be in [0,1].");
- }
- d_beta = beta;
-}
-
void
digital_fll_band_edge_cc::set_samples_per_symbol(float sps)
{
@@ -173,57 +119,10 @@ digital_fll_band_edge_cc::set_filter_size(int filter_size)
design_filter(d_sps, d_rolloff, d_filter_size);
}
-void
-digital_fll_band_edge_cc::set_frequency(float freq)
-{
- if(freq > d_max_freq)
- d_freq = d_min_freq;
- else if(freq < d_min_freq)
- d_freq = d_max_freq;
- else
- d_freq = freq;
-}
-
-void
-digital_fll_band_edge_cc::set_phase(float phase)
-{
- d_phase = phase;
- while(d_phase>M_TWOPI)
- d_phase -= M_TWOPI;
- while(d_phase<-M_TWOPI)
- d_phase += M_TWOPI;
-}
-
-
/*******************************************************************
GET FUNCTIONS
*******************************************************************/
-
-float
-digital_fll_band_edge_cc::get_loop_bandwidth() const
-{
- return d_loop_bw;
-}
-
-float
-digital_fll_band_edge_cc::get_damping_factor() const
-{
- return d_damping;
-}
-
-float
-digital_fll_band_edge_cc::get_alpha() const
-{
- return d_alpha;
-}
-
-float
-digital_fll_band_edge_cc::get_beta() const
-{
- return d_beta;
-}
-
float
digital_fll_band_edge_cc::get_samples_per_symbol() const
{
@@ -242,31 +141,10 @@ digital_fll_band_edge_cc:: get_filter_size() const
return d_filter_size;
}
-float
-digital_fll_band_edge_cc::get_frequency() const
-{
- return d_freq;
-}
-
-float
-digital_fll_band_edge_cc::get_phase() const
-{
- return d_phase;
-}
-
/*******************************************************************
*******************************************************************/
-
-void
-digital_fll_band_edge_cc::update_gains()
-{
- float denom = (1.0 + 2.0*d_damping*d_loop_bw + d_loop_bw*d_loop_bw);
- d_alpha = (4*d_damping*d_loop_bw) / denom;
- d_beta = (4*d_loop_bw*d_loop_bw) / denom;
-}
-
void
digital_fll_band_edge_cc::design_filter(float samps_per_sym,
float rolloff, int filter_size)
@@ -366,18 +244,9 @@ digital_fll_band_edge_cc::work (int noutput_items,
}
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;
+ advance_loop(error);
+ phase_wrap();
+ frequency_limit();
if(output_items.size() == 4) {
frq[i] = d_freq;
diff --git a/gr-digital/lib/digital_fll_band_edge_cc.h b/gr-digital/lib/digital_fll_band_edge_cc.h
index 496289d90..5b7732906 100644
--- a/gr-digital/lib/digital_fll_band_edge_cc.h
+++ b/gr-digital/lib/digital_fll_band_edge_cc.h
@@ -25,6 +25,7 @@
#define INCLUDED_DIGITAL_FLL_BAND_EDGE_CC_H
#include <gr_sync_block.h>
+#include <gri_control_loop.h>
class digital_fll_band_edge_cc;
typedef boost::shared_ptr<digital_fll_band_edge_cc> digital_fll_band_edge_cc_sptr;
@@ -39,39 +40,51 @@ digital_fll_band_edge_cc_sptr digital_make_fll_band_edge_cc (float samps_per_sym
*
* \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 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).
+ * 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 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
+ * 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.
+ * 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.
+ * It is very important that the band edge filters be the derivatives
+ * of the pulse shaping filter, and that they be linear
+ * phase. Otherwise, the variance of the error will be very large.
*
*/
-class digital_fll_band_edge_cc : public gr_sync_block
+class digital_fll_band_edge_cc : public gr_sync_block, public gri_control_loop
{
private:
/*!
@@ -92,18 +105,10 @@ class digital_fll_band_edge_cc : public gr_sync_block
float d_max_freq;
float d_min_freq;
- float d_loop_bw;
- float d_damping;
- float d_alpha;
- float d_beta;
-
std::vector<gr_complex> d_taps_lower;
std::vector<gr_complex> d_taps_upper;
bool d_updated;
- float d_freq;
- float d_phase;
-
/*!
* Build the FLL
* \param samps_per_sym (float) number of samples per symbol
@@ -115,11 +120,6 @@ class digital_fll_band_edge_cc : public gr_sync_block
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
*
@@ -137,67 +137,11 @@ public:
*******************************************************************/
/*!
- * \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.
+ * 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
*
@@ -207,13 +151,14 @@ public:
/*!
* \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 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).
+ * 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]
*
@@ -223,68 +168,25 @@ public:
/*!
* \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 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.
+ * This should be about the same number of taps used in the
+ * transmitter's shaping filter and also not very large. A large
+ * number of taps will result in a large delay between input and
+ * frequency estimation, and so will not be as accurate. Between 30
+ * and 70 taps is usual.
*
* \param filter_size (float) number of taps in the filters
*
*/
void set_filter_size(int filter_size);
- /*!
- * \brief Set the FLL's frequency.
- *
- * Set's the FLL's frequency. While this is normally updated by the
- * inner loop of the algorithm, it could be useful to manually initialize,
- * set, or reset this under certain circumstances.
- *
- * \param freq (float) new frequency
- *
- */
- void set_frequency(float freq);
-
- /*!
- * \brief Set the FLL's phase.
- *
- * Set's the FLL's phase. While this is normally updated by the
- * inner loop of the algorithm, it could be useful to manually initialize,
- * set, or reset this under certain circumstances.
- *
- * \param phase (float) new phase
- *
- */
- void set_phase(float phase);
-
/*******************************************************************
GET FUNCTIONS
*******************************************************************/
/*!
- * \brief Returns the loop bandwidth
- */
- float get_loop_bandwidth() const;
-
- /*!
- * \brief Returns the loop damping factor
- */
- float get_damping_factor() const;
-
- /*!
- * \brief Returns the loop gain alpha
- */
- float get_alpha() const;
-
- /*!
- * \brief Returns the loop gain beta
- */
- float get_beta() const;
-
- /*!
* \brief Returns the number of sampler per symbol used for the filter
*/
float get_samples_per_symbol() const;
@@ -300,16 +202,6 @@ public:
int get_filter_size() const;
/*!
- * \brief Get the FLL's frequency estimate
- */
- float get_frequency() const;
-
- /*!
- * \brief Get the FLL's phase estimate
- */
- float get_phase() const;
-
- /*!
* Print the taps to screen.
*/
void print_taps();
diff --git a/gr-digital/lib/digital_mpsk_receiver_cc.cc b/gr-digital/lib/digital_mpsk_receiver_cc.cc
index 3b2ea9840..363b86c9f 100644
--- a/gr-digital/lib/digital_mpsk_receiver_cc.cc
+++ b/gr-digital/lib/digital_mpsk_receiver_cc.cc
@@ -41,28 +41,30 @@
digital_mpsk_receiver_cc_sptr
digital_make_mpsk_receiver_cc(unsigned int M, float theta,
- float alpha, float beta,
+ float loop_bw,
float fmin, float fmax,
float mu, float gain_mu,
float omega, float gain_omega, float omega_rel)
{
return gnuradio::get_initial_sptr(new digital_mpsk_receiver_cc (M, theta,
- alpha, beta,
- fmin, fmax,
- mu, gain_mu,
- omega, gain_omega, omega_rel));
+ loop_bw,
+ fmin, fmax,
+ mu, gain_mu,
+ omega, gain_omega,
+ omega_rel));
}
digital_mpsk_receiver_cc::digital_mpsk_receiver_cc (unsigned int M, float theta,
- float alpha, float beta,
- float fmin, float fmax,
- float mu, float gain_mu,
- float omega, float gain_omega, float omega_rel)
+ float loop_bw,
+ float fmin, float fmax,
+ float mu, float gain_mu,
+ float omega, float gain_omega,
+ float omega_rel)
: gr_block ("mpsk_receiver_cc",
gr_make_io_signature (1, 1, sizeof (gr_complex)),
gr_make_io_signature (1, 1, sizeof (gr_complex))),
+ gri_control_loop(loop_bw, fmax, fmin),
d_M(M), d_theta(theta),
- d_alpha(alpha), d_beta(beta), d_freq(0), d_max_freq(fmax), d_min_freq(fmin), d_phase(0),
d_current_const_point(0),
d_mu(mu), d_gain_mu(gain_mu), d_gain_omega(gain_omega),
d_omega_rel(omega_rel), d_max_omega(0), d_min_omega(0),
@@ -265,18 +267,10 @@ digital_mpsk_receiver_cc::phase_error_tracking(gr_complex sample)
// Make phase and frequency corrections based on sampled value
phase_error = (*this.*d_phase_error_detector)(sample);
-
- d_freq += d_beta*phase_error; // adjust frequency based on error
- d_phase += d_freq + d_alpha*phase_error; // adjust phase based on error
-
- // Make sure we stay within +-2pi
- while(d_phase > M_TWOPI)
- d_phase -= M_TWOPI;
- while(d_phase < -M_TWOPI)
- d_phase += M_TWOPI;
- // Limit the frequency range
- d_freq = gr_branchless_clip(d_freq, d_max_freq);
+ advance_loop(phase_error);
+ phase_wrap();
+ frequency_limit();
#if VERBOSE_COSTAS
printf("cl: phase_error: %f phase: %f freq: %f sample: %f+j%f constellation: %f+j%f\n",
diff --git a/gr-digital/lib/digital_mpsk_receiver_cc.h b/gr-digital/lib/digital_mpsk_receiver_cc.h
index bcb06e17c..91cd4a14d 100644
--- a/gr-digital/lib/digital_mpsk_receiver_cc.h
+++ b/gr-digital/lib/digital_mpsk_receiver_cc.h
@@ -24,6 +24,7 @@
#define INCLUDED_DIGITAL_MPSK_RECEIVER_CC_H
#include <gruel/attributes.h>
+#include <gri_control_loop.h>
#include <gr_block.h>
#include <gr_complex.h>
#include <fstream>
@@ -36,41 +37,48 @@ typedef boost::shared_ptr<digital_mpsk_receiver_cc> digital_mpsk_receiver_cc_spt
// public constructor
digital_mpsk_receiver_cc_sptr
digital_make_mpsk_receiver_cc (unsigned int M, float theta,
- float alpha, float beta,
+ float loop_bw,
float fmin, float fmax,
float mu, float gain_mu,
float omega, float gain_omega, float omega_rel);
/*!
- * \brief This block takes care of receiving M-PSK modulated signals through phase, frequency, and symbol
- * synchronization.
+ * \brief This block takes care of receiving M-PSK modulated signals
+ * through phase, frequency, and symbol synchronization.
* \ingroup sync_blk
* \ingroup demod_blk
*
- * This block takes care of receiving M-PSK modulated signals through phase, frequency, and symbol
- * synchronization. It performs carrier frequency and phase locking as well as symbol timing recovery.
- * It works with (D)BPSK, (D)QPSK, and (D)8PSK as tested currently. It should also work for OQPSK and
- * PI/4 DQPSK.
+ * This block takes care of receiving M-PSK modulated signals through
+ * phase, frequency, and symbol synchronization. It performs carrier
+ * frequency and phase locking as well as symbol timing recovery. It
+ * works with (D)BPSK, (D)QPSK, and (D)8PSK as tested currently. It
+ * should also work for OQPSK and PI/4 DQPSK.
*
- * The phase and frequency synchronization are based on a Costas loop that finds the error of the incoming
- * signal point compared to its nearest constellation point. The frequency and phase of the NCO are
- * updated according to this error. There are optimized phase error detectors for BPSK and QPSK, but 8PSK
- * is done using a brute-force computation of the constellation points to find the minimum.
+ * The phase and frequency synchronization are based on a Costas loop
+ * that finds the error of the incoming signal point compared to its
+ * nearest constellation point. The frequency and phase of the NCO are
+ * updated according to this error. There are optimized phase error
+ * detectors for BPSK and QPSK, but 8PSK is done using a brute-force
+ * computation of the constellation points to find the minimum.
*
- * The symbol synchronization is done using a modified Mueller and Muller circuit from the paper:
+ * The symbol synchronization is done using a modified Mueller and
+ * Muller circuit from the paper:
*
- * G. R. Danesfahani, T.G. Jeans, "Optimisation of modified Mueller and Muller
- * algorithm," Electronics Letters, Vol. 31, no. 13, 22 June 1995, pp. 1032 - 1033.
+ * G. R. Danesfahani, T.G. Jeans, "Optimisation of modified Mueller
+ * and Muller algorithm," Electronics Letters, Vol. 31, no. 13, 22
+ * June 1995, pp. 1032 - 1033.
*
- * This circuit interpolates the downconverted sample (using the NCO developed by the Costas loop)
- * every mu samples, then it finds the sampling error based on this and the past symbols and the decision
- * made on the samples. Like the phase error detector, there are optimized decision algorithms for BPSK
- * and QPKS, but 8PSK uses another brute force computation against all possible symbols. The modifications
- * to the M&M used here reduce self-noise.
+ * This circuit interpolates the downconverted sample (using the NCO
+ * developed by the Costas loop) every mu samples, then it finds the
+ * sampling error based on this and the past symbols and the decision
+ * made on the samples. Like the phase error detector, there are
+ * optimized decision algorithms for BPSK and QPKS, but 8PSK uses
+ * another brute force computation against all possible symbols. The
+ * modifications to the M&M used here reduce self-noise.
*
*/
-class digital_mpsk_receiver_cc : public gr_block
+class digital_mpsk_receiver_cc : public gr_block, public gri_control_loop
{
public:
~digital_mpsk_receiver_cc ();
@@ -111,43 +119,14 @@ class digital_mpsk_receiver_cc : public gr_block
//! (M&M) Sets value for omega gain factor
void set_gain_omega (float gain_omega) { d_gain_omega = gain_omega; }
-
-
- // Member function related to the phase/frequency tracking portion of the receiver
- //! (CL) Returns the value for alpha (the phase gain term)
- float alpha() const { return d_alpha; }
-
- //! (CL) Returns the value of beta (the frequency gain term)
- float beta() const { return d_beta; }
-
- //! (CL) Returns the current value of the frequency of the NCO in the Costas loop
- float freq() const { return d_freq; }
-
- //! (CL) Returns the current value of the phase of the NCO in the Costal loop
- float phase() const { return d_phase; }
-
- //! (CL) Sets the value for alpha (the phase gain term)
- void set_alpha(float alpha) { d_alpha = alpha; }
-
- //! (CL) Setss the value of beta (the frequency gain term)
- void set_beta(float beta) { d_beta = beta; }
-
- //! (CL) Sets the current value of the frequency of the NCO in the Costas loop
- void set_freq(float freq) { d_freq = freq; }
-
- //! (CL) Setss the current value of the phase of the NCO in the Costal loop
- void set_phase(float phase) { d_phase = phase; }
-
-
protected:
-
- /*!
+
+ /*!
* \brief Constructor to synchronize incoming M-PSK symbols
*
* \param M modulation order of the M-PSK modulation
* \param theta any constant phase rotation from the real axis of the constellation
- * \param alpha gain parameter to adjust the phase in the Costas loop (~0.01)
- * \param beta gain parameter to adjust the frequency in the Costas loop (~alpha^2/4)
+ * \param loop_bw Loop bandwidth to set gains of phase/freq tracking loop
* \param fmin minimum normalized frequency value the loop can achieve
* \param fmax maximum normalized frequency value the loop can achieve
* \param mu initial parameter for the interpolator [0,1]
@@ -160,7 +139,7 @@ protected:
* value of M.
*/
digital_mpsk_receiver_cc (unsigned int M, float theta,
- float alpha, float beta,
+ float loop_bw,
float fmin, float fmax,
float mu, float gain_mu,
float omega, float gain_omega, float omega_rel);
@@ -171,54 +150,61 @@ protected:
void phase_error_tracking(gr_complex sample);
-/*!
+ /*!
* \brief Phase error detector for MPSK modulations.
*
* \param sample the I&Q sample from which to determine the phase error
*
- * This function determines the phase error for any MPSK signal by creating a set of PSK constellation points
- * and doing a brute-force search to see which point minimizes the Euclidean distance. This point is then used
- * to derotate the sample to the real-axis and a atan (using the fast approximation function) to determine the
- * phase difference between the incoming sample and the real constellation point
+ * This function determines the phase error for any MPSK signal by
+ * creating a set of PSK constellation points and doing a
+ * brute-force search to see which point minimizes the Euclidean
+ * distance. This point is then used to derotate the sample to the
+ * real-axis and a atan (using the fast approximation function) to
+ * determine the phase difference between the incoming sample and
+ * the real constellation point
*
* This should be cleaned up and made more efficient.
*
* \returns the approximated phase error.
- */
+ */
float phase_error_detector_generic(gr_complex sample) const; // generic for M but more costly
- /*!
+ /*!
* \brief Phase error detector for BPSK modulation.
*
* \param sample the I&Q sample from which to determine the phase error
*
- * This function determines the phase error using a simple BPSK phase error detector by multiplying the real
- * and imaginary (the error signal) components together. As the imaginary part goes to 0, so does this error.
+ * This function determines the phase error using a simple BPSK
+ * phase error detector by multiplying the real and imaginary (the
+ * error signal) components together. As the imaginary part goes to
+ * 0, so does this error.
*
* \returns the approximated phase error.
- */
+ */
float phase_error_detector_bpsk(gr_complex sample) const; // optimized for BPSK
- /*!
+ /*!
* \brief Phase error detector for QPSK modulation.
*
* \param sample the I&Q sample from which to determine the phase error
*
- * This function determines the phase error using the limiter approach in a standard 4th order Costas loop
+ * This function determines the phase error using the limiter
+ * approach in a standard 4th order Costas loop
*
* \returns the approximated phase error.
- */
+ */
float phase_error_detector_qpsk(gr_complex sample) const;
- /*!
+ /*!
* \brief Decision maker for a generic MPSK constellation.
*
* \param sample the baseband I&Q sample from which to make the decision
*
- * This decision maker is a generic implementation that does a brute-force search
- * for the constellation point that minimizes the error between it and the incoming signal.
+ * This decision maker is a generic implementation that does a
+ * brute-force search for the constellation point that minimizes the
+ * error between it and the incoming signal.
*
* \returns the index to d_constellation that minimizes the error/
*/
@@ -230,46 +216,44 @@ protected:
*
* \param sample the baseband I&Q sample from which to make the decision
*
- * This decision maker is a simple slicer function that makes a decision on the symbol based on its
- * placement on the real axis of greater than 0 or less than 0; the quadrature component is always 0.
+ * This decision maker is a simple slicer function that makes a
+ * decision on the symbol based on its placement on the real axis of
+ * greater than 0 or less than 0; the quadrature component is always
+ * 0.
*
* \returns the index to d_constellation that minimizes the error/
- */
+ */
unsigned int decision_bpsk(gr_complex sample) const;
- /*!
+ /*!
* \brief Decision maker for QPSK constellation.
*
* \param sample the baseband I&Q sample from which to make the decision
*
- * This decision maker is a simple slicer function that makes a decision on the symbol based on its
- * placement versus both axes and returns which quadrant the symbol is in.
+ * This decision maker is a simple slicer function that makes a
+ * decision on the symbol based on its placement versus both axes
+ * and returns which quadrant the symbol is in.
*
* \returns the index to d_constellation that minimizes the error/
- */
+ */
unsigned int decision_qpsk(gr_complex sample) const;
private:
unsigned int d_M;
float d_theta;
- // Members related to carrier and phase tracking
- float d_alpha;
- float d_beta;
- float d_freq, d_max_freq, d_min_freq;
- float d_phase;
-
-/*!
+ /*!
* \brief Decision maker function pointer
*
* \param sample the baseband I&Q sample from which to make the decision
*
- * This is a function pointer that is set in the constructor to point to the proper decision function
- * for the specified constellation order.
+ * This is a function pointer that is set in the constructor to
+ * point to the proper decision function for the specified
+ * constellation order.
*
* \return index into d_constellation point that is the closest to the recieved sample
- */
+ */
unsigned int (digital_mpsk_receiver_cc::*d_decision)(gr_complex sample) const; // pointer to decision function
@@ -282,14 +266,15 @@ protected:
gr_complex d_p_2T, d_p_1T, d_p_0T;
gr_complex d_c_2T, d_c_1T, d_c_0T;
- /*!
+ /*!
* \brief Phase error detector function pointer
*
* \param sample the I&Q sample from which to determine the phase error
*
- * This is a function pointer that is set in the constructor to point to the proper phase error detector
- * function for the specified constellation order.
- */
+ * This is a function pointer that is set in the constructor to
+ * point to the proper phase error detector function for the
+ * specified constellation order.
+ */
float (digital_mpsk_receiver_cc::*d_phase_error_detector)(gr_complex sample) const;
@@ -307,7 +292,7 @@ protected:
friend digital_mpsk_receiver_cc_sptr
digital_make_mpsk_receiver_cc (unsigned int M, float theta,
- float alpha, float beta,
+ float loop_bw,
float fmin, float fmax,
float mu, float gain_mu,
float omega, float gain_omega, float omega_rel);
diff --git a/gr-digital/python/qa_crc32.py b/gr-digital/python/qa_crc32.py
index f86813f3f..f86813f3f 100644..100755
--- a/gr-digital/python/qa_crc32.py
+++ b/gr-digital/python/qa_crc32.py
diff --git a/gr-digital/python/qa_fll_band_edge.py b/gr-digital/python/qa_fll_band_edge.py
index 088eb2b68..088eb2b68 100644..100755
--- a/gr-digital/python/qa_fll_band_edge.py
+++ b/gr-digital/python/qa_fll_band_edge.py
diff --git a/gr-digital/python/qa_lms_equalizer.py b/gr-digital/python/qa_lms_equalizer.py
index 025c785aa..025c785aa 100644..100755
--- a/gr-digital/python/qa_lms_equalizer.py
+++ b/gr-digital/python/qa_lms_equalizer.py
diff --git a/gr-digital/python/qa_mpsk_receiver.py b/gr-digital/python/qa_mpsk_receiver.py
index 7e9a76e1f..6531e59f7 100644..100755
--- a/gr-digital/python/qa_mpsk_receiver.py
+++ b/gr-digital/python/qa_mpsk_receiver.py
@@ -36,8 +36,7 @@ class test_mpsk_receiver(gr_unittest.TestCase):
# Test BPSK sync
M = 2
theta = 0
- alpha = 0.1
- beta = 0.25*alpha*alpha
+ loop_bw = cmath.pi/100.0
fmin = -0.5
fmax = 0.5
mu = 0.25
@@ -46,7 +45,7 @@ class test_mpsk_receiver(gr_unittest.TestCase):
gain_omega = 0.001
omega_rel = 0.001
- self.test = digital_swig.mpsk_receiver_cc(M, theta, alpha, beta,
+ self.test = digital_swig.mpsk_receiver_cc(M, theta, loop_bw,
fmin, fmax, mu, gain_mu,
omega, gain_omega,
omega_rel)
@@ -68,8 +67,8 @@ class test_mpsk_receiver(gr_unittest.TestCase):
expected_result = expected_result[len_e - Ncmp:]
dst_data = dst_data[len_d - Ncmp:]
- #print expected_result
- #print dst_data
+ #for e,d in zip(expected_result, dst_data):
+ # print e, d
self.assertComplexTuplesAlmostEqual (expected_result, dst_data, 1)
@@ -78,8 +77,7 @@ class test_mpsk_receiver(gr_unittest.TestCase):
# Test QPSK sync
M = 4
theta = 0
- alpha = 0.1
- beta = 0.25*alpha*alpha
+ loop_bw = 2*cmath.pi/100.0
fmin = -0.5
fmax = 0.5
mu = 0.25
@@ -88,11 +86,11 @@ class test_mpsk_receiver(gr_unittest.TestCase):
gain_omega = 0.001
omega_rel = 0.001
- self.test = digital_swig.mpsk_receiver_cc(M, theta, alpha, beta,
+ self.test = digital_swig.mpsk_receiver_cc(M, theta, loop_bw,
fmin, fmax, mu, gain_mu,
omega, gain_omega,
omega_rel)
-
+
data = 1000*[complex( 0.707, 0.707), complex( 0.707, 0.707),
complex(-0.707, 0.707), complex(-0.707, 0.707),
complex(-0.707, -0.707), complex(-0.707, -0.707),
@@ -103,8 +101,8 @@ class test_mpsk_receiver(gr_unittest.TestCase):
self.tb.connect(self.src, self.test, self.snk)
self.tb.run()
- expected_result = 1000*[complex(1.2, 0), complex(0, 1.2),
- complex(-1.2, 0), complex(0, -1.2)]
+ expected_result = 1000*[complex(0, -1.0), complex(1.0, 0),
+ complex(0, 1.0), complex(-1.0, 0)]
dst_data = self.snk.data()
# Only compare last Ncmp samples
@@ -114,9 +112,9 @@ class test_mpsk_receiver(gr_unittest.TestCase):
expected_result = expected_result[len_e - Ncmp:]
dst_data = dst_data[len_d - Ncmp:]
- #print expected_result
- #print dst_data
-
+ #for e,d in zip(expected_result, dst_data):
+ # print e, d
+
self.assertComplexTuplesAlmostEqual (expected_result, dst_data, 1)
if __name__ == '__main__':
diff --git a/gr-digital/swig/digital_fll_band_edge_cc.i b/gr-digital/swig/digital_fll_band_edge_cc.i
index f022bc7e1..3efcb89ed 100644
--- a/gr-digital/swig/digital_fll_band_edge_cc.i
+++ b/gr-digital/swig/digital_fll_band_edge_cc.i
@@ -27,7 +27,7 @@ digital_fll_band_edge_cc_sptr digital_make_fll_band_edge_cc (float samps_per_sym
int filter_size,
float bandwidth);
-class digital_fll_band_edge_cc : public gr_sync_block
+class digital_fll_band_edge_cc : public gr_sync_block, public gri_control_loop
{
private:
digital_fll_band_edge_cc (float samps_per_sym, float rolloff,
diff --git a/gr-digital/swig/digital_mpsk_receiver_cc.i b/gr-digital/swig/digital_mpsk_receiver_cc.i
index cdc9f661b..b51411f6f 100644
--- a/gr-digital/swig/digital_mpsk_receiver_cc.i
+++ b/gr-digital/swig/digital_mpsk_receiver_cc.i
@@ -23,16 +23,16 @@
GR_SWIG_BLOCK_MAGIC(digital,mpsk_receiver_cc);
digital_mpsk_receiver_cc_sptr digital_make_mpsk_receiver_cc (unsigned int M, float theta,
- float alpha, float beta,
+ float loop_bw,
float fmin, float fmax,
float mu, float gain_mu,
float omega, float gain_omega,
float omega_rel);
-class digital_mpsk_receiver_cc : public gr_block
+class digital_mpsk_receiver_cc : public gr_block, public gri_control_loop
{
private:
digital_mpsk_receiver_cc (unsigned int M,float theta,
- float alpha, float beta,
+ float loop_bw,
float fmin, float fmax,
float mu, float gain_mu,
float omega, float gain_omega, float omega_rel);
@@ -49,12 +49,4 @@ public:
}
void set_gain_mu (float gain_mu) { d_gain_mu = gain_mu; }
void set_gain_omega (float gain_omega) { d_gain_omega = gain_omega; }
- float alpha() const { return d_alpha; }
- float beta() const { return d_beta; }
- float freq() const { return d_freq; }
- float phase() const { return d_phase; }
- void set_alpha(float alpha) { d_alpha = alpha; }
- void set_beta(float beta) { d_beta = beta; }
- void set_freq(float freq) { d_freq = freq; }
- void set_phase(float phase) { d_phase = phase; }
};