// compute filter coefficients and determine resulting ISI // // _k : filter over-sampling rate (samples/symbol) // _m : filter delay (symbols) // _beta : filter excess bandwidth factor (0,1) // _dt : filter fractional sample delay // _rho : transition bandwidth adjustment, 0 < _rho < 1 // _h : filter buffer [size: 2*_k*_m+1] float liquid_firdes_rkaiser_internal_isi(unsigned int _k, unsigned int _m, float _beta, float _dt, float _rho, float * _h) { // validate input if (_rho < 0.0f) { fprintf(stderr,"warning: liquid_firdes_rkaiser_internal_isi(), rho < 0\n"); } else if (_rho > 1.0f) { fprintf(stderr,"warning: liquid_firdes_rkaiser_internal_isi(), rho > 1\n"); } unsigned int n=2*_k*_m+1; // filter length float kf = (float)_k; // samples/symbol (float) float del = _beta*_rho / kf; // transition bandwidth float As = estimate_req_filter_As(del, n); // stop-band suppression float fc = 0.5f*(1 + _beta*(1.0f-_rho))/kf; // filter cutoff // evaluate performance (ISI) float isi_max; float isi_rms; // compute filter liquid_firdes_kaiser(n,fc,As,_dt,_h); // compute filter ISI liquid_filter_isi(_h,_k,_m,&isi_rms,&isi_max); // return RMS of ISI return isi_rms; }
// Design frequency-shifted root-Nyquist filter based on // the Kaiser-windowed sinc using approximation for rho. // // _k : filter over-sampling rate (samples/symbol) // _m : filter delay (symbols) // _beta : filter excess bandwidth factor (0,1) // _dt : filter fractional sample delay // _h : resulting filter [size: 2*_k*_m+1] void liquid_firdes_arkaiser(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h) { // validate input if (_k < 2) { fprintf(stderr,"error: liquid_firdes_arkaiser(), k must be at least 2\n"); exit(1); } else if (_m < 1) { fprintf(stderr,"error: liquid_firdes_arkaiser(), m must be at least 1\n"); exit(1); } else if (_beta <= 0.0f || _beta >= 1.0f) { fprintf(stderr,"error: liquid_firdes_arkaiser(), beta must be in (0,1)\n"); exit(1); } else if (_dt < -1.0f || _dt > 1.0f) { fprintf(stderr,"error: liquid_firdes_arkaiser(), dt must be in [-1,1]\n"); exit(1); } #if 0 // compute bandwidth adjustment estimate float rho_hat = rkaiser_approximate_rho(_m,_beta); // bandwidth correction factor #else // rho ~ c0 + c1*log(_beta) + c2*log^2(_beta) // c0 ~ 0.762886 + 0.067663*log(m) // c1 ~ 0.065515 // c2 ~ log( 1 - 0.088*m^-1.6 ) float c0 = 0.762886 + 0.067663*logf(_m); float c1 = 0.065515; float c2 = logf( 1 - 0.088*powf(_m,-1.6 ) ); float log_beta = logf(_beta); float rho_hat = c0 + c1*log_beta + c2*log_beta*log_beta; // ensure range is valid if (rho_hat <= 0.0f || rho_hat >= 1.0f) rho_hat = rkaiser_approximate_rho(_m,_beta); #endif unsigned int n=2*_k*_m+1; // filter length float kf = (float)_k; // samples/symbol (float) float del = _beta*rho_hat / kf; // transition bandwidth float As = estimate_req_filter_As(del, n); // stop-band suppression float fc = 0.5f*(1 + _beta*(1.0f-rho_hat))/kf; // filter cutoff #if DEBUG_RKAISER printf("rho-hat : %12.8f (compare to %12.8f)\n", rho_hat, rkaiser_approximate_rho(_m,_beta)); printf("fc : %12.8f\n", fc); printf("delta-f : %12.8f\n", del); printf("As : %12.8f dB\n", As); printf("alpha : %12.8f\n", kaiser_beta_As(As)); #endif // compute filter coefficients liquid_firdes_kaiser(n,fc,As,_dt,_h); // normalize coefficients float e2 = 0.0f; unsigned int i; for (i=0; i<n; i++) e2 += _h[i]*_h[i]; for (i=0; i<n; i++) _h[i] *= sqrtf(_k/e2); }
// Design (root-)Nyquist filter from prototype // _type : filter type (e.g. LIQUID_FIRFILT_RRRC) // _k : samples/symbol // _m : symbol delay // _beta : excess bandwidth factor, _beta in [0,1] // _dt : fractional sample delay // _h : output coefficient buffer (length: 2*k*m+1) void liquid_firdes_prototype(liquid_firfilt_type _type, unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h) { // compute filter parameters unsigned int h_len = 2*_k*_m + 1; // length float fc = 0.5f / (float)_k; // cut-off frequency float df = _beta / (float)_k; // transition bandwidth float As = estimate_req_filter_As(df,h_len); // stop-band attenuation // Parks-McClellan algorithm parameters float bands[6] = { 0.0f, fc-0.5f*df, fc, fc, fc+0.5f*df, 0.5f}; float des[3] = { (float)_k, 0.5f*_k, 0.0f }; float weights[3] = {1.0f, 1.0f, 1.0f}; liquid_firdespm_wtype wtype[3] = { LIQUID_FIRDESPM_FLATWEIGHT, LIQUID_FIRDESPM_FLATWEIGHT, LIQUID_FIRDESPM_FLATWEIGHT}; switch (_type) { // Nyquist filter prototypes case LIQUID_FIRFILT_KAISER: liquid_firdes_kaiser(h_len, fc, As, _dt, _h); break; case LIQUID_FIRFILT_PM: // WARNING: input timing offset is ignored here firdespm_run(h_len, 3, bands, des, weights, wtype, LIQUID_FIRDESPM_BANDPASS, _h); break; case LIQUID_FIRFILT_RCOS: liquid_firdes_rcos(_k, _m, _beta, _dt, _h); break; case LIQUID_FIRFILT_FEXP: liquid_firdes_fexp(_k, _m, _beta, _dt, _h); break; case LIQUID_FIRFILT_FSECH: liquid_firdes_fsech(_k, _m, _beta, _dt, _h); break; case LIQUID_FIRFILT_FARCSECH: liquid_firdes_farcsech(_k, _m, _beta, _dt, _h); break; // root-Nyquist filter prototypes case LIQUID_FIRFILT_ARKAISER: liquid_firdes_arkaiser(_k, _m, _beta, _dt, _h); break; case LIQUID_FIRFILT_RKAISER: liquid_firdes_rkaiser(_k, _m, _beta, _dt, _h); break; case LIQUID_FIRFILT_RRC: liquid_firdes_rrcos(_k, _m, _beta, _dt, _h); break; case LIQUID_FIRFILT_hM3: liquid_firdes_hM3(_k, _m, _beta, _dt, _h); break; case LIQUID_FIRFILT_GMSKTX: liquid_firdes_gmsktx(_k, _m, _beta, _dt, _h); break; case LIQUID_FIRFILT_GMSKRX: liquid_firdes_gmskrx(_k, _m, _beta, _dt, _h); break; case LIQUID_FIRFILT_RFEXP: liquid_firdes_rfexp(_k, _m, _beta, _dt, _h); break; case LIQUID_FIRFILT_RFSECH: liquid_firdes_rfsech(_k, _m, _beta, _dt, _h); break; case LIQUID_FIRFILT_RFARCSECH: liquid_firdes_rfarcsech(_k, _m, _beta, _dt, _h); break; default: fprintf(stderr,"error: liquid_firdes_prototype(), invalid root-Nyquist filter type '%d'\n", _type); exit(1); } }