// create firpfb from external coefficients // _M : number of filters in the bank // _h : coefficients [size: _M*_h_len x 1] // _h_len : filter delay (symbols) FIRPFB() FIRPFB(_create)(unsigned int _M, TC * _h, unsigned int _h_len) { // validate input if (_M == 0) { fprintf(stderr,"error: firpfb_%s_create(), number of filters must be greater than zero\n", EXTENSION_FULL); exit(1); } else if (_h_len == 0) { fprintf(stderr,"error: firpfb_%s_create(), filter length must be greater than zero\n", EXTENSION_FULL); exit(1); } // create main filter object FIRPFB() q = (FIRPFB()) malloc(sizeof(struct FIRPFB(_s))); // set user-defined parameters q->num_filters = _M; q->h_len = _h_len; // each filter is realized as a dotprod object q->dp = (DOTPROD()*) malloc((q->num_filters)*sizeof(DOTPROD())); // generate bank of sub-samped filters // length of each sub-sampled filter unsigned int h_sub_len = _h_len / q->num_filters; TC h_sub[h_sub_len]; unsigned int i, n; for (i=0; i<q->num_filters; i++) { for (n=0; n<h_sub_len; n++) { // load filter in reverse order h_sub[h_sub_len-n-1] = _h[i + n*(q->num_filters)]; } // create dot product object q->dp[i] = DOTPROD(_create)(h_sub,h_sub_len); } // save sub-sampled filter length q->h_sub_len = h_sub_len; // create window buffer q->w = WINDOW(_create)(q->h_sub_len); // set default scaling q->scale = 1; // reset object and return FIRPFB(_reset)(q); return q; }
// create square-root Nyquist filterbank // _type : filter type (e.g. LIQUID_RNYQUIST_RRC) // _M : number of filters in the bank // _k : samples/symbol _k > 1 // _m : filter delay (symbols), _m > 0 // _beta : excess bandwidth factor, 0 < _beta < 1 FIRPFB() FIRPFB(_create_rnyquist)(int _type, unsigned int _M, unsigned int _k, unsigned int _m, float _beta) { // validate input if (_M == 0) { fprintf(stderr,"error: firpfb_%s_create_rnyquist(), number of filters must be greater than zero\n", EXTENSION_FULL); exit(1); } else if (_k < 2) { fprintf(stderr,"error: firpfb_%s_create_rnyquist(), filter samples/symbol must be greater than 1\n", EXTENSION_FULL); exit(1); } else if (_m == 0) { fprintf(stderr,"error: firpfb_%s_create_rnyquist(), filter delay must be greater than 0\n", EXTENSION_FULL); exit(1); } else if (_beta < 0.0f || _beta > 1.0f) { fprintf(stderr,"error: firpfb_%s_create_rnyquist(), filter excess bandwidth factor must be in [0,1]\n", EXTENSION_FULL); exit(1); } // generate square-root Nyquist filter unsigned int H_len = 2*_M*_k*_m + 1; float Hf[H_len]; liquid_firdes_rnyquist(_type,_M*_k,_m,_beta,0,Hf); // copy coefficients to type-specific array (e.g. float complex) unsigned int i; TC Hc[H_len]; for (i=0; i<H_len; i++) Hc[i] = Hf[i]; // return filterbank object return FIRPFB(_create)(_M, Hc, H_len); }
// create arbitrary resampler // _rate : resampling rate // _m : prototype filter semi-length // _fc : prototype filter cutoff frequency, fc in (0, 0.5) // _As : prototype filter stop-band attenuation [dB] (e.g. 60) // _npfb : number of filters in polyphase filterbank RESAMP() RESAMP(_create)(float _rate, unsigned int _m, float _fc, float _As, unsigned int _npfb) { // validate input if (_rate <= 0) { fprintf(stderr,"error: resamp_%s_create(), resampling rate must be greater than zero\n", EXTENSION_FULL); exit(1); } else if (_m == 0) { fprintf(stderr,"error: resamp_%s_create(), filter semi-length must be greater than zero\n", EXTENSION_FULL); exit(1); } else if (_fc <= 0.0f || _fc >= 0.5f) { fprintf(stderr,"error: resamp_%s_create(), filter cutoff must be in (0,0.5)\n", EXTENSION_FULL); exit(1); } else if (_As <= 0.0f) { fprintf(stderr,"error: resamp_%s_create(), filter stop-band suppression must be greater than zero\n", EXTENSION_FULL); exit(1); } else if (_npfb == 0) { fprintf(stderr,"error: resamp_%s_create(), number of filter banks must be greater than zero\n", EXTENSION_FULL); exit(1); } // allocate memory for resampler RESAMP() q = (RESAMP()) malloc(sizeof(struct RESAMP(_s))); // set rate using formal method (specifies output stride // value 'del') RESAMP(_set_rate)(q, _rate); // set properties q->m = _m; // prototype filter semi-length q->fc = _fc; // prototype filter cutoff frequency q->As = _As; // prototype filter stop-band attenuation q->npfb = _npfb; // number of filters in bank // design filter unsigned int n = 2*q->m*q->npfb+1; float hf[n]; TC h[n]; liquid_firdes_kaiser(n,q->fc/((float)(q->npfb)),q->As,0.0f,hf); // normalize filter coefficients by DC gain unsigned int i; float gain=0.0f; for (i=0; i<n; i++) gain += hf[i]; gain = (q->npfb)/(gain); // copy to type-specific array, applying gain for (i=0; i<n; i++) h[i] = hf[i]*gain; q->f = FIRPFB(_create)(q->npfb,h,n-1); // reset object and return RESAMP(_reset)(q); return q; }
// create firpfb derivative square-root Nyquist filterbank // _type : filter type (e.g. LIQUID_RNYQUIST_RRC) // _M : number of filters in the bank // _k : samples/symbol _k > 1 // _m : filter delay (symbols), _m > 0 // _beta : excess bandwidth factor, 0 < _beta < 1 FIRPFB() FIRPFB(_create_drnyquist)(int _type, unsigned int _M, unsigned int _k, unsigned int _m, float _beta) { // validate input if (_M == 0) { fprintf(stderr,"error: firpfb_%s_create_drnyquist(), number of filters must be greater than zero\n", EXTENSION_FULL); exit(1); } else if (_k < 2) { fprintf(stderr,"error: firpfb_%s_create_drnyquist(), filter samples/symbol must be greater than 1\n", EXTENSION_FULL); exit(1); } else if (_m == 0) { fprintf(stderr,"error: firpfb_%s_create_drnyquist(), filter delay must be greater than 0\n", EXTENSION_FULL); exit(1); } else if (_beta < 0.0f || _beta > 1.0f) { fprintf(stderr,"error: firpfb_%s_create_drnyquist(), filter excess bandwidth factor must be in [0,1]\n", EXTENSION_FULL); exit(1); } // generate square-root Nyquist filter unsigned int H_len = 2*_M*_k*_m + 1; float Hf[H_len]; liquid_firdes_rnyquist(_type,_M*_k,_m,_beta,0,Hf); // compute derivative filter float dHf[H_len]; float HdH_max = 0.0f; unsigned int i; for (i=0; i<H_len; i++) { if (i==0) { dHf[i] = Hf[i+1] - Hf[H_len-1]; } else if (i==H_len-1) { dHf[i] = Hf[0] - Hf[i-1]; } else { dHf[i] = Hf[i+1] - Hf[i-1]; } // find maximum of h*dh if ( fabsf(Hf[i]*dHf[i]) > HdH_max ) HdH_max = fabsf(Hf[i]*dHf[i]); } // copy coefficients to type-specific array (e.g. float complex) // and apply scaling factor for normalized response TC Hc[H_len]; for (i=0; i<H_len; i++) Hc[i] = dHf[i] * 0.06f / HdH_max; // return filterbank object return FIRPFB(_create)(_M, Hc, H_len); }
// create synchronizer object from external coefficients // _k : samples per symbol // _M : number of filters in the bank // _h : matched filter coefficients // _h_len : length of matched filter SYMSYNC() SYMSYNC(_create)(unsigned int _k, unsigned int _M, TC * _h, unsigned int _h_len) { // validate input if (_k < 2) { fprintf(stderr,"error: symsync_%s_create(), input sample rate must be at least 2\n", EXTENSION_FULL); exit(1); } else if (_h_len == 0) { fprintf(stderr,"error: symsync_%s_create(), filter length must be greater than zero\n", EXTENSION_FULL); exit(1); } else if (_M == 0) { fprintf(stderr,"error: symsync_%s_create(), number of filter banks must be greater than zero\n", EXTENSION_FULL); exit(1); } SYMSYNC() q = (SYMSYNC()) malloc(sizeof(struct SYMSYNC(_s))); q->k = _k; q->M = _M; q->tau = 0.0f; q->bf = 0.0f; q->b = 0; // set output rate (nominally 1, full decimation) SYMSYNC(_set_output_rate)(q, 1); // TODO: validate length q->h_len = (_h_len-1)/q->M; // compute derivative filter TC dh[_h_len]; float hdh_max = 0.0f; unsigned int i; for (i=0; i<_h_len; i++) { if (i==0) { dh[i] = _h[i+1] - _h[_h_len-1]; } else if (i==_h_len-1) { dh[i] = _h[0] - _h[i-1]; } else { dh[i] = _h[i+1] - _h[i-1]; } // find maximum of h*dh if ( fabsf(_h[i]*dh[i]) > hdh_max || i==0 ) hdh_max = fabsf(_h[i]*dh[i]); } // apply scaling factor for normalized response // TODO: scale to 1.0 for consistency for (i=0; i<_h_len; i++) dh[i] *= 0.06f / hdh_max; q->mf = FIRPFB(_create)(q->M, _h, _h_len); q->dmf = FIRPFB(_create)(q->M, dh, _h_len); // reset state and initialize loop filter q->A[0] = 1.0f; q->B[0] = 0.0f; q->A[1] = 0.0f; q->B[1] = 0.0f; q->A[2] = 0.0f; q->B[2] = 0.0f; q->pll = iirfiltsos_rrrf_create(q->B, q->A); SYMSYNC(_reset)(q); SYMSYNC(_set_lf_bw)(q, 0.01f); // set output rate nominally at 1 sample/symbol (full decimation) SYMSYNC(_set_output_rate)(q, 1); // unlock loop control SYMSYNC(_unlock)(q); #if DEBUG_SYMSYNC q->debug_del = windowf_create(DEBUG_BUFFER_LEN); q->debug_tau = windowf_create(DEBUG_BUFFER_LEN); q->debug_bsoft = windowf_create(DEBUG_BUFFER_LEN); q->debug_b = windowf_create(DEBUG_BUFFER_LEN); q->debug_q_hat = windowf_create(DEBUG_BUFFER_LEN); #endif // return main object return q; }
// and apply scaling factor for normalized response TC Hc[H_len]; for (i=0; i<H_len; i++) Hc[i] = dHf[i] * 0.06f / HdH_max; // return filterbank object return FIRPFB(_create)(_M, Hc, H_len); } // re-create filterbank object // _q : original firpfb object // _M : number of filters in the bank // _h : coefficients [size: _M x _h_len] // _h_len : length of each filter FIRPFB() FIRPFB(_recreate)(FIRPFB() _q, unsigned int _M, TC * _h, unsigned int _h_len) { // check to see if filter length has changed if (_h_len != _q->h_len || _M != _q->num_filters) { // filter length has changed: recreate entire filter FIRPFB(_destroy)(_q); _q = FIRPFB(_create)(_M,_h,_h_len); return _q; } // re-create each dotprod object TC h_sub[_q->h_sub_len]; unsigned int i, n;
RESAMP() RESAMP(_create)(float _r, unsigned int _h_len, float _fc, float _As, unsigned int _npfb) { // validate input if (_r <= 0) { fprintf(stderr,"error: resamp_%s_create(), resampling rate must be greater than zero\n", EXTENSION_FULL); exit(1); } else if (_h_len == 0) { fprintf(stderr,"error: resamp_%s_create(), filter length must be greater than zero\n", EXTENSION_FULL); exit(1); } else if (_npfb == 0) { fprintf(stderr,"error: resamp_%s_create(), number of filter banks must be greater than zero\n", EXTENSION_FULL); exit(1); } else if (_fc <= 0.0f || _fc >= 0.5f) { fprintf(stderr,"error: resamp_%s_create(), filter cutoff must be in (0,0.5)\n", EXTENSION_FULL); exit(1); } else if (_As <= 0.0f) { fprintf(stderr,"error: resamp_%s_create(), filter stop-band suppression must be greater than zero\n", EXTENSION_FULL); exit(1); } RESAMP() q = (RESAMP()) malloc(sizeof(struct RESAMP(_s))); q->r = _r; q->As = _As; q->fc = _fc; q->h_len = _h_len; q->b = 0; q->del = 1.0f / q->r; #if RESAMP_USE_FIXED_POINT_PHASE q->num_bits_npfb = liquid_nextpow2(_npfb); q->npfb = 1<<q->num_bits_npfb; q->num_bits_phase = 20; q->max_phase = 1 << q->num_bits_phase; q->num_shift_bits = q->num_bits_phase - q->num_bits_npfb; q->theta = 0; q->d_theta = (unsigned int)( q->max_phase * q->del ); #else q->npfb = _npfb; q->tau = 0.0f; q->bf = 0.0f; #endif // design filter unsigned int n = 2*_h_len*q->npfb+1; float hf[n]; TC h[n]; liquid_firdes_kaiser(n,q->fc/((float)(q->npfb)),q->As,0.0f,hf); // normalize filter coefficients by DC gain unsigned int i; float gain=0.0f; for (i=0; i<n; i++) gain += hf[i]; gain = (q->npfb)/(gain); // copy to type-specific array for (i=0; i<n; i++) h[i] = hf[i]*gain; q->f = FIRPFB(_create)(q->npfb,h,n-1); //for (i=0; i<n; i++) // PRINTVAL_TC(h[i],%12.8f); //exit(0); return q; }