GNU Radio 3.6.5 C++ API
|
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 synchronizers_blk 00050 * 00051 * \details 00052 * This block takes care of receiving M-PSK modulated signals through 00053 * phase, frequency, and symbol synchronization. It performs carrier 00054 * frequency and phase locking as well as symbol timing recovery. It 00055 * works with (D)BPSK, (D)QPSK, and (D)8PSK as tested currently. It 00056 * should also work for OQPSK and PI/4 DQPSK. 00057 * 00058 * The phase and frequency synchronization are based on a Costas loop 00059 * that finds the error of the incoming signal point compared to its 00060 * nearest constellation point. The frequency and phase of the NCO are 00061 * updated according to this error. There are optimized phase error 00062 * detectors for BPSK and QPSK, but 8PSK is done using a brute-force 00063 * computation of the constellation points to find the minimum. 00064 * 00065 * The symbol synchronization is done using a modified Mueller and 00066 * Muller circuit from the paper: 00067 * 00068 * "G. R. Danesfahani, T. G. Jeans, "Optimisation of modified Mueller 00069 * and Muller algorithm," Electronics Letters, Vol. 31, no. 13, 22 00070 * June 1995, pp. 1032 - 1033." 00071 * 00072 * This circuit interpolates the downconverted sample (using the NCO 00073 * developed by the Costas loop) every mu samples, then it finds the 00074 * sampling error based on this and the past symbols and the decision 00075 * made on the samples. Like the phase error detector, there are 00076 * optimized decision algorithms for BPSK and QPKS, but 8PSK uses 00077 * another brute force computation against all possible symbols. The 00078 * modifications to the M&M used here reduce self-noise. 00079 */ 00080 class DIGITAL_API digital_mpsk_receiver_cc : public gr_block, public gri_control_loop 00081 { 00082 public: 00083 ~digital_mpsk_receiver_cc (); 00084 void forecast(int noutput_items, gr_vector_int &ninput_items_required); 00085 int general_work (int noutput_items, 00086 gr_vector_int &ninput_items, 00087 gr_vector_const_void_star &input_items, 00088 gr_vector_void_star &output_items); 00089 00090 00091 //! Returns the modulation order (M) currently set 00092 float modulation_order() const { return d_M; } 00093 00094 //! Returns current value of theta 00095 float theta() const { return d_theta; } 00096 00097 //! Returns current value of mu 00098 float mu() const { return d_mu; } 00099 00100 //! Returns current value of omega 00101 float omega() const { return d_omega; } 00102 00103 //! Returns mu gain factor 00104 float gain_mu() const { return d_gain_mu; } 00105 00106 //! Returns omega gain factor 00107 float gain_omega() const { return d_gain_omega; } 00108 00109 //! Returns the relative omega limit 00110 float gain_omega_rel() const {return d_omega_rel; } 00111 00112 //! Sets the modulation order (M) currently 00113 void set_modulation_order(unsigned int M); 00114 00115 //! Sets value of theta 00116 void set_theta(float theta) { d_theta = theta; } 00117 00118 //! Sets value of mu 00119 void set_mu (float mu) { d_mu = mu; } 00120 00121 //! Sets value of omega and its min and max values 00122 void set_omega (float omega) { 00123 d_omega = omega; 00124 d_min_omega = omega*(1.0 - d_omega_rel); 00125 d_max_omega = omega*(1.0 + d_omega_rel); 00126 d_omega_mid = 0.5*(d_min_omega+d_max_omega); 00127 } 00128 00129 //! Sets value for mu gain factor 00130 void set_gain_mu (float gain_mu) { d_gain_mu = gain_mu; } 00131 00132 //! Sets value for omega gain factor 00133 void set_gain_omega (float gain_omega) { d_gain_omega = gain_omega; } 00134 00135 //! Sets the relative omega limit and resets omega min/max values 00136 void set_gain_omega_rel(float omega_rel); 00137 00138 protected: 00139 00140 /*! 00141 * \brief Constructor to synchronize incoming M-PSK symbols 00142 * 00143 * \param M modulation order of the M-PSK modulation 00144 * \param theta any constant phase rotation from the real axis of the constellation 00145 * \param loop_bw Loop bandwidth to set gains of phase/freq tracking loop 00146 * \param fmin minimum normalized frequency value the loop can achieve 00147 * \param fmax maximum normalized frequency value the loop can achieve 00148 * \param mu initial parameter for the interpolator [0,1] 00149 * \param gain_mu gain parameter of the M&M error signal to adjust mu (~0.05) 00150 * \param omega initial value for the number of symbols between samples (~number of samples/symbol) 00151 * \param gain_omega gain parameter to adjust omega based on the error (~omega^2/4) 00152 * \param omega_rel sets the maximum (omega*(1+omega_rel)) and minimum (omega*(1+omega_rel)) omega (~0.005) 00153 * 00154 * The constructor also chooses which phase detector and decision maker to use in the work loop based on the 00155 * value of M. 00156 */ 00157 digital_mpsk_receiver_cc (unsigned int M, float theta, 00158 float loop_bw, 00159 float fmin, float fmax, 00160 float mu, float gain_mu, 00161 float omega, float gain_omega, float omega_rel); 00162 00163 void make_constellation(); 00164 void mm_sampler(const gr_complex symbol); 00165 void mm_error_tracking(gr_complex sample); 00166 void phase_error_tracking(gr_complex sample); 00167 00168 00169 /*! 00170 * \brief Phase error detector for MPSK modulations. 00171 * 00172 * \param sample the I&Q sample from which to determine the phase error 00173 * 00174 * This function determines the phase error for any MPSK signal by 00175 * creating a set of PSK constellation points and doing a 00176 * brute-force search to see which point minimizes the Euclidean 00177 * distance. This point is then used to derotate the sample to the 00178 * real-axis and a atan (using the fast approximation function) to 00179 * determine the phase difference between the incoming sample and 00180 * the real constellation point 00181 * 00182 * This should be cleaned up and made more efficient. 00183 * 00184 * \returns the approximated phase error. 00185 */ 00186 float phase_error_detector_generic(gr_complex sample) const; // generic for M but more costly 00187 00188 /*! 00189 * \brief Phase error detector for BPSK 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 a simple BPSK 00194 * phase error detector by multiplying the real and imaginary (the 00195 * error signal) components together. As the imaginary part goes to 00196 * 0, so does this error. 00197 * 00198 * \returns the approximated phase error. 00199 */ 00200 float phase_error_detector_bpsk(gr_complex sample) const; // optimized for BPSK 00201 00202 /*! 00203 * \brief Phase error detector for QPSK modulation. 00204 * 00205 * \param sample the I&Q sample from which to determine the phase error 00206 * 00207 * This function determines the phase error using the limiter 00208 * approach in a standard 4th order Costas loop 00209 * 00210 * \returns the approximated phase error. 00211 */ 00212 float phase_error_detector_qpsk(gr_complex sample) const; 00213 00214 00215 00216 /*! 00217 * \brief Decision maker for a generic MPSK constellation. 00218 * 00219 * \param sample the baseband I&Q sample from which to make the decision 00220 * 00221 * This decision maker is a generic implementation that does a 00222 * brute-force search for the constellation point that minimizes the 00223 * error between it and the incoming signal. 00224 * 00225 * \returns the index to d_constellation that minimizes the error/ 00226 */ 00227 unsigned int decision_generic(gr_complex sample) const; 00228 00229 00230 /*! 00231 * \brief Decision maker for BPSK constellation. 00232 * 00233 * \param sample the baseband I&Q sample from which to make the decision 00234 * 00235 * This decision maker is a simple slicer function that makes a 00236 * decision on the symbol based on its placement on the real axis of 00237 * greater than 0 or less than 0; the quadrature component is always 00238 * 0. 00239 * 00240 * \returns the index to d_constellation that minimizes the error/ 00241 */ 00242 unsigned int decision_bpsk(gr_complex sample) const; 00243 00244 00245 /*! 00246 * \brief Decision maker for QPSK constellation. 00247 * 00248 * \param sample the baseband I&Q sample from which to make the decision 00249 * 00250 * This decision maker is a simple slicer function that makes a 00251 * decision on the symbol based on its placement versus both axes 00252 * and returns which quadrant the symbol is in. 00253 * 00254 * \returns the index to d_constellation that minimizes the error/ 00255 */ 00256 unsigned int decision_qpsk(gr_complex sample) const; 00257 00258 private: 00259 unsigned int d_M; 00260 float d_theta; 00261 00262 /*! 00263 * \brief Decision maker function pointer 00264 * 00265 * \param sample the baseband I&Q sample from which to make the decision 00266 * 00267 * This is a function pointer that is set in the constructor to 00268 * point to the proper decision function for the specified 00269 * constellation order. 00270 * 00271 * \return index into d_constellation point that is the closest to the recieved sample 00272 */ 00273 unsigned int (digital_mpsk_receiver_cc::*d_decision)(gr_complex sample) const; // pointer to decision function 00274 00275 00276 std::vector<gr_complex> d_constellation; 00277 unsigned int d_current_const_point; 00278 00279 // Members related to symbol timing 00280 float d_mu, d_gain_mu; 00281 float d_omega, d_gain_omega, d_omega_rel, d_max_omega, d_min_omega, d_omega_mid; 00282 gr_complex d_p_2T, d_p_1T, d_p_0T; 00283 gr_complex d_c_2T, d_c_1T, d_c_0T; 00284 00285 /*! 00286 * \brief Phase error detector function pointer 00287 * 00288 * \param sample the I&Q sample from which to determine the phase error 00289 * 00290 * This is a function pointer that is set in the constructor to 00291 * point to the proper phase error detector function for the 00292 * specified constellation order. 00293 */ 00294 float (digital_mpsk_receiver_cc::*d_phase_error_detector)(gr_complex sample) const; 00295 00296 00297 //! get interpolated value 00298 gri_mmse_fir_interpolator_cc *d_interp; 00299 00300 //! delay line length. 00301 static const unsigned int DLLEN = 8; 00302 00303 //! delay line plus some length for overflow protection 00304 __GR_ATTR_ALIGNED(8) gr_complex d_dl[2*DLLEN]; 00305 00306 //! index to delay line 00307 unsigned int d_dl_idx; 00308 00309 friend DIGITAL_API digital_mpsk_receiver_cc_sptr 00310 digital_make_mpsk_receiver_cc (unsigned int M, float theta, 00311 float loop_bw, 00312 float fmin, float fmax, 00313 float mu, float gain_mu, 00314 float omega, float gain_omega, float omega_rel); 00315 }; 00316 00317 #endif