GNU Radio 3.5.1 C++ API
digital_mpsk_receiver_cc.h
Go to the documentation of this file.
00001 /* -*- c++ -*- */
00002 /*
00003  * Copyright 2004,2007,2011 Free Software Foundation, Inc.
00004  *
00005  * This file is part of GNU Radio
00006  *
00007  * GNU Radio is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 3, or (at your option)
00010  * any later version.
00011  *
00012  * GNU Radio is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with GNU Radio; see the file COPYING.  If not, write to
00019  * the Free Software Foundation, Inc., 51 Franklin Street,
00020  * Boston, MA 02110-1301, USA.
00021  */
00022 
00023 #ifndef INCLUDED_DIGITAL_MPSK_RECEIVER_CC_H
00024 #define INCLUDED_DIGITAL_MPSK_RECEIVER_CC_H
00025 
00026 #include <digital_api.h>
00027 #include <gruel/attributes.h>
00028 #include <gri_control_loop.h>
00029 #include <gr_block.h>
00030 #include <gr_complex.h>
00031 #include <fstream>
00032 
00033 class gri_mmse_fir_interpolator_cc;
00034 
00035 class digital_mpsk_receiver_cc;
00036 typedef boost::shared_ptr<digital_mpsk_receiver_cc> digital_mpsk_receiver_cc_sptr;
00037 
00038 // public constructor
00039 DIGITAL_API digital_mpsk_receiver_cc_sptr 
00040 digital_make_mpsk_receiver_cc (unsigned int M, float theta, 
00041                                float loop_bw,
00042                                float fmin, float fmax,
00043                                float mu, float gain_mu, 
00044                                float omega, float gain_omega, float omega_rel);
00045 
00046 /*!
00047  * \brief This block takes care of receiving M-PSK modulated signals
00048  * through phase, frequency, and symbol synchronization.
00049  * \ingroup sync_blk
00050  * \ingroup demod_blk
00051  * \ingroup digital
00052  *
00053  * This block takes care of receiving M-PSK modulated signals through
00054  * phase, frequency, and symbol synchronization. It performs carrier
00055  * frequency and phase locking as well as symbol timing recovery.  It
00056  * works with (D)BPSK, (D)QPSK, and (D)8PSK as tested currently. It
00057  * should also work for OQPSK and PI/4 DQPSK.
00058  *
00059  * The phase and frequency synchronization are based on a Costas loop
00060  * that finds the error of the incoming signal point compared to its
00061  * nearest constellation point. The frequency and phase of the NCO are
00062  * updated according to this error. There are optimized phase error
00063  * detectors for BPSK and QPSK, but 8PSK is done using a brute-force
00064  * computation of the constellation points to find the minimum.
00065  *
00066  * The symbol synchronization is done using a modified Mueller and
00067  * Muller circuit from the paper:
00068  * 
00069  *    G. R. Danesfahani, T.G. Jeans, "Optimisation of modified Mueller
00070  *    and Muller algorithm," Electronics Letters, Vol. 31, no. 13, 22
00071  *    June 1995, pp. 1032 - 1033.
00072  *
00073  * This circuit interpolates the downconverted sample (using the NCO
00074  * developed by the Costas loop) every mu samples, then it finds the
00075  * sampling error based on this and the past symbols and the decision
00076  * made on the samples. Like the phase error detector, there are
00077  * optimized decision algorithms for BPSK and QPKS, but 8PSK uses
00078  * another brute force computation against all possible symbols. The
00079  * modifications to the M&M used here reduce self-noise.
00080  *
00081  */
00082 
00083 class DIGITAL_API digital_mpsk_receiver_cc : public gr_block, public gri_control_loop
00084 {
00085  public:
00086   ~digital_mpsk_receiver_cc ();
00087   void forecast(int noutput_items, gr_vector_int &ninput_items_required);
00088   int general_work (int noutput_items,
00089                     gr_vector_int &ninput_items,
00090                     gr_vector_const_void_star &input_items,
00091                     gr_vector_void_star &output_items);
00092 
00093 
00094   // Member functions related to the symbol tracking portion of the receiver
00095   //! (M&M) Returns current value of mu
00096   float mu() const { return d_mu;}
00097 
00098   //! (M&M) Returns current value of omega
00099   float omega() const { return d_omega;}
00100 
00101   //! (M&M) Returns mu gain factor
00102   float gain_mu() const { return d_gain_mu;}
00103 
00104   //! (M&M) Returns omega gain factor
00105   float gain_omega() const { return d_gain_omega;}
00106 
00107   //! (M&M) Sets value of mu
00108   void set_mu (float mu) { d_mu = mu; }
00109   
00110   //! (M&M) Sets value of omega and its min and max values 
00111   void set_omega (float omega) { 
00112     d_omega = omega;
00113     d_min_omega = omega*(1.0 - d_omega_rel);
00114     d_max_omega = omega*(1.0 + d_omega_rel);
00115     d_omega_mid = 0.5*(d_min_omega+d_max_omega);
00116   }
00117 
00118   //! (M&M) Sets value for mu gain factor
00119   void set_gain_mu (float gain_mu) { d_gain_mu = gain_mu; }
00120 
00121   //! (M&M) Sets value for omega gain factor
00122   void set_gain_omega (float gain_omega) { d_gain_omega = gain_omega; }
00123 
00124 protected:
00125   
00126   /*!
00127    * \brief Constructor to synchronize incoming M-PSK symbols
00128    *
00129    * \param M           modulation order of the M-PSK modulation
00130    * \param theta       any constant phase rotation from the real axis of the constellation
00131    * \param loop_bw     Loop bandwidth to set gains of phase/freq tracking loop
00132    * \param fmin        minimum normalized frequency value the loop can achieve
00133    * \param fmax        maximum normalized frequency value the loop can achieve
00134    * \param mu          initial parameter for the interpolator [0,1]
00135    * \param gain_mu     gain parameter of the M&M error signal to adjust mu (~0.05)
00136    * \param omega       initial value for the number of symbols between samples (~number of samples/symbol)
00137    * \param gain_omega  gain parameter to adjust omega based on the error (~omega^2/4)
00138    * \param omega_rel   sets the maximum (omega*(1+omega_rel)) and minimum (omega*(1+omega_rel)) omega (~0.005)
00139    *
00140    * The constructor also chooses which phase detector and decision maker to use in the work loop based on the
00141    * value of M.
00142    */
00143   digital_mpsk_receiver_cc (unsigned int M, float theta, 
00144                             float loop_bw,
00145                             float fmin, float fmax,
00146                             float mu, float gain_mu, 
00147                             float omega, float gain_omega, float omega_rel);
00148 
00149   void make_constellation();
00150   void mm_sampler(const gr_complex symbol);
00151   void mm_error_tracking(gr_complex sample);
00152   void phase_error_tracking(gr_complex sample);
00153 
00154 
00155   /*!
00156    * \brief Phase error detector for MPSK modulations.
00157    *
00158    * \param sample   the I&Q sample from which to determine the phase error
00159    *
00160    * This function determines the phase error for any MPSK signal by
00161    * creating a set of PSK constellation points and doing a
00162    * brute-force search to see which point minimizes the Euclidean
00163    * distance. This point is then used to derotate the sample to the
00164    * real-axis and a atan (using the fast approximation function) to
00165    * determine the phase difference between the incoming sample and
00166    * the real constellation point
00167    *
00168    * This should be cleaned up and made more efficient.
00169    *
00170    * \returns the approximated phase error.
00171    */
00172   float phase_error_detector_generic(gr_complex sample) const; // generic for M but more costly
00173 
00174   /*!
00175    * \brief Phase error detector for BPSK modulation.
00176    *
00177    * \param sample   the I&Q sample from which to determine the phase error
00178    *
00179    * This function determines the phase error using a simple BPSK
00180    * phase error detector by multiplying the real and imaginary (the
00181    * error signal) components together. As the imaginary part goes to
00182    * 0, so does this error.
00183    *
00184    * \returns the approximated phase error.
00185    */
00186   float phase_error_detector_bpsk(gr_complex sample) const;    // optimized for BPSK
00187 
00188   /*!
00189    * \brief Phase error detector for QPSK modulation.
00190    *
00191    * \param sample   the I&Q sample from which to determine the phase error
00192    *
00193    * This function determines the phase error using the limiter
00194    * approach in a standard 4th order Costas loop
00195    *
00196    * \returns the approximated phase error.
00197    */
00198   float phase_error_detector_qpsk(gr_complex sample) const;
00199 
00200 
00201 
00202   /*!
00203    * \brief Decision maker for a generic MPSK constellation.
00204    *
00205    * \param sample   the baseband I&Q sample from which to make the decision
00206    *
00207    * This decision maker is a generic implementation that does a
00208    * brute-force search for the constellation point that minimizes the
00209    * error between it and the incoming signal.
00210    *
00211    * \returns the index to d_constellation that minimizes the error/
00212  */
00213   unsigned int decision_generic(gr_complex sample) const;
00214 
00215 
00216  /*!
00217    * \brief Decision maker for BPSK constellation.
00218    *
00219    * \param sample   the baseband I&Q sample from which to make the decision
00220    *
00221    * This decision maker is a simple slicer function that makes a
00222    * decision on the symbol based on its placement on the real axis of
00223    * greater than 0 or less than 0; the quadrature component is always
00224    * 0.
00225    *
00226    * \returns the index to d_constellation that minimizes the error/
00227    */
00228   unsigned int decision_bpsk(gr_complex sample) const;
00229   
00230 
00231   /*!
00232    * \brief Decision maker for QPSK constellation.
00233    *
00234    * \param sample   the baseband I&Q sample from which to make the decision
00235    *
00236    * This decision maker is a simple slicer function that makes a
00237    * decision on the symbol based on its placement versus both axes
00238    * and returns which quadrant the symbol is in.
00239    *
00240    * \returns the index to d_constellation that minimizes the error/
00241    */
00242   unsigned int decision_qpsk(gr_complex sample) const;
00243 
00244 private:
00245   unsigned int d_M;
00246   float        d_theta;
00247 
00248   /*!
00249    * \brief Decision maker function pointer 
00250    *
00251    * \param sample   the baseband I&Q sample from which to make the decision
00252    *
00253    * This is a function pointer that is set in the constructor to
00254    * point to the proper decision function for the specified
00255    * constellation order.
00256    *
00257    * \return index into d_constellation point that is the closest to the recieved sample
00258    */
00259   unsigned int (digital_mpsk_receiver_cc::*d_decision)(gr_complex sample) const; // pointer to decision function
00260 
00261 
00262   std::vector<gr_complex> d_constellation;
00263   unsigned int d_current_const_point;
00264 
00265   // Members related to symbol timing
00266   float d_mu, d_gain_mu;
00267   float d_omega, d_gain_omega, d_omega_rel, d_max_omega, d_min_omega, d_omega_mid;
00268   gr_complex d_p_2T, d_p_1T, d_p_0T;
00269   gr_complex d_c_2T, d_c_1T, d_c_0T;
00270 
00271   /*!
00272    * \brief Phase error detector function pointer 
00273    *
00274    * \param sample   the I&Q sample from which to determine the phase error
00275    *
00276    * This is a function pointer that is set in the constructor to
00277    * point to the proper phase error detector function for the
00278    * specified constellation order.
00279    */
00280   float (digital_mpsk_receiver_cc::*d_phase_error_detector)(gr_complex sample) const;
00281 
00282 
00283   //! get interpolated value
00284   gri_mmse_fir_interpolator_cc  *d_interp;
00285   
00286   //! delay line length.
00287   static const unsigned int DLLEN = 8;
00288   
00289   //! delay line plus some length for overflow protection
00290   __GR_ATTR_ALIGNED(8) gr_complex d_dl[2*DLLEN];
00291   
00292   //! index to delay line
00293   unsigned int d_dl_idx;
00294 
00295   friend DIGITAL_API digital_mpsk_receiver_cc_sptr
00296   digital_make_mpsk_receiver_cc (unsigned int M, float theta,
00297                                  float loop_bw,
00298                                  float fmin, float fmax,
00299                                  float mu, float gain_mu, 
00300                                  float omega, float gain_omega, float omega_rel);
00301 };
00302 
00303 #endif