⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gr_mpsk_receiver_cc.cc

📁 这是用python语言写的一个数字广播的信号处理工具包。利用它
💻 CC
字号:
/* -*- c++ -*- *//* * Copyright 2005,2006,2007 Free Software Foundation, Inc. * * This file is part of GNU Radio * * GNU Radio is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * GNU Radio is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Radio; see the file COPYING.  If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <gr_io_signature.h>#include <gr_prefs.h>#include <gr_mpsk_receiver_cc.h>#include <stdexcept>#include <gr_math.h>#include <gr_expj.h>#include <gri_mmse_fir_interpolator_cc.h>#define M_TWOPI (2*M_PI)#define VERBOSE_MM     0     // Used for debugging symbol timing loop#define VERBOSE_COSTAS 0     // Used for debugging phase and frequency tracking// Public constructorgr_mpsk_receiver_cc_sptr gr_make_mpsk_receiver_cc(unsigned int M, float theta,			 float alpha, float beta,			 float fmin, float fmax,			 float mu, float gain_mu, 			 float omega, float gain_omega, float omega_rel){  return gr_mpsk_receiver_cc_sptr (new gr_mpsk_receiver_cc (M, theta, 							    alpha, beta,							    fmin, fmax,							    mu, gain_mu, 							    omega, gain_omega, omega_rel));}gr_mpsk_receiver_cc::gr_mpsk_receiver_cc (unsigned int M, float theta, 					  float alpha, float beta,					  float fmin, float fmax,					  float mu, float gain_mu, 					  float omega, float gain_omega, float omega_rel)  : gr_block ("mpsk_receiver_cc",	      gr_make_io_signature (1, 1, sizeof (gr_complex)),	      gr_make_io_signature (1, 1, sizeof (gr_complex))),    d_M(M), d_theta(theta),     d_alpha(alpha), d_beta(beta), d_freq(0), d_max_freq(fmax), d_min_freq(fmin), d_phase(0),    d_current_const_point(0),    d_mu(mu), d_gain_mu(gain_mu), d_gain_omega(gain_omega),     d_omega_rel(omega_rel), d_max_omega(0), d_min_omega(0),    d_p_2T(0), d_p_1T(0), d_p_0T(0), d_c_2T(0), d_c_1T(0), d_c_0T(0){  d_interp = new gri_mmse_fir_interpolator_cc();  d_dl_idx = 0;  set_omega(omega);  if (omega <= 0.0)    throw std::out_of_range ("clock rate must be > 0");  if (gain_mu <  0  || gain_omega < 0)    throw std::out_of_range ("Gains must be non-negative");    assert(d_interp->ntaps() <= DLLEN);    // zero double length delay line.  for (unsigned int i = 0; i < 2 * DLLEN; i++)    d_dl[i] = gr_complex(0.0,0.0);  // build the constellation vector from M  make_constellation();    // Select a phase detector and a decision maker for the modulation order  switch(d_M) {  case 2:  // optimized algorithms for BPSK    d_phase_error_detector = &gr_mpsk_receiver_cc::phase_error_detector_generic; //bpsk;    d_decision = &gr_mpsk_receiver_cc::decision_generic; //bpsk;    break;  case 4: // optimized algorithms for QPSK    d_phase_error_detector = &gr_mpsk_receiver_cc::phase_error_detector_generic; //qpsk;    d_decision = &gr_mpsk_receiver_cc::decision_generic; //qpsk;    break;  default: // generic algorithms for any M (power of 2?) but not pretty    d_phase_error_detector = &gr_mpsk_receiver_cc::phase_error_detector_generic;    d_decision = &gr_mpsk_receiver_cc::decision_generic;    break;  }  set_history(3);			// ensure 2 extra input sample is available}gr_mpsk_receiver_cc::~gr_mpsk_receiver_cc (){  delete d_interp;}voidgr_mpsk_receiver_cc::forecast(int noutput_items, gr_vector_int &ninput_items_required){  unsigned ninputs = ninput_items_required.size();  for (unsigned i=0; i < ninputs; i++)    ninput_items_required[i] = (int) ceil((noutput_items * d_omega) + d_interp->ntaps());  //ninput_items_required[i] = (int)(d_omega);}// FIXME add these back in an test difference in performancefloatgr_mpsk_receiver_cc::phase_error_detector_qpsk(gr_complex sample) const{  float phase_error = ((sample.real()>0 ? 1.0 : -1.0) * sample.imag() -		       (sample.imag()>0 ? 1.0 : -1.0) * sample.real());  return -phase_error;}// FIXME add these back in an test difference in performancefloatgr_mpsk_receiver_cc::phase_error_detector_bpsk(gr_complex sample) const{  return (sample.real()*sample.imag());}float gr_mpsk_receiver_cc::phase_error_detector_generic(gr_complex sample) const{  //return gr_fast_atan2f(sample*conj(d_constellation[d_current_const_point]));  return -arg(sample*conj(d_constellation[d_current_const_point]));}// FIXME add these back in an test difference in performanceunsigned intgr_mpsk_receiver_cc::decision_bpsk(gr_complex sample) const{  unsigned int index = 0;  // Implements a 1-demensional slicer  if(sample.real() > 0)    index = 1;  return index;}// FIXME add these back in an test difference in performanceunsigned intgr_mpsk_receiver_cc::decision_qpsk(gr_complex sample) const{  unsigned int index = 0;  // Implements a simple slicer function  if((sample.real() < 0) && (sample.imag() > 0))    index = 1;  else if((sample.real() < 0) && (sample.imag() < 0))    index = 2;  else    index = 3;  return index;}unsigned intgr_mpsk_receiver_cc::decision_generic(gr_complex sample) const{  unsigned int min_m = 0;  float min_s = 65535;    // Develop all possible constellation points and find the one that minimizes  // the Euclidean distance (error) with the sample  for(unsigned int m=0; m < d_M; m++) {    gr_complex diff = norm(d_constellation[m] - sample);        if(fabs(diff.real()) < min_s) {      min_s = fabs(diff.real());      min_m = m;    }  }  // Return the index of the constellation point that minimizes the error  return min_m;}voidgr_mpsk_receiver_cc::make_constellation(){  for(unsigned int m=0; m < d_M; m++) {    d_constellation.push_back(gr_expj((M_TWOPI/d_M)*m));  }}voidgr_mpsk_receiver_cc::mm_sampler(const gr_complex symbol){  gr_complex sample, nco;  d_mu--;             // skip a number of symbols between sampling  d_phase += d_freq;  // increment the phase based on the frequency of the rotation  // Keep phase clamped and not walk to infinity  while(d_phase>M_TWOPI)    d_phase -= M_TWOPI;  while(d_phase<-M_TWOPI)    d_phase += M_TWOPI;  nco = gr_expj(d_phase+d_theta);   // get the NCO value for derotating the current sample  sample = nco*symbol;      // get the downconverted symbol    // Fill up the delay line for the interpolator  d_dl[d_dl_idx] = sample;  d_dl[(d_dl_idx + DLLEN)] = sample;  // put this in the second half of the buffer for overflows  d_dl_idx = (d_dl_idx+1) % DLLEN;    // Keep the delay line index in bounds}voidgr_mpsk_receiver_cc::mm_error_tracking(gr_complex sample){  gr_complex u, x, y;  float mm_error = 0;  // Make sample timing corrections  // set the delayed samples  d_p_2T = d_p_1T;  d_p_1T = d_p_0T;  d_p_0T = sample;  d_c_2T = d_c_1T;  d_c_1T = d_c_0T;    d_current_const_point = (*this.*d_decision)(d_p_0T);  // make a decision on the sample value  d_c_0T = d_constellation[d_current_const_point];    x = (d_c_0T - d_c_2T) * conj(d_p_1T);  y = (d_p_0T - d_p_2T) * conj(d_c_1T);  u = y - x;  mm_error = u.real();   // the error signal is in the real part    // limit mm_val  if (mm_error > 1.0)    mm_error = 1.0;  else if (mm_error < -1.0)    mm_error = -1.0;    d_omega = d_omega + d_gain_omega * mm_error;  // update omega based on loop error  // make sure we don't walk away  if (d_omega > d_max_omega)    d_omega = d_max_omega;  else if (d_omega < d_min_omega)    d_omega = d_min_omega;    d_mu += d_omega + d_gain_mu * mm_error;   // update mu based on loop error  #if VERBOSE_MM  printf("mm: mu: %f   omega: %f  mm_error: %f  sample: %f+j%f  constellation: %f+j%f\n", 	 d_mu, d_omega, mm_error, sample.real(), sample.imag(), 	 d_constellation[d_current_const_point].real(), d_constellation[d_current_const_point].imag());#endif}voidgr_mpsk_receiver_cc::phase_error_tracking(gr_complex sample){  float phase_error = 0;  // Make phase and frequency corrections based on sampled value  phase_error = (*this.*d_phase_error_detector)(sample);  if (phase_error > 1)    phase_error = 1;  else if (phase_error < -1)    phase_error = -1;    d_freq += d_beta*phase_error;             // adjust frequency based on error  d_phase += d_freq + d_alpha*phase_error;  // adjust phase based on error    // Make sure we stay within +-2pi  while(d_phase>M_TWOPI)    d_phase -= M_TWOPI;  while(d_phase<-M_TWOPI)    d_phase += M_TWOPI;    // Limit the frequency range  if (d_freq > d_max_freq)    d_freq = d_max_freq;  else if (d_freq < d_min_freq)    d_freq = d_min_freq;#if VERBOSE_COSTAS  printf("cl: phase_error: %f  phase: %f  freq: %f  sample: %f+j%f  constellation: %f+j%f\n",	 phase_error, d_phase, d_freq, sample.real(), sample.imag(), 	 d_constellation[d_current_const_point].real(), d_constellation[d_current_const_point].imag());#endif}intgr_mpsk_receiver_cc::general_work (int noutput_items,				   gr_vector_int &ninput_items,				   gr_vector_const_void_star &input_items,				   gr_vector_void_star &output_items){  const gr_complex *in = (const gr_complex *) input_items[0];  gr_complex *out = (gr_complex *) output_items[0];  int i=0, o=0;  //while(i < ninput_items[0]) {      while((o < noutput_items) && (i < ninput_items[0])) {    while((d_mu > 1) && (i < ninput_items[0]))  {      mm_sampler(in[i]);   // puts symbols into a buffer and adjusts d_mu      i++;    }        if(i < ninput_items[0]) {      gr_complex interp_sample = d_interp->interpolate(&d_dl[d_dl_idx], d_mu);             mm_error_tracking(interp_sample);     // corrects M&M sample time      phase_error_tracking(interp_sample);  // corrects phase and frequency offsets      out[o++] = interp_sample;    }  }  #if 0  printf("ninput_items: %d   noutput_items: %d   consuming: %d   returning: %d\n",	 ninput_items[0], noutput_items, i, o);  #endif  consume_each(i);  return o;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -