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