diff options
author | Tom Rondeau | 2011-08-30 16:36:13 -0400 |
---|---|---|
committer | Tom Rondeau | 2011-08-30 16:36:13 -0400 |
commit | ea7cd530c1f9ba58c6d0582d6381b1ea1f104d6d (patch) | |
tree | 4fd01772f22205f37c0db6108a6bc333e3afb72b /gr-digital | |
parent | 317e8321472cb9e921757636b561897b12199195 (diff) | |
parent | ba3a3158456cfc866204071183ccdd773f0ab5a2 (diff) | |
download | gnuradio-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.cc | 139 | ||||
-rw-r--r-- | gr-digital/lib/digital_fll_band_edge_cc.h | 216 | ||||
-rw-r--r-- | gr-digital/lib/digital_mpsk_receiver_cc.cc | 36 | ||||
-rw-r--r-- | gr-digital/lib/digital_mpsk_receiver_cc.h | 167 | ||||
-rwxr-xr-x[-rw-r--r--] | gr-digital/python/qa_crc32.py | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | gr-digital/python/qa_fll_band_edge.py | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | gr-digital/python/qa_lms_equalizer.py | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | gr-digital/python/qa_mpsk_receiver.py | 26 | ||||
-rw-r--r-- | gr-digital/swig/digital_fll_band_edge_cc.i | 2 | ||||
-rw-r--r-- | gr-digital/swig/digital_mpsk_receiver_cc.i | 14 |
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; } }; |