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