GNU Radio 3.5.3.2 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 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 //! Returns the modulation order (M) currently set 00095 float modulation_order() const { return d_M; } 00096 00097 //! Returns current value of theta 00098 float theta() const { return d_theta; } 00099 00100 //! Returns current value of mu 00101 float mu() const { return d_mu; } 00102 00103 //! Returns current value of omega 00104 float omega() const { return d_omega; } 00105 00106 //! Returns mu gain factor 00107 float gain_mu() const { return d_gain_mu; } 00108 00109 //! Returns omega gain factor 00110 float gain_omega() const { return d_gain_omega; } 00111 00112 //! Returns the relative omega limit 00113 float gain_omega_rel() const {return d_omega_rel; } 00114 00115 //! Sets the modulation order (M) currently 00116 void set_modulation_order(unsigned int M); 00117 00118 //! Sets value of theta 00119 void set_theta(float theta) { d_theta = theta; } 00120 00121 //! Sets value of mu 00122 void set_mu (float mu) { d_mu = mu; } 00123 00124 //! Sets value of omega and its min and max values 00125 void set_omega (float omega) { 00126 d_omega = omega; 00127 d_min_omega = omega*(1.0 - d_omega_rel); 00128 d_max_omega = omega*(1.0 + d_omega_rel); 00129 d_omega_mid = 0.5*(d_min_omega+d_max_omega); 00130 } 00131 00132 //! Sets value for mu gain factor 00133 void set_gain_mu (float gain_mu) { d_gain_mu = gain_mu; } 00134 00135 //! Sets value for omega gain factor 00136 void set_gain_omega (float gain_omega) { d_gain_omega = gain_omega; } 00137 00138 //! Sets the relative omega limit and resets omega min/max values 00139 void set_gain_omega_rel(float omega_rel); 00140 00141 protected: 00142 00143 /*! 00144 * \brief Constructor to synchronize incoming M-PSK symbols 00145 * 00146 * \param M modulation order of the M-PSK modulation 00147 * \param theta any constant phase rotation from the real axis of the constellation 00148 * \param loop_bw Loop bandwidth to set gains of phase/freq tracking loop 00149 * \param fmin minimum normalized frequency value the loop can achieve 00150 * \param fmax maximum normalized frequency value the loop can achieve 00151 * \param mu initial parameter for the interpolator [0,1] 00152 * \param gain_mu gain parameter of the M&M error signal to adjust mu (~0.05) 00153 * \param omega initial value for the number of symbols between samples (~number of samples/symbol) 00154 * \param gain_omega gain parameter to adjust omega based on the error (~omega^2/4) 00155 * \param omega_rel sets the maximum (omega*(1+omega_rel)) and minimum (omega*(1+omega_rel)) omega (~0.005) 00156 * 00157 * The constructor also chooses which phase detector and decision maker to use in the work loop based on the 00158 * value of M. 00159 */ 00160 digital_mpsk_receiver_cc (unsigned int M, float theta, 00161 float loop_bw, 00162 float fmin, float fmax, 00163 float mu, float gain_mu, 00164 float omega, float gain_omega, float omega_rel); 00165 00166 void make_constellation(); 00167 void mm_sampler(const gr_complex symbol); 00168 void mm_error_tracking(gr_complex sample); 00169 void phase_error_tracking(gr_complex sample); 00170 00171 00172 /*! 00173 * \brief Phase error detector for MPSK modulations. 00174 * 00175 * \param sample the I&Q sample from which to determine the phase error 00176 * 00177 * This function determines the phase error for any MPSK signal by 00178 * creating a set of PSK constellation points and doing a 00179 * brute-force search to see which point minimizes the Euclidean 00180 * distance. This point is then used to derotate the sample to the 00181 * real-axis and a atan (using the fast approximation function) to 00182 * determine the phase difference between the incoming sample and 00183 * the real constellation point 00184 * 00185 * This should be cleaned up and made more efficient. 00186 * 00187 * \returns the approximated phase error. 00188 */ 00189 float phase_error_detector_generic(gr_complex sample) const; // generic for M but more costly 00190 00191 /*! 00192 * \brief Phase error detector for BPSK modulation. 00193 * 00194 * \param sample the I&Q sample from which to determine the phase error 00195 * 00196 * This function determines the phase error using a simple BPSK 00197 * phase error detector by multiplying the real and imaginary (the 00198 * error signal) components together. As the imaginary part goes to 00199 * 0, so does this error. 00200 * 00201 * \returns the approximated phase error. 00202 */ 00203 float phase_error_detector_bpsk(gr_complex sample) const; // optimized for BPSK 00204 00205 /*! 00206 * \brief Phase error detector for QPSK modulation. 00207 * 00208 * \param sample the I&Q sample from which to determine the phase error 00209 * 00210 * This function determines the phase error using the limiter 00211 * approach in a standard 4th order Costas loop 00212 * 00213 * \returns the approximated phase error. 00214 */ 00215 float phase_error_detector_qpsk(gr_complex sample) const; 00216 00217 00218 00219 /*! 00220 * \brief Decision maker for a generic MPSK constellation. 00221 * 00222 * \param sample the baseband I&Q sample from which to make the decision 00223 * 00224 * This decision maker is a generic implementation that does a 00225 * brute-force search for the constellation point that minimizes the 00226 * error between it and the incoming signal. 00227 * 00228 * \returns the index to d_constellation that minimizes the error/ 00229 */ 00230 unsigned int decision_generic(gr_complex sample) const; 00231 00232 00233 /*! 00234 * \brief Decision maker for BPSK constellation. 00235 * 00236 * \param sample the baseband I&Q sample from which to make the decision 00237 * 00238 * This decision maker is a simple slicer function that makes a 00239 * decision on the symbol based on its placement on the real axis of 00240 * greater than 0 or less than 0; the quadrature component is always 00241 * 0. 00242 * 00243 * \returns the index to d_constellation that minimizes the error/ 00244 */ 00245 unsigned int decision_bpsk(gr_complex sample) const; 00246 00247 00248 /*! 00249 * \brief Decision maker for QPSK constellation. 00250 * 00251 * \param sample the baseband I&Q sample from which to make the decision 00252 * 00253 * This decision maker is a simple slicer function that makes a 00254 * decision on the symbol based on its placement versus both axes 00255 * and returns which quadrant the symbol is in. 00256 * 00257 * \returns the index to d_constellation that minimizes the error/ 00258 */ 00259 unsigned int decision_qpsk(gr_complex sample) const; 00260 00261 private: 00262 unsigned int d_M; 00263 float d_theta; 00264 00265 /*! 00266 * \brief Decision maker function pointer 00267 * 00268 * \param sample the baseband I&Q sample from which to make the decision 00269 * 00270 * This is a function pointer that is set in the constructor to 00271 * point to the proper decision function for the specified 00272 * constellation order. 00273 * 00274 * \return index into d_constellation point that is the closest to the recieved sample 00275 */ 00276 unsigned int (digital_mpsk_receiver_cc::*d_decision)(gr_complex sample) const; // pointer to decision function 00277 00278 00279 std::vector<gr_complex> d_constellation; 00280 unsigned int d_current_const_point; 00281 00282 // Members related to symbol timing 00283 float d_mu, d_gain_mu; 00284 float d_omega, d_gain_omega, d_omega_rel, d_max_omega, d_min_omega, d_omega_mid; 00285 gr_complex d_p_2T, d_p_1T, d_p_0T; 00286 gr_complex d_c_2T, d_c_1T, d_c_0T; 00287 00288 /*! 00289 * \brief Phase error detector function pointer 00290 * 00291 * \param sample the I&Q sample from which to determine the phase error 00292 * 00293 * This is a function pointer that is set in the constructor to 00294 * point to the proper phase error detector function for the 00295 * specified constellation order. 00296 */ 00297 float (digital_mpsk_receiver_cc::*d_phase_error_detector)(gr_complex sample) const; 00298 00299 00300 //! get interpolated value 00301 gri_mmse_fir_interpolator_cc *d_interp; 00302 00303 //! delay line length. 00304 static const unsigned int DLLEN = 8; 00305 00306 //! delay line plus some length for overflow protection 00307 __GR_ATTR_ALIGNED(8) gr_complex d_dl[2*DLLEN]; 00308 00309 //! index to delay line 00310 unsigned int d_dl_idx; 00311 00312 friend DIGITAL_API digital_mpsk_receiver_cc_sptr 00313 digital_make_mpsk_receiver_cc (unsigned int M, float theta, 00314 float loop_bw, 00315 float fmin, float fmax, 00316 float mu, float gain_mu, 00317 float omega, float gain_omega, float omega_rel); 00318 }; 00319 00320 #endif