// 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; }
// create FIR polyphase filterbank channelizer object with // prototype filter based on windowed Kaiser design // _type : channelizer type (LIQUID_ANALYZER | LIQUID_SYNTHESIZER) // _M : number of channels // _m : filter delay (symbols) // _As : stop-band attentuation [dB] FIRPFBCH() FIRPFBCH(_create_kaiser)(int _type, unsigned int _M, unsigned int _m, float _As) { // validate input if (_M == 0) { fprintf(stderr,"error: firpfbch_%s_create_kaiser(), number of channels must be greater than 0\n", EXTENSION_FULL); exit(1); } else if (_m == 0) { fprintf(stderr,"error: firpfbch_%s_create_kaiser(), invalid filter size (must be greater than 0)\n", EXTENSION_FULL); exit(1); } _As = fabsf(_As); // design filter unsigned int h_len = 2*_M*_m + 1; float h[h_len]; float fc = 0.5f / (float)_M; // TODO : check this value liquid_firdes_kaiser(h_len, fc, _As, 0.0f, h); // copy coefficients to type-specfic array TC hc[h_len]; unsigned int i; for (i=0; i<h_len; i++) hc[i] = h[i]; // create filterbank object unsigned int p = 2*_m; FIRPFBCH() q = FIRPFBCH(_create)(_type, _M, p, hc); // return filterbank object return q; }
// create LMS EQ initialized with low-pass filter // _h_len : filter length // _fc : filter cut-off, _fc in (0,0.5] EQLMS() EQLMS(_create_lowpass)(unsigned int _h_len, float _fc) { // validate input if (_h_len == 0) { fprintf(stderr,"error: eqlms_%s_create_lowpass(), filter length must be greater than 0\n", EXTENSION_FULL); exit(1); } else if (_fc <= 0.0f || _fc > 0.5f) { fprintf(stderr,"error: eqlms_%s_create_rnyquist(), filter cutoff must be in (0,0.5]\n", EXTENSION_FULL); exit(1); } // generate low-pass filter prototype float h[_h_len]; liquid_firdes_kaiser(_h_len, _fc, 40.0f, 0.0f, h); // copy coefficients to type-specific array (e.g. float complex) unsigned int i; T hc[_h_len]; for (i=0; i<_h_len; i++) hc[i] = h[i]; // return equalizer object return EQLMS(_create)(hc, _h_len); }
// create decimator from prototype // _M : decimolation factor // _m : symbol delay // _As : stop-band attenuation [dB] FIRDECIM() FIRDECIM(_create_prototype)(unsigned int _M, unsigned int _m, float _As) { // validate input if (_M < 2) { fprintf(stderr,"error: decim_%s_create_prototype(), decim factor must be greater than 1\n", EXTENSION_FULL); exit(1); } else if (_m == 0) { fprintf(stderr,"error: decim_%s_create_prototype(), filter delay must be greater than 0\n", EXTENSION_FULL); exit(1); } else if (_As < 0.0f) { fprintf(stderr,"error: decim_%s_create_prototype(), stop-band attenuation must be positive\n", EXTENSION_FULL); exit(1); } // compute filter coefficients (floating point precision) unsigned int h_len = 2*_M*_m + 1; float hf[h_len]; float fc = 0.5f / (float) (_M); liquid_firdes_kaiser(h_len, fc, _As, 0.0f, hf); // copy coefficients to type-specific array (e.g. float complex) TC hc[h_len]; unsigned int i; for (i=0; i<h_len; i++) hc[i] = hf[i]; // return decimator object return FIRDECIM(_create)(_M, hc, 2*_M*_m); }
// 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; }
ModemKit *ModemFMStereo::buildKit(long long sampleRate, int audioSampleRate) { ModemKitFMStereo *kit = new ModemKitFMStereo; kit->audioResampleRatio = double(audioSampleRate) / double(sampleRate); kit->sampleRate = sampleRate; kit->audioSampleRate = audioSampleRate; float As = 60.0f; // stop-band attenuation [dB] kit->audioResampler = msresamp_rrrf_create(kit->audioResampleRatio, As); kit->stereoResampler = msresamp_rrrf_create(kit->audioResampleRatio, As); // Stereo filters / shifters double firStereoCutoff = 16000.0 / double(audioSampleRate); // filter transition float ft = 1000.0f / double(audioSampleRate); // fractional timing offset float mu = 0.0f; if (firStereoCutoff < 0) { firStereoCutoff = 0; } if (firStereoCutoff > 0.5) { firStereoCutoff = 0.5; } unsigned int h_len = estimate_req_filter_len(ft, As); float *h = new float[h_len]; liquid_firdes_kaiser(h_len, firStereoCutoff, As, mu, h); kit->firStereoLeft = firfilt_rrrf_create(h, h_len); kit->firStereoRight = firfilt_rrrf_create(h, h_len); // stereo pilot filter float bw = float(sampleRate); if (bw < 100000.0) { bw = 100000.0; } unsigned int order = 5; // filter order float f0 = ((float) 19000 / bw); float fc = ((float) 19500 / bw); float Ap = 1.0f; kit->iirStereoPilot = iirfilt_crcf_create_prototype(LIQUID_IIRDES_CHEBY2, LIQUID_IIRDES_BANDPASS, LIQUID_IIRDES_SOS, order, fc, f0, Ap, As); kit->firStereoR2C = firhilbf_create(5, 60.0f); kit->firStereoC2R = firhilbf_create(5, 60.0f); kit->stereoPilot = nco_crcf_create(LIQUID_VCO); nco_crcf_reset(kit->stereoPilot); nco_crcf_pll_set_bandwidth(kit->stereoPilot, 0.25f); return kit; }
// create firhilb object // _m : filter semi-length (delay: 2*m+1) // _As : stop-band attenuation [dB] FIRHILB() FIRHILB(_create)(unsigned int _m, float _As) { // validate firhilb inputs if (_m < 2) { fprintf(stderr,"error: firhilb_create(), filter semi-length (m) must be at least 2\n"); exit(1); } // allocate memory for main object FIRHILB() q = (FIRHILB()) malloc(sizeof(struct FIRHILB(_s))); q->m = _m; // filter semi-length q->As = fabsf(_As); // stop-band attenuation // set filter length and allocate memory for coefficients q->h_len = 4*(q->m) + 1; q->h = (T *) malloc((q->h_len)*sizeof(T)); q->hc = (T complex *) malloc((q->h_len)*sizeof(T complex)); // allocate memory for quadrature filter component q->hq_len = 2*(q->m); q->hq = (T *) malloc((q->hq_len)*sizeof(T)); // compute filter coefficients for half-band filter liquid_firdes_kaiser(q->h_len, 0.25f, q->As, 0.0f, q->h); // alternate sign of non-zero elements unsigned int i; for (i=0; i<q->h_len; i++) { float t = (float)i - (float)(q->h_len-1)/2.0f; q->hc[i] = q->h[i] * cexpf(_Complex_I*0.5f*M_PI*t); q->h[i] = cimagf(q->hc[i]); } // resample, reverse direction unsigned int j=0; for (i=1; i<q->h_len; i+=2) q->hq[j++] = q->h[q->h_len - i - 1]; // create windows for upper and lower polyphase filter branches q->w1 = WINDOW(_create)(2*(q->m)); q->w0 = WINDOW(_create)(2*(q->m)); WINDOW(_clear)(q->w0); WINDOW(_clear)(q->w1); // create internal dot product object q->dpq = DOTPROD(_create)(q->hq, q->hq_len); // reset internal state and return object FIRHILB(_reset)(q); return q; }
void DemodulatorPreThread::initialize() { initialized = false; iqResampleRatio = (double) (params.bandwidth) / (double) params.sampleRate; audioResampleRatio = (double) (params.audioSampleRate) / (double) params.bandwidth; float As = 120.0f; // stop-band attenuation [dB] iqResampler = msresamp_crcf_create(iqResampleRatio, As); audioResampler = msresamp_rrrf_create(audioResampleRatio, As); stereoResampler = msresamp_rrrf_create(audioResampleRatio, As); // Stereo filters / shifters double firStereoCutoff = ((double) 16000 / (double) params.audioSampleRate); float ft = ((double) 1000 / (double) params.audioSampleRate); // filter transition float mu = 0.0f; // fractional timing offset if (firStereoCutoff < 0) { firStereoCutoff = 0; } if (firStereoCutoff > 0.5) { firStereoCutoff = 0.5; } unsigned int h_len = estimate_req_filter_len(ft, As); float *h = new float[h_len]; liquid_firdes_kaiser(h_len, firStereoCutoff, As, mu, h); firStereoLeft = firfilt_rrrf_create(h, h_len); firStereoRight = firfilt_rrrf_create(h, h_len); // stereo pilot filter float bw = params.bandwidth; if (bw < 100000.0) { bw = 100000.0; } unsigned int order = 5; // filter order float f0 = ((double) 19000 / bw); float fc = ((double) 19500 / bw); float Ap = 1.0f; As = 60.0f; iirStereoPilot = iirfilt_crcf_create_prototype(LIQUID_IIRDES_CHEBY2, LIQUID_IIRDES_BANDPASS, LIQUID_IIRDES_SOS, order, fc, f0, Ap, As); initialized = true; lastParams = params; }
// create symsync using Kaiser filter interpolator; useful // when the input signal has matched filter applied already // _k : input samples/symbol // _m : symbol delay // _beta : rolloff factor, beta in (0,1] // _M : number of filters in the bank SYMSYNC() SYMSYNC(_create_kaiser)(unsigned int _k, unsigned int _m, float _beta, unsigned int _M) { // validate input if (_k < 2) { fprintf(stderr,"error: symsync_%s_create_kaiser(), samples/symbol must be at least 2\n", EXTENSION_FULL); exit(1); } else if (_m == 0) { fprintf(stderr,"error: symsync_%s_create_kaiser(), filter delay (m) must be greater than zero\n", EXTENSION_FULL); exit(1); } else if (_beta < 0.0f || _beta > 1.0f) { fprintf(stderr,"error: symsync_%s_create_kaiser(), filter excess bandwidth must be in [0,1]\n", EXTENSION_FULL); exit(1); } // allocate memory for filter coefficients unsigned int H_len = 2*_M*_k*_m + 1; float Hf[H_len]; // design interpolating filter whose bandwidth is outside the cut-off // frequency of input signal // TODO: use _beta to compute more accurate cut-off frequency float fc = 0.75f; // filter cut-off frequency (nominal) float As = 40.0f; // filter stop-band attenuation liquid_firdes_kaiser(H_len, fc / (float)(_k*_M), As, 0.0f, Hf); // copy coefficients to type-specific array, adjusting to relative // filter gain unsigned int i; TC H[H_len]; for (i=0; i<H_len; i++) H[i] = Hf[i] * 2.0f * fc; // create object and return return SYMSYNC(_create)(_k, _M, H, H_len); }
// create filter using Kaiser-Bessel windowed sinc method // _n : filter length, _n > 0 // _fc : cutoff frequency, 0 < _fc < 0.5 // _As : stop-band attenuation [dB], _As > 0 // _mu : fractional sample offset, -0.5 < _mu < 0.5 FIRFILT() FIRFILT(_create_kaiser)(unsigned int _n, float _fc, float _As, float _mu) { // validate input if (_n == 0) { fprintf(stderr,"error: firfilt_%s_create_kaiser(), filter length must be greater than zero\n", EXTENSION_FULL); exit(1); } // compute temporary array for holding coefficients float hf[_n]; liquid_firdes_kaiser(_n, _fc, _As, _mu, hf); // copy coefficients to type-specific array TC h[_n]; unsigned int i; for (i=0; i<_n; i++) h[i] = (TC) hf[i]; // return FIRFILT(_create)(h, _n); }
int main() { float r=sqrtf(19); // resampling rate (output/input) unsigned int n=37; // number of input samples float As=60.0f; // stop-band attenuation [dB] unsigned int i; // derived values: number of input, output samples (adjusted for filter delay) unsigned int nx = 1.4*n; unsigned int ny_alloc = (unsigned int) (2*(float)nx * r); // allocation for output // allocate memory for arrays float complex x[nx]; float complex y[ny_alloc]; // generate input signal (filter pulse with frequency offset) float hf[n]; liquid_firdes_kaiser(n, 0.08f, 80.0f, 0, hf); for (i=0; i<nx; i++) x[i] = (i < n) ? hf[i]*cexpf(_Complex_I*1.17f*i) : 0.0f; // create resampler msresamp_crcf q = msresamp_crcf_create(r,As); float delay = msresamp_crcf_get_delay(q); // execute resampler, storing in output buffer unsigned int ny; msresamp_crcf_execute(q, x, nx, y, &ny); // print basic results printf("input samples : %u\n", nx); printf("output samples : %u\n", ny); printf("delay : %f samples\n", delay); // clean up allocated objects msresamp_crcf_destroy(q); // // export output files // FILE * fid; // // export time plot // fid = fopen(OUTPUT_FILENAME_TIME,"w"); fprintf(fid,"# %s: auto-generated file\n\n", OUTPUT_FILENAME_TIME); fprintf(fid,"reset\n"); fprintf(fid,"set terminal postscript eps enhanced color solid rounded\n"); //fprintf(fid,"set xrange [0:%u];\n",n); fprintf(fid,"set yrange [-1.2:1.2]\n"); fprintf(fid,"set size ratio 0.3\n"); fprintf(fid,"set xlabel 'Input Sample Index'\n"); fprintf(fid,"set key top right nobox\n"); fprintf(fid,"set ytics -5,1,5\n"); fprintf(fid,"set grid xtics ytics\n"); fprintf(fid,"set grid linetype 1 linecolor rgb '%s' lw 1\n", LIQUID_DOC_COLOR_GRID); fprintf(fid,"set multiplot layout 2,1 scale 1.0,1.0\n"); fprintf(fid,"# real\n"); fprintf(fid,"set ylabel 'Real'\n"); fprintf(fid,"plot '-' using 1:2 with linespoints pointtype 6 pointsize 0.9 linetype 1 linewidth 1 linecolor rgb '#666666' title 'original',\\\n"); fprintf(fid," '-' using 1:2 with points pointtype 7 pointsize 0.6 linecolor rgb '#008000' title 'resampled'\n"); // export input signal for (i=0; i<nx; i++) fprintf(fid,"%12.4e %12.4e %12.4e\n", (float)i, crealf(x[i]), cimagf(x[i])); fprintf(fid,"e\n"); // export output signal for (i=0; i<ny; i++) fprintf(fid,"%12.4e %12.4e %12.4e\n", (float)(i)/r - delay, crealf(y[i]), cimagf(y[i])); fprintf(fid,"e\n"); fprintf(fid,"# imag\n"); fprintf(fid,"set ylabel 'Imag'\n"); fprintf(fid,"plot '-' using 1:3 with linespoints pointtype 6 pointsize 0.9 linetype 1 linewidth 1 linecolor rgb '#666666' title 'original',\\\n"); fprintf(fid," '-' using 1:3 with points pointtype 7 pointsize 0.6 linecolor rgb '#800000' title 'resampled'\n"); // export input signal for (i=0; i<nx; i++) fprintf(fid,"%12.4e %12.4e %12.4e\n", (float)i, crealf(x[i]), cimagf(x[i])); fprintf(fid,"e\n"); // export output signal for (i=0; i<ny; i++) fprintf(fid,"%12.4e %12.4e %12.4e\n", (float)(i)/r - delay, crealf(y[i]), cimagf(y[i])); fprintf(fid,"e\n"); fprintf(fid,"unset multiplot\n"); // close output file fclose(fid); // // export spectrum plot // fid = fopen(OUTPUT_FILENAME_FREQ,"w"); unsigned int nfft = 512; float complex X[nfft]; float complex Y[nfft]; liquid_doc_compute_psdcf(x, nx, X, nfft, LIQUID_DOC_PSDWINDOW_NONE, 1); liquid_doc_compute_psdcf(y, ny, Y, nfft, LIQUID_DOC_PSDWINDOW_NONE, 1); fft_shift(X,nfft); fft_shift(Y,nfft); fprintf(fid,"# %s: auto-generated file\n\n", OUTPUT_FILENAME_FREQ); fprintf(fid,"reset\n"); fprintf(fid,"set terminal postscript eps enhanced color solid rounded\n"); fprintf(fid,"set xrange [-0.5:0.5];\n"); fprintf(fid,"set yrange [-120:20]\n"); fprintf(fid,"set size ratio 0.6\n"); fprintf(fid,"set xlabel 'Normalized Output Frequency'\n"); fprintf(fid,"set ylabel 'Power Spectral Density [dB]'\n"); fprintf(fid,"set key top right nobox\n"); fprintf(fid,"set grid xtics ytics\n"); fprintf(fid,"set pointsize 0.6\n"); fprintf(fid,"set grid linetype 1 linecolor rgb '%s' lw 1\n",LIQUID_DOC_COLOR_GRID); fprintf(fid,"# real\n"); fprintf(fid,"plot '-' using 1:2 with lines linetype 1 linewidth 4 linecolor rgb '#999999' title 'original',\\\n"); fprintf(fid," '-' using 1:2 with lines linetype 1 linewidth 4 linecolor rgb '#004080' title 'resampled'\n"); // export output for (i=0; i<nfft; i++) { float fx = ((float)(i) / (float)nfft - 0.5f) / r; fprintf(fid,"%12.8f %12.4e\n", fx, 20*log10f(cabsf(X[i]))); } fprintf(fid,"e\n"); for (i=0; i<nfft; i++) { float fy = ((float)(i) / (float)nfft - 0.5f); fprintf(fid,"%12.8f %12.4e\n", fy, 20*log10f(cabsf(Y[i]))); } fprintf(fid,"e\n"); fclose(fid); printf("done.\n"); return 0; }
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; }
int main() { // options unsigned int h_len=17; // filter length float fc=0.2f; // filter cutoff float As=30.0f; // stop-band attenuation [dB] float mu=0.0f; // timing offset unsigned int n=64; // number of random input samples // derived values unsigned int num_samples = n + h_len; // arrays float x[num_samples]; // filter input float y[num_samples]; // filter output unsigned int i; float h[h_len]; liquid_firdes_kaiser(h_len,fc,As,mu,h); firfilt_rrrf f = firfilt_rrrf_create(h,h_len); firfilt_rrrf_print(f); for (i=0; i<num_samples; i++) { // generate noise x[i] = (i<n) ? randnf()/sqrtf(n/2) : 0.0f; firfilt_rrrf_push(f, x[i]); firfilt_rrrf_execute(f, &y[i]); printf("x[%4u] = %12.8f, y[%4u] = %12.8f;\n", i, x[i], i, y[i]); } // destroy filter object firfilt_rrrf_destroy(f); // // export results // FILE*fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% firfilt_rrrf_example.m: auto-generated file\n\n"); fprintf(fid,"clear all;\nclose all;\n\n"); fprintf(fid,"h_len=%u;\nn=%u;\n", h_len, n); for (i=0; i<h_len; i++) fprintf(fid,"h(%4u) = %12.4e;\n", i+1, h[i]); for (i=0; i<num_samples; i++) fprintf(fid,"x(%4u) = %12.4e; y(%4u) = %12.4e;\n", i+1, x[i], i+1, y[i]); fprintf(fid,"nfft=512;\n"); fprintf(fid,"H=20*log10(abs(fftshift(fft(h,nfft))));\n"); fprintf(fid,"X=20*log10(abs(fftshift(fft(x,nfft))));\n"); fprintf(fid,"Y=20*log10(abs(fftshift(fft(y,nfft))));\n"); fprintf(fid,"f=[0:(nfft-1)]/nfft-0.5;\n"); fprintf(fid,"figure;\n"); fprintf(fid,"plot(f,X,'Color',[0.3 0.3 0.3],...\n"); fprintf(fid," f,Y,'LineWidth',2,...\n"); fprintf(fid," f,H,'-b','LineWidth',2);\n"); fprintf(fid,"axis([-0.5 0.5 -80 40]);\n"); fprintf(fid,"grid on;\nxlabel('normalized frequency');\nylabel('PSD [dB]');\n"); fprintf(fid,"legend('noise','filtered noise','filter prototype',1);"); fclose(fid); printf("results written to %s\n", OUTPUT_FILENAME); printf("done.\n"); return 0; }
firpfbch firpfbch_create(unsigned int _num_channels, unsigned int _m, float _beta, float _dt, int _nyquist, int _gradient) { firpfbch c = (firpfbch) malloc(sizeof(struct firpfbch_s)); c->num_channels = _num_channels; c->m = _m; c->beta = _beta; c->dt = _dt; c->nyquist = _nyquist; // validate inputs if (_m < 1) { printf("error: firpfbch_create(), invalid filter delay (must be greater than 0)\n"); exit(1); } // create bank of filters c->dp = (DOTPROD()*) malloc((c->num_channels)*sizeof(DOTPROD())); c->w = (WINDOW()*) malloc((c->num_channels)*sizeof(WINDOW())); // design filter // TODO: use filter prototype object c->h_len = 2*(c->m)*(c->num_channels); c->h = (float*) malloc((c->h_len+1)*sizeof(float)); if (c->nyquist == FIRPFBCH_NYQUIST) { float fc = 0.5f/(float)(c->num_channels); // cutoff frequency liquid_firdes_kaiser(c->h_len+1, fc, c->beta, 0.0f, c->h); } else if (c->nyquist == FIRPFBCH_ROOTNYQUIST) { design_rkaiser_filter(c->num_channels, c->m, c->beta, c->dt, c->h); } else { printf("error: firpfbch_create(), unsupported nyquist flag: %d\n", _nyquist); exit(1); } unsigned int i; if (_gradient) { float dh[c->h_len]; for (i=0; i<c->h_len; i++) { if (i==0) { dh[i] = c->h[i+1] - c->h[c->h_len-1]; } else if (i==c->h_len-1) { dh[i] = c->h[0] - c->h[i-1]; } else { dh[i] = c->h[i+1] - c->h[i-1]; } } memmove(c->h, dh, (c->h_len)*sizeof(float)); } // generate bank of sub-samped filters unsigned int n; unsigned int h_sub_len = 2*(c->m); // length of each sub-sampled filter float h_sub[h_sub_len]; for (i=0; i<c->num_channels; i++) { // sub-sample prototype filter, loading coefficients in reverse order for (n=0; n<h_sub_len; n++) { h_sub[h_sub_len-n-1] = c->h[i + n*(c->num_channels)]; } // create window buffer and dotprod object (coefficients // loaded in reverse order) c->dp[i] = DOTPROD(_create)(h_sub,h_sub_len); c->w[i] = WINDOW(_create)(h_sub_len); #if DEBUG_FIRPFBCH_PRINT printf("h_sub[%u] :\n", i); for (n=0; n<h_sub_len; n++) printf(" h[%3u] = %8.4f\n", n, h_sub[n]); #endif } #if DEBUG_FIRPFBCH_PRINT for (i=0; i<c->h_len+1; i++) printf("h(%4u) = %12.4e;\n", i+1, c->h[i]); #endif // allocate memory for buffers // TODO : use fftw_malloc if HAVE_FFTW3_H c->x = (float complex*) malloc((c->num_channels)*sizeof(float complex)); c->X = (float complex*) malloc((c->num_channels)*sizeof(float complex)); c->X_prime = (float complex*) malloc((c->num_channels)*sizeof(float complex)); firpfbch_clear(c); // create fft plan c->fft = FFT_CREATE_PLAN(c->num_channels, c->X, c->x, FFT_DIR_BACKWARD, FFT_METHOD); return c; }
int main(int argc, char*argv[]) { // options float mod_index = 0.5f; // modulation index (bandwidth) float fc = 0.0f; // FM carrier liquid_freqmodem_type type = LIQUID_FREQMODEM_DELAYCONJ; unsigned int num_samples = 256; // number of samples float SNRdB = 30.0f; // signal-to-noise ratio [dB] int dopt; while ((dopt = getopt(argc,argv,"hn:S:f:m:t:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'n': num_samples = atoi(optarg); break; case 'S': SNRdB = atof(optarg); break; case 'f': fc = atof(optarg); break; case 'm': mod_index = atof(optarg); break; case 't': if (strcmp(optarg,"delayconj")==0) { type = LIQUID_FREQMODEM_DELAYCONJ; } else if (strcmp(optarg,"pll")==0) { type = LIQUID_FREQMODEM_PLL; } else { fprintf(stderr,"error: %s, invalid FM type: %s\n", argv[0], optarg); exit(1); } break; default: exit(1); } } // create mod/demod objects freqmodem mod = freqmodem_create(mod_index,fc,type); freqmodem demod = freqmodem_create(mod_index,fc,type); freqmodem_print(mod); unsigned int i; float x[num_samples]; float complex y[num_samples]; float z[num_samples]; // generate un-modulated signal (band-limited pulse) liquid_firdes_kaiser(num_samples, 0.05f, -40.0f, 0.0f, x); // modulate signal for (i=0; i<num_samples; i++) freqmodem_modulate(mod, x[i], &y[i]); // add channel impairments float nstd = powf(10.0f,-SNRdB/20.0f); for (i=0; i<num_samples; i++) y[i] += nstd*( randnf() + _Complex_I*randnf() ) * M_SQRT1_2; // demodulate signal for (i=0; i<num_samples; i++) freqmodem_demodulate(demod, y[i], &z[i]); // write results to output file FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all\n"); fprintf(fid,"close all\n"); fprintf(fid,"n=%u;\n",num_samples); for (i=0; i<num_samples; i++) { fprintf(fid,"x(%3u) = %12.4e;\n", i+1, x[i]); fprintf(fid,"y(%3u) = %12.4e + j*%12.4e;\n", i+1, crealf(y[i]), cimagf(y[i])); fprintf(fid,"z(%3u) = %12.4e;\n", i+1, z[i]); } // plot results fprintf(fid,"t=0:(n-1);\n"); fprintf(fid,"figure;\n"); fprintf(fid,"plot(t,x,t,z);\n"); fprintf(fid,"axis([0 n -1.2 1.2]);\n"); // spectrum fprintf(fid,"nfft=1024;\n"); fprintf(fid,"f=[0:(nfft-1)]/nfft - 0.5;\n"); fprintf(fid,"Y = 20*log10(abs(fftshift(fft(y/n,nfft))));\n"); fprintf(fid,"figure;\n"); fprintf(fid,"plot(f,Y);\n"); fprintf(fid,"axis([-0.5 0.5 -60 20]);\n"); fprintf(fid,"grid on;\n"); fclose(fid); printf("results written to %s\n", OUTPUT_FILENAME); freqmodem_destroy(mod); freqmodem_destroy(demod); return 0; }
int main(int argc, char*argv[]) { // options unsigned int num_channels=16; // number of channels unsigned int m = 5; // filter semi-length (symbols) unsigned int num_symbols=25; // number of symbols float As = 80.0f; // filter stop-band attenuation int dopt; while ((dopt = getopt(argc,argv,"hM:m:s:n:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'M': num_channels = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 's': As = atof(optarg); break; case 'n': num_symbols = atof(optarg); break; default: exit(1); } } unsigned int i; // validate input if (num_channels < 2 || num_channels % 2) { fprintf(stderr,"error: %s, number of channels must be greater than 2 and even\n", argv[0]); exit(1); } else if (m == 0) { fprintf(stderr,"error: %s, filter semi-length must be greater than zero\n", argv[0]); exit(1); } else if (num_symbols == 0) { fprintf(stderr,"error: %s, number of symbols must be greater than zero", argv[0]); exit(1); } // derived values unsigned int num_samples = num_channels * num_symbols; // allocate arrays float complex x[num_samples]; float complex y[num_samples]; // generate input signal unsigned int w_len = (unsigned int)(0.4*num_samples); for (i=0; i<num_samples; i++) { //x[i] = (i==0) ? 1.0f : 0.0f; //x[i] = cexpf( (-0.05f + 0.07f*_Complex_I)*i ); // decaying complex exponential x[i] = cexpf( _Complex_I * (1.3f*i - 0.007f*i*i) ); x[i] *= i < w_len ? hamming(i,w_len) : 0.0f; //x[i] = (i==0) ? 1.0f : 0.0f; } // create filterbank objects from prototype firpfbch2_crcf qa = firpfbch2_crcf_create_kaiser(LIQUID_ANALYZER, num_channels, m, As); firpfbch2_crcf qs = firpfbch2_crcf_create_kaiser(LIQUID_SYNTHESIZER, num_channels, m, As); firpfbch2_crcf_print(qa); firpfbch2_crcf_print(qs); // run channelizer float complex Y[num_channels]; for (i=0; i<num_samples; i+=num_channels/2) { // run analysis filterbank firpfbch2_crcf_execute(qa, &x[i], Y); // run synthesis filterbank firpfbch2_crcf_execute(qs, Y, &y[i]); } // destroy fiterbank objects firpfbch2_crcf_destroy(qa); // analysis fitlerbank firpfbch2_crcf_destroy(qs); // synthesis filterbank // print output for (i=0; i<num_samples; i++) printf("%4u : %12.8f + %12.8fj\n", i, crealf(y[i]), cimagf(y[i])); // compute RMSE float rmse = 0.0f; unsigned int delay = 2*num_channels*m - num_channels/2 + 1; for (i=0; i<num_samples; i++) { float complex err = y[i] - (i < delay ? 0.0f : x[i-delay]); rmse += crealf( err*conjf(err) ); } rmse = sqrtf( rmse/(float)num_samples ); printf("rmse : %12.4e\n", rmse); // // EXPORT DATA TO FILES // FILE * fid = NULL; fid = fopen(OUTPUT_FILENAME_TIME,"w"); fprintf(fid,"# %s: auto-generated file\n", OUTPUT_FILENAME_TIME); fprintf(fid,"#\n"); fprintf(fid,"# %8s %12s %12s %12s %12s %12s %12s\n", "time", "real(x)", "imag(x)", "real(y)", "imag(y)", "real(e)", "imag(e)"); // save input and output arrays for (i=0; i<num_samples; i++) { float complex e = (i < delay) ? 0.0f : y[i] - x[i-delay]; fprintf(fid," %8.1f %12.4e %12.4e %12.4e %12.4e %12.4e %12.4e\n", (float)i, crealf(x[i]), cimagf(x[i]), crealf(y[i]), cimagf(y[i]), crealf(e), cimagf(e)); } fclose(fid); printf("results written to '%s'\n", OUTPUT_FILENAME_TIME); // // export frequency data // unsigned int nfft = 2048; float complex y_time[nfft]; float complex y_freq[nfft]; for (i=0; i<nfft; i++) y_time[i] = i < num_samples ? y[i] : 0.0f; fft_run(nfft, y_time, y_freq, LIQUID_FFT_FORWARD, 0); // filter spectrum unsigned int h_len = 2*num_channels*m+1; float h[h_len]; float fc = 0.5f/(float)num_channels; liquid_firdes_kaiser(h_len, fc, As, 0.0f, h); float complex h_time[nfft]; float complex h_freq[nfft]; for (i=0; i<nfft; i++) h_time[i] = i < h_len ? 2*h[i]*fc : 0.0f; fft_run(nfft, h_time, h_freq, LIQUID_FFT_FORWARD, 0); // error spectrum float complex e_time[nfft]; float complex e_freq[nfft]; for (i=0; i<nfft; i++) e_time[i] = i < delay || i > num_samples ? 0.0f : y[i] - x[i-delay]; fft_run(nfft, e_time, e_freq, LIQUID_FFT_FORWARD, 0); fid = fopen(OUTPUT_FILENAME_FREQ,"w"); fprintf(fid,"# %s: auto-generated file\n", OUTPUT_FILENAME_FREQ); fprintf(fid,"#\n"); fprintf(fid,"# nfft = %u\n", nfft); fprintf(fid,"# %12s %12s %12s %12s\n", "freq", "PSD [dB]", "filter [dB]", "error [dB]"); // save input and output arrays for (i=0; i<nfft; i++) { float f = (float)i/(float)nfft - 0.5f; unsigned int k = (i + nfft/2)%nfft; fprintf(fid," %12.8f %12.8f %12.8f %12.8f\n", f, 20*log10f(cabsf(y_freq[k])), 20*log10f(cabsf(h_freq[k])), 20*log10f(cabsf(e_freq[k]))); } fclose(fid); printf("results written to '%s'\n", OUTPUT_FILENAME_FREQ); printf("done.\n"); return 0; }
void DemodulatorWorkerThread::threadMain() { std::cout << "Demodulator worker thread started.." << std::endl; while (!terminated) { bool filterChanged = false; DemodulatorWorkerThreadCommand filterCommand; DemodulatorWorkerThreadCommand command; bool done = false; while (!done) { commandQueue->pop(command); switch (command.cmd) { case DemodulatorWorkerThreadCommand::DEMOD_WORKER_THREAD_CMD_BUILD_FILTERS: filterChanged = true; filterCommand = command; break; default: break; } done = commandQueue->empty(); } if (filterChanged && !terminated) { DemodulatorWorkerThreadResult result(DemodulatorWorkerThreadResult::DEMOD_WORKER_THREAD_RESULT_FILTERS); float As = 60.0f; // stop-band attenuation [dB] if (filterCommand.sampleRate && filterCommand.bandwidth) { result.iqResampleRatio = (double) (filterCommand.bandwidth) / (double) filterCommand.sampleRate; result.iqResampler = msresamp_crcf_create(result.iqResampleRatio, As); } if (filterCommand.bandwidth && filterCommand.audioSampleRate) { result.audioResamplerRatio = (double) (filterCommand.audioSampleRate) / (double) filterCommand.bandwidth; result.audioResampler = msresamp_rrrf_create(result.audioResamplerRatio, As); result.stereoResampler = msresamp_rrrf_create(result.audioResamplerRatio, As); result.audioSampleRate = filterCommand.audioSampleRate; // Stereo filters / shifters double firStereoCutoff = ((double) 16000 / (double) filterCommand.audioSampleRate); float ft = ((double) 1000 / (double) filterCommand.audioSampleRate); // filter transition float mu = 0.0f; // fractional timing offset if (firStereoCutoff < 0) { firStereoCutoff = 0; } if (firStereoCutoff > 0.5) { firStereoCutoff = 0.5; } unsigned int h_len = estimate_req_filter_len(ft, As); float *h = new float[h_len]; liquid_firdes_kaiser(h_len, firStereoCutoff, As, mu, h); result.firStereoLeft = firfilt_rrrf_create(h, h_len); result.firStereoRight = firfilt_rrrf_create(h, h_len); float bw = filterCommand.bandwidth; if (bw < 100000.0) { bw = 100000.0; } // stereo pilot filter unsigned int order = 5; // filter order float f0 = ((double) 19000 / bw); float fc = ((double) 19500 / bw); float Ap = 1.0f; As = 60.0f; result.iirStereoPilot = iirfilt_crcf_create_prototype(LIQUID_IIRDES_CHEBY2, LIQUID_IIRDES_BANDPASS, LIQUID_IIRDES_SOS, order, fc, f0, Ap, As); } if (filterCommand.bandwidth) { result.bandwidth = filterCommand.bandwidth; } if (filterCommand.sampleRate) { result.sampleRate = filterCommand.sampleRate; } resultQueue->push(result); } } std::cout << "Demodulator worker thread done." << std::endl; }
int main(int argc, char*argv[]) { // options unsigned int k=4; // samples/symbol unsigned int m=3; // filter delay [symbols] float BT = 0.3f; // bandwidth-time product // read properties from command line int dopt; while ((dopt = getopt(argc,argv,"uhk:m:b:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'b': BT = atof(optarg); break; default: exit(1); } } // validate input if (k < 2) { fprintf(stderr,"error: %s, k must be at least 2\n", argv[0]); exit(1); } else if (m < 1) { fprintf(stderr,"error: %s, m must be at least 1\n", argv[0]); exit(1); } else if (BT <= 0.0f || BT >= 1.0f) { fprintf(stderr,"error: %s, BT must be in (0,1)\n", argv[0]); exit(1); } unsigned int i; // derived values unsigned int h_len = 2*k*m+1; // filter length // arrays float ht[h_len]; // transmit filter coefficients float hr[h_len]; // recieve filter coefficients // design transmit filter liquid_firdes_gmsktx(k,m,BT,0.0f,ht); // print results to screen printf("gmsk transmit filter:\n"); for (i=0; i<h_len; i++) printf(" ht(%3u) = %12.8f;\n", i+1, ht[i]); // // start of filter design procedure // float beta = BT; // prototype filter cut-off float delta = 1e-2f; // filter design correction factor // temporary arrays float h_primef[h_len]; // temporary buffer for real coefficients float g_primef[h_len]; // float complex h_tx[h_len]; // impulse response of transmit filter float complex h_prime[h_len]; // impulse response of 'prototype' filter float complex g_prime[h_len]; // impulse response of 'gain' filter float complex h_hat[h_len]; // impulse response of receive filter float complex H_tx[h_len]; // frequency response of transmit filter float complex H_prime[h_len]; // frequency response of 'prototype' filter float complex G_prime[h_len]; // frequency response of 'gain' filter float complex H_hat[h_len]; // frequency response of receive filter // create 'prototype' matched filter // for now use raised-cosine liquid_firdes_nyquist(LIQUID_NYQUIST_RCOS,k,m,beta,0.0f,h_primef); // create 'gain' filter to improve stop-band rejection float fc = (0.7f + 0.1*beta) / (float)k; float As = 60.0f; liquid_firdes_kaiser(h_len, fc, As, 0.0f, g_primef); // copy to fft input buffer, shifting appropriately for (i=0; i<h_len; i++) { h_prime[i] = h_primef[ (i+k*m)%h_len ]; g_prime[i] = g_primef[ (i+k*m)%h_len ]; h_tx[i] = ht[ (i+k*m)%h_len ]; } // run ffts fft_run(h_len, h_prime, H_prime, FFT_FORWARD, 0); fft_run(h_len, g_prime, G_prime, FFT_FORWARD, 0); fft_run(h_len, h_tx, H_tx, FFT_FORWARD, 0); #if 0 // print results for (i=0; i<h_len; i++) printf("Ht(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(H_tx[i]), cimagf(H_tx[i])); for (i=0; i<h_len; i++) printf("H_prime(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(H_prime[i]), cimagf(H_prime[i])); for (i=0; i<h_len; i++) printf("G_prime(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(G_prime[i]), cimagf(G_prime[i])); #endif // find minimum of reponses float H_tx_min = 0.0f; float H_prime_min = 0.0f; float G_prime_min = 0.0f; for (i=0; i<h_len; i++) { if (i==0 || crealf(H_tx[i]) < H_tx_min) H_tx_min = crealf(H_tx[i]); if (i==0 || crealf(H_prime[i]) < H_prime_min) H_prime_min = crealf(H_prime[i]); if (i==0 || crealf(G_prime[i]) < G_prime_min) G_prime_min = crealf(G_prime[i]); } // compute 'prototype' response, removing minima, and add correction factor for (i=0; i<h_len; i++) { // compute response necessary to yeild prototype response (not exact, but close) H_hat[i] = crealf(H_prime[i] - H_prime_min + delta) / crealf(H_tx[i] - H_tx_min + delta); // include additional term to add stop-band suppression H_hat[i] *= crealf(G_prime[i] - G_prime_min) / crealf(G_prime[0]); } // compute ifft and copy response fft_run(h_len, H_hat, h_hat, FFT_REVERSE, 0); for (i=0; i<h_len; i++) hr[i] = crealf( h_hat[(i+k*m+1)%h_len] ) / (float)(k*h_len); // // end of filter design procedure // // print results to screen printf("gmsk receive filter:\n"); for (i=0; i<h_len; i++) printf(" hr(%3u) = %12.8f;\n", i+1, hr[i]); // compute isi float rxy0 = liquid_filter_crosscorr(ht,h_len, hr,h_len, 0); float isi_rms = 0.0f; for (i=1; i<2*m; i++) { float e = liquid_filter_crosscorr(ht,h_len, hr,h_len, i*k) / rxy0; isi_rms += e*e; } isi_rms = sqrtf(isi_rms / (float)(2*m-1)); printf("\n"); printf("ISI (RMS) = %12.8f dB\n", 20*log10f(isi_rms)); // // export output file // FILE*fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n"); fprintf(fid,"\n\n"); fprintf(fid,"k = %u;\n", k); fprintf(fid,"m = %u;\n", m); fprintf(fid,"beta = %f;\n", BT); fprintf(fid,"h_len = 2*k*m+1;\n"); fprintf(fid,"nfft = 1024;\n"); fprintf(fid,"ht = zeros(1,h_len);\n"); fprintf(fid,"hp = zeros(1,h_len);\n"); fprintf(fid,"hr = zeros(1,h_len);\n"); // print results for (i=0; i<h_len; i++) fprintf(fid,"ht(%3u) = %12.4e;\n", i+1, ht[i] / k); for (i=0; i<h_len; i++) fprintf(fid,"hr(%3u) = %12.4e;\n", i+1, hr[i] * k); for (i=0; i<h_len; i++) fprintf(fid,"hp(%3u) = %12.4e;\n", i+1, h_primef[i]); fprintf(fid,"hc = k*conv(ht,hr);\n"); // plot results fprintf(fid,"f = [0:(nfft-1)]/nfft - 0.5;\n"); fprintf(fid,"Ht = 20*log10(abs(fftshift(fft(ht, nfft))));\n"); fprintf(fid,"Hp = 20*log10(abs(fftshift(fft(hp/k,nfft))));\n"); fprintf(fid,"Hr = 20*log10(abs(fftshift(fft(hr, nfft))));\n"); fprintf(fid,"Hc = 20*log10(abs(fftshift(fft(hc/k,nfft))));\n"); fprintf(fid,"\n"); fprintf(fid,"figure;\n"); fprintf(fid,"plot(f,Ht,'LineWidth',1,'Color',[0.00 0.25 0.50],...\n"); fprintf(fid," f,Hp,'LineWidth',1,'Color',[0.80 0.80 0.80],...\n"); fprintf(fid," f,Hr,'LineWidth',1,'Color',[0.00 0.50 0.25],...\n"); fprintf(fid," f,Hc,'LineWidth',2,'Color',[0.50 0.00 0.00],...\n"); fprintf(fid," [-0.5/k 0.5/k], [1 1]*20*log10(0.5),'or');\n"); fprintf(fid,"legend('transmit','prototype','receive','composite','alias points',1);\n"); fprintf(fid,"xlabel('Normalized Frequency');\n"); fprintf(fid,"ylabel('PSD');\n"); fprintf(fid,"grid on;\n"); fprintf(fid,"axis([-0.5 0.5 -100 20]);\n"); fprintf(fid,"\n"); fprintf(fid,"figure;\n"); fprintf(fid,"tr = [ -k*m:k*m]/k;\n"); fprintf(fid,"tc = [-2*k*m:2*k*m]/k;\n"); fprintf(fid,"ic = [0:k:(4*k*m)]+1;\n"); fprintf(fid,"subplot(2,1,1);\n"); fprintf(fid," plot(tr,ht,'-x', tr,hr,'-x');\n"); fprintf(fid," legend('transmit','receive',1);\n"); fprintf(fid," xlabel('Time');\n"); fprintf(fid," ylabel('GMSK Tx/Rx Filters');\n"); fprintf(fid," grid on;\n"); fprintf(fid," axis([-2*m 2*m floor(5*min([hr ht]))/5 ceil(5*max([hr ht]))/5]);\n"); fprintf(fid,"subplot(2,1,2);\n"); fprintf(fid," plot(tc,hc,'-x', tc(ic),hc(ic),'or');\n"); fprintf(fid," xlabel('Time');\n"); fprintf(fid," ylabel('GMSK Composite Response');\n"); fprintf(fid," grid on;\n"); fprintf(fid," axis([-2*m 2*m -0.2 1.2]);\n"); fprintf(fid," axis([-2*m 2*m floor(5*min(hc))/5 ceil(5*max(hc))/5]);\n"); fclose(fid); printf("results written to %s.\n", OUTPUT_FILENAME); return 0; }
int main() { // options unsigned int num_channels=8; // number of channels unsigned int m=4; // filter delay float As=60; // stop-band attenuation unsigned int num_frames=25; // number of frames // unsigned int i; unsigned int k; // derived values unsigned int num_samples = num_frames * num_channels; // data arrays float complex x[num_samples]; // time-domain input [size: num_samples x 1 ] float complex y[num_samples]; // channelized output [size: num_channels x num_frames] // initialize input with zeros for (i=0; i<num_samples; i++) x[i] = 0.0f; // generate input signal(s) unsigned int num_signals = 4; float fc[4] = {0.0f, 0.25f, 0.375f, -0.375f}; // center frequencies float bw[4] = {0.035f, 0.035f, 0.035f, 0.035f}; // bandwidths unsigned int pulse_len = 137; float pulse[pulse_len]; for (i=0; i<num_signals; i++) { // create pulse liquid_firdes_kaiser(pulse_len, bw[i], 50.0f, 0.0f, pulse); // add pulse to input signal with carrier offset for (k=0; k<pulse_len; k++) x[k] += pulse[k] * cexpf(_Complex_I*2*M_PI*fc[i]*k) * bw[i]; } // create prototype filter unsigned int h_len = 2*num_channels*m + 1; float h[h_len]; liquid_firdes_kaiser(h_len, 0.5f/(float)num_channels, As, 0.0f, h); #if 0 // create filterbank channelizer object using internal method for filter firpfbch_crcf q = firpfbch_crcf_create_kaiser(LIQUID_ANALYZER, num_channels, m, As); #else // create filterbank channelizer object using external filter coefficients firpfbch_crcf q = firpfbch_crcf_create(LIQUID_ANALYZER, num_channels, 2*m, h); #endif // channelize input data for (i=0; i<num_frames; i++) { // execute analysis filter bank firpfbch_crcf_analyzer_execute(q, &x[i*num_channels], &y[i*num_channels]); } // destroy channelizer object firpfbch_crcf_destroy(q); // // export results to file // FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s: auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n"); fprintf(fid,"num_channels = %u;\n", num_channels); fprintf(fid,"m = %u;\n", m); fprintf(fid,"num_frames = %u;\n", num_frames); fprintf(fid,"h_len = 2*num_channels*m+1;\n"); fprintf(fid,"num_samples = num_frames*num_channels;\n"); fprintf(fid,"h = zeros(1,h_len);\n"); fprintf(fid,"x = zeros(1,num_samples);\n"); fprintf(fid,"y = zeros(num_channels, num_frames);\n"); // save prototype filter for (i=0; i<h_len; i++) fprintf(fid," h(%6u) = %12.4e;\n", i+1, h[i]); // save input signal for (i=0; i<num_samples; i++) fprintf(fid," x(%6u) = %12.4e + 1i*%12.4e;\n", i+1, crealf(x[i]), cimagf(x[i])); // save channelized output signals for (i=0; i<num_frames; i++) { for (k=0; k<num_channels; k++) { float complex v = y[i*num_channels + k]; fprintf(fid," y(%3u,%6u) = %12.4e + 1i*%12.4e;\n", k+1, i+1, crealf(v), cimagf(v)); } } // plot results fprintf(fid,"\n"); fprintf(fid,"nfft = 1024;\n"); // TODO: use nextpow2 fprintf(fid,"f = [0:(nfft-1)]/nfft - 0.5;\n"); fprintf(fid,"H = 20*log10(abs(fftshift(fft(h/num_channels,nfft))));\n"); fprintf(fid,"X = 20*log10(abs(fftshift(fft(x,nfft))));\n"); fprintf(fid,"figure;\n"); fprintf(fid,"subplot(2,1,1);\n"); fprintf(fid," plot(f, H, 'Color', [0 0.5 0.25], 'LineWidth', 2);\n"); fprintf(fid," axis([-0.5 0.5 -100 10]);\n"); fprintf(fid," grid on;\n"); fprintf(fid," xlabel('Normalized Frequency [f/F_s]');\n"); fprintf(fid," ylabel('Prototype Filter PSD');\n"); fprintf(fid,"subplot(2,1,2);\n"); fprintf(fid," plot(f, X, 'Color', [0 0.25 0.5], 'LineWidth', 2);\n"); fprintf(fid," axis([-0.5 0.5 -100 0]);\n"); fprintf(fid," grid on;\n"); fprintf(fid," xlabel('Normalized Frequency [f/F_s]');\n"); fprintf(fid," ylabel('Input PSD');\n"); // compute the PSD of each output and plot results on a square grid fprintf(fid,"n = ceil(sqrt(num_channels));\n"); fprintf(fid,"figure;\n"); fprintf(fid,"for i=1:num_channels,\n"); fprintf(fid," Y = 20*log10(abs(fftshift(fft(y(i,:),nfft))));\n"); fprintf(fid," subplot(n,n,i);\n"); fprintf(fid," plot(f, Y, 'Color', [0.25 0 0.25], 'LineWidth', 1.5);\n"); fprintf(fid," axis([-0.5 0.5 -120 20]);\n"); fprintf(fid," grid on;\n"); fprintf(fid," title(num2str(i-1));\n"); fprintf(fid,"end;\n"); fclose(fid); printf("results written to %s\n", OUTPUT_FILENAME); printf("done.\n"); return 0; }
// 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); } }
int main() { // options unsigned int num_channels = 16; // number of channels unsigned int m = 5; // filter delay float As = 60; // stop-band attenuation unsigned int num_frames = 25; // number of frames // unsigned int i; unsigned int k; // derived values unsigned int num_samples = num_frames * num_channels; // data arrays float complex x[num_channels][num_frames]; // channelized input float complex y[num_samples]; // time-domain output [size: num_samples x 1] // create narrow-band pulse unsigned int pulse_len = 17; // pulse length [samples] float bw = 0.30f; // pulse width (bandwidth) float pulse[pulse_len]; // buffer liquid_firdes_kaiser(pulse_len, bw, 50.0f, 0.0f, pulse); // generate input signal(s) int enabled[num_channels]; // signal enabled? for (i=0; i<num_channels; i++) { // pseudo-random channel enabled flag enabled[i] = ((i*37)%101)%2; if (enabled[i]) { // move pulse to input buffer for (k=0; k<num_frames; k++) x[i][k] = k < pulse_len ? bw*pulse[k] : 0.0f; } else { // channel disabled; set as nearly zero (-100 dB impulse) for (k=0; k<num_frames; k++) x[i][k] = (k == 0) ? 1e-5f : 0.0f; } } // create prototype filter unsigned int h_len = 2*num_channels*m + 1; float h[h_len]; liquid_firdes_kaiser(h_len, 0.5f/(float)num_channels, As, 0.0f, h); #if 0 // create filterbank channelizer object using internal method for filter firpfbch_crcf q = firpfbch_crcf_create_kaiser(LIQUID_SYNTHESIZER, num_channels, m, As); #else // create filterbank channelizer object using external filter coefficients firpfbch_crcf q = firpfbch_crcf_create(LIQUID_SYNTHESIZER, num_channels, 2*m, h); #endif // channelize input data float complex v[num_channels]; for (i=0; i<num_frames; i++) { // assemble input vector for (k=0; k<num_channels; k++) v[k] = x[k][i]; // execute synthesis filter bank firpfbch_crcf_synthesizer_execute(q, v, &y[i*num_channels]); } // destroy channelizer object firpfbch_crcf_destroy(q); // // export results to file // FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s: auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n"); fprintf(fid,"num_channels = %u;\n", num_channels); fprintf(fid,"m = %u;\n", m); fprintf(fid,"num_frames = %u;\n", num_frames); fprintf(fid,"h_len = 2*num_channels*m+1;\n"); fprintf(fid,"num_samples = num_frames*num_channels;\n"); fprintf(fid,"h = zeros(1,h_len);\n"); fprintf(fid,"x = zeros(num_channels, num_frames);\n"); fprintf(fid,"y = zeros(1,num_samples);\n"); // save prototype filter for (i=0; i<h_len; i++) fprintf(fid," h(%6u) = %12.4e;\n", i+1, h[i]); // save channelized input signals for (i=0; i<num_frames; i++) { for (k=0; k<num_channels; k++) { float complex v = x[k][i]; fprintf(fid," x(%3u,%6u) = %12.4e + 1i*%12.4e;\n", k+1, i+1, crealf(v), cimagf(v)); } } // save output time signal for (i=0; i<num_samples; i++) fprintf(fid," y(%6u) = %12.4e + 1i*%12.4e;\n", i+1, crealf(y[i]), cimagf(y[i])); // compute the PSD of each input and plot results on a square grid fprintf(fid,"nfft = 1024;\n"); // TODO: use nextpow2 fprintf(fid,"f = [0:(nfft-1)]/nfft - 0.5;\n"); fprintf(fid,"n = ceil(sqrt(num_channels));\n"); fprintf(fid,"figure;\n"); fprintf(fid,"for i=1:num_channels,\n"); fprintf(fid," X = 20*log10(abs(fftshift(fft(x(i,:),nfft))));\n"); fprintf(fid," subplot(n,n,i);\n"); fprintf(fid," plot(f, X, 'Color', [0.25 0 0.25], 'LineWidth', 1.5);\n"); fprintf(fid," axis([-0.5 0.5 -120 20]);\n"); fprintf(fid," grid on;\n"); fprintf(fid," title(num2str(i-1));\n"); fprintf(fid,"end;\n"); // plot results fprintf(fid,"\n"); fprintf(fid,"H = 20*log10(abs(fftshift(fft(h/num_channels,nfft))));\n"); fprintf(fid,"Y = 20*log10(abs(fftshift(fft(y/num_channels,nfft))));\n"); fprintf(fid,"figure;\n"); fprintf(fid,"subplot(2,1,1);\n"); fprintf(fid," plot(f, H, 'Color', [0 0.5 0.25], 'LineWidth', 2);\n"); fprintf(fid," axis([-0.5 0.5 -100 10]);\n"); fprintf(fid," grid on;\n"); fprintf(fid," xlabel('Normalized Frequency [f/F_s]');\n"); fprintf(fid," ylabel('Prototype Filter PSD');\n"); fprintf(fid,"subplot(2,1,2);\n"); fprintf(fid," plot(f, Y, 'Color', [0 0.25 0.5], 'LineWidth', 2);\n"); fprintf(fid," axis([-0.5 0.5 -100 0]);\n"); fprintf(fid," grid on;\n"); fprintf(fid," xlabel('Normalized Frequency [f/F_s]');\n"); fprintf(fid," ylabel('Output PSD');\n"); fclose(fid); printf("results written to %s\n", OUTPUT_FILENAME); printf("done.\n"); return 0; }
int main() { // spectral periodogram options unsigned int nfft = 1024; // spectral periodogram FFT size unsigned int num_samples = 4000; // number of samples float beta = 10.0f; // Kaiser-Bessel window parameter float noise_floor = -60.0f; // noise floor [dB] float alpha = 0.1f; // PSD estimate bandwidth unsigned int i; // derived values float nstd = powf(10.0f, noise_floor/20.0f); // create spectral periodogram unsigned int window_size = nfft/2; // spgramf window size spgramf q = spgramf_create_kaiser(nfft, window_size, beta); // generate signal (filter with frequency offset) unsigned int h_len = 91; // filter length float fc = 0.07f; // filter cut-off frequency float f0 = 0.20f; // filter center frequency float As = 60.0f; // filter stop-band attenuation float h[h_len]; // filter coefficients liquid_firdes_kaiser(h_len, fc, As, 0, h); // add frequency offset for (i=0; i<h_len; i++) h[i] *= cosf(2*M_PI*f0*i); firfilt_rrrf filter = firfilt_rrrf_create(h, h_len); firfilt_rrrf_set_scale(filter, 2.0f*fc); for (i=0; i<num_samples; i++) { // generate random sample float x = randnf(); // filter float y = 0; firfilt_rrrf_push(filter, x); firfilt_rrrf_execute(filter, &y); // add noise y += nstd * randnf(); // push resulting sample through periodogram spgramf_accumulate_psd(q, &y, alpha, 1); } // compute power spectral density output float psd[nfft]; spgramf_write_accumulation(q, psd); // destroy objects firfilt_rrrf_destroy(filter); spgramf_destroy(q); // // export output file // FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n\n"); fprintf(fid,"nfft = %u;\n", nfft); fprintf(fid,"f = [0:(nfft-1)]/nfft - 0.5;\n"); fprintf(fid,"H = zeros(1,nfft);\n"); fprintf(fid,"noise_floor = %12.6f;\n", noise_floor); for (i=0; i<nfft; i++) fprintf(fid,"H(%6u) = %12.4e;\n", i+1, psd[i]); fprintf(fid,"figure;\n"); fprintf(fid,"plot(f, H, '-', 'LineWidth',1.5);\n"); fprintf(fid,"xlabel('Normalized Frequency [f/F_s]');\n"); fprintf(fid,"ylabel('Power Spectral Density [dB]');\n"); fprintf(fid,"grid on;\n"); fprintf(fid,"ymin = 10*floor([noise_floor-20]/10);\n"); fprintf(fid,"ymax = 10*floor([noise_floor+80]/10);\n"); fprintf(fid,"axis([-0.5 0.5 ymin ymax]);\n"); fclose(fid); printf("results written to %s.\n", OUTPUT_FILENAME); printf("done.\n"); return 0; }
// 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 GMSK receive filter // _k : samples/symbol // _m : symbol delay // _beta : rolloff factor (0 < beta <= 1) // _dt : fractional sample delay // _h : output coefficient buffer (length: 2*k*m+1) void liquid_firdes_gmskrx(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h) { // validate input if ( _k < 1 ) { fprintf(stderr,"error: liquid_firdes_gmskrx(): k must be greater than 0\n"); exit(1); } else if ( _m < 1 ) { fprintf(stderr,"error: liquid_firdes_gmskrx(): m must be greater than 0\n"); exit(1); } else if ( (_beta < 0.0f) || (_beta > 1.0f) ) { fprintf(stderr,"error: liquid_firdes_gmskrx(): beta must be in [0,1]\n"); exit(1); } else; unsigned int k = _k; unsigned int m = _m; float BT = _beta; // internal options float beta = BT; // prototype filter cut-off float delta = 1e-3f; // filter design correction factor liquid_firfilt_type prototype = LIQUID_FIRFILT_KAISER; // Nyquist prototype unsigned int i; // derived values unsigned int h_len = 2*k*m+1; // filter length // arrays float ht[h_len]; // transmit filter coefficients float hr[h_len]; // recieve filter coefficients // design transmit filter liquid_firdes_gmsktx(k,m,BT,0.0f,ht); // // start of filter design procedure // // 'internal' arrays float h_primef[h_len]; // temporary buffer for real 'prototype' coefficients float g_primef[h_len]; // temporary buffer for real 'gain' coefficient float complex h_tx[h_len]; // impulse response of transmit filter float complex h_prime[h_len]; // impulse response of 'prototype' filter float complex g_prime[h_len]; // impulse response of 'gain' filter float complex h_hat[h_len]; // impulse response of receive filter float complex H_tx[h_len]; // frequency response of transmit filter float complex H_prime[h_len]; // frequency response of 'prototype' filter float complex G_prime[h_len]; // frequency response of 'gain' filter float complex H_hat[h_len]; // frequency response of receive filter // create 'prototype' matched filter liquid_firdes_nyquist(prototype,k,m,beta,0.0f,h_primef); // create 'gain' filter to improve stop-band rejection float fc = (0.7f + 0.1*beta) / (float)k; float As = 60.0f; liquid_firdes_kaiser(h_len, fc, As, 0.0f, g_primef); // copy to fft input buffer, shifting appropriately for (i=0; i<h_len; i++) { h_prime[i] = h_primef[ (i+k*m)%h_len ]; g_prime[i] = g_primef[ (i+k*m)%h_len ]; h_tx[i] = ht[ (i+k*m)%h_len ]; } // run ffts fft_run(h_len, h_prime, H_prime, LIQUID_FFT_FORWARD, 0); fft_run(h_len, g_prime, G_prime, LIQUID_FFT_FORWARD, 0); fft_run(h_len, h_tx, H_tx, LIQUID_FFT_FORWARD, 0); // find minimum of reponses float H_tx_min = 0.0f; float H_prime_min = 0.0f; float G_prime_min = 0.0f; for (i=0; i<h_len; i++) { if (i==0 || crealf(H_tx[i]) < H_tx_min) H_tx_min = crealf(H_tx[i]); if (i==0 || crealf(H_prime[i]) < H_prime_min) H_prime_min = crealf(H_prime[i]); if (i==0 || crealf(G_prime[i]) < G_prime_min) G_prime_min = crealf(G_prime[i]); } // compute 'prototype' response, removing minima, and add correction factor for (i=0; i<h_len; i++) { // compute response necessary to yeild prototype response (not exact, but close) H_hat[i] = crealf(H_prime[i] - H_prime_min + delta) / crealf(H_tx[i] - H_tx_min + delta); // include additional term to add stop-band suppression H_hat[i] *= crealf(G_prime[i] - G_prime_min) / crealf(G_prime[0]); } // compute ifft and copy response fft_run(h_len, H_hat, h_hat, LIQUID_FFT_BACKWARD, 0); for (i=0; i<h_len; i++) hr[i] = crealf( h_hat[(i+k*m+1)%h_len] ) / (float)(k*h_len); // copy result, scaling by (samples/symbol)^2 for (i=0; i<h_len; i++) _h[i] = hr[i]*_k*_k; }
int main(int argc, char*argv[]) { // options unsigned int h_len=19; // filter length unsigned int p=5; // polynomial order float fc=0.45f; // filter cutoff float As=60.0f; // stop-band attenuation [dB] float mu=0.1f; // fractional sample delay unsigned int num_samples=60; // number of samples to evaluate int verbose = 0; // verbose output? int dopt; while ((dopt = getopt(argc,argv,"hvt:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'v': verbose = 1; break; case 't': mu = atof(optarg); break; default: exit(1); } } // data arrays float x[num_samples]; // input data array float y[num_samples]; // output data array // create and initialize Farrow filter object firfarrow_rrrf f = firfarrow_rrrf_create(h_len, p, fc, As); firfarrow_rrrf_set_delay(f, mu); unsigned int i; // generate input (filtered noise) float hx[21]; liquid_firdes_kaiser(15, 0.1, 60, 0, hx); firfilt_rrrf fx = firfilt_rrrf_create(hx, 15); for (i=0; i<num_samples; i++) { firfilt_rrrf_push(fx, i < 40 ? randnf() : 0.0f); firfilt_rrrf_execute(fx, &x[i]); } firfilt_rrrf_destroy(fx); // push input through filter for (i=0; i<num_samples; i++) { firfarrow_rrrf_push(f, x[i]); firfarrow_rrrf_execute(f, &y[i]); } // destroy Farrow filter object firfarrow_rrrf_destroy(f); FILE*fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\nclose all;\n\n"); fprintf(fid,"h_len = %u;\n", h_len); fprintf(fid,"mu = %f;\n", mu); fprintf(fid,"num_samples = %u;\n", num_samples); for (i=0; i<num_samples; i++) { fprintf(fid,"x(%4u) = %12.4e; y(%4u) = %12.4e;\n", i+1, x[i], i+1, y[i]); } // plot the results fprintf(fid,"\n\n"); fprintf(fid,"figure;\n"); fprintf(fid,"tx = 0:(num_samples-1); %% input time scale\n"); fprintf(fid,"ty = tx - (h_len-1)/2 + mu; %% output time scale\n"); fprintf(fid,"plot(tx, x,'-s','MarkerSize',3, ...\n"); fprintf(fid," ty, y,'-s','MarkerSize',3);\n"); fprintf(fid,"legend('input','output',0);\n"); fclose(fid); printf("results written to %s\n", OUTPUT_FILENAME); printf("done.\n"); return 0; }
int main(int argc, char*argv[]) { // options unsigned int num_channels=6; // number of channels (must be even) unsigned int m=4; // filter delay unsigned int num_symbols=4*m; // number of symbols // validate input if (num_channels%2) { fprintf(stderr,"error: %s, number of channels must be even\n", argv[0]); exit(1); } // derived values unsigned int num_samples = num_channels * num_symbols; unsigned int i; unsigned int j; // generate filter // NOTE : these coefficients can be random; the purpose of this // exercise is to demonstrate mathematical equivalence #if 0 unsigned int h_len = 2*m*num_channels; float h[h_len]; for (i=0; i<h_len; i++) h[i] = randnf(); #else unsigned int h_len = 2*m*num_channels+1; float h[h_len]; // NOTE: 81.29528 dB > beta = 8.00000 (6 channels, m=4) liquid_firdes_kaiser(h_len, 1.0f/(float)num_channels, 81.29528f, 0.0f, h); #endif // normalize float hsum = 0.0f; for (i=0; i<h_len; i++) hsum += h[i]; for (i=0; i<h_len; i++) h[i] = h[i] * num_channels / hsum; // sub-sampled filters for M=6 channels, m=4, beta=8.0 // -3.2069e-19 -6.7542e-04 -1.3201e-03 2.2878e-18 3.7613e-03 5.8033e-03 // -7.2899e-18 -1.2305e-02 -1.7147e-02 1.6510e-17 3.1187e-02 4.0974e-02 // -3.0032e-17 -6.8026e-02 -8.6399e-02 4.6273e-17 1.3732e-01 1.7307e-01 // -6.2097e-17 -2.8265e-01 -3.7403e-01 7.3699e-17 8.0663e-01 1.6438e+00 // 2.0001e+00 1.6438e+00 8.0663e-01 7.3699e-17 -3.7403e-01 -2.8265e-01 // -6.2097e-17 1.7307e-01 1.3732e-01 4.6273e-17 -8.6399e-02 -6.8026e-02 // -3.0032e-17 4.0974e-02 3.1187e-02 1.6510e-17 -1.7147e-02 -1.2305e-02 // -7.2899e-18 5.8033e-03 3.7613e-03 2.2878e-18 -1.3201e-03 -6.7542e-04 // create filterbank manually dotprod_crcf dp[num_channels]; // vector dot products windowcf w[num_channels]; // window buffers #if DEBUG // print coefficients printf("h_prototype:\n"); for (i=0; i<h_len; i++) printf(" h[%3u] = %12.8f\n", i, h[i]); #endif // create objects unsigned int h_sub_len = 2*m; float h_sub[h_sub_len]; for (i=0; i<num_channels; i++) { // sub-sample prototype filter #if 0 for (j=0; j<h_sub_len; j++) h_sub[j] = h[j*num_channels+i]; #else // load coefficients in reverse order for (j=0; j<h_sub_len; j++) h_sub[h_sub_len-j-1] = h[j*num_channels+i]; #endif // create window buffer and dotprod objects dp[i] = dotprod_crcf_create(h_sub, h_sub_len); w[i] = windowcf_create(h_sub_len); #if DEBUG printf("h_sub[%u] : \n", i); for (j=0; j<h_sub_len; j++) printf(" h[%3u] = %12.8f\n", j, h_sub[j]); #endif } // generate DFT object float complex x[num_channels]; // time-domain buffer float complex X[num_channels]; // freq-domain buffer #if 1 fftplan fft = fft_create_plan(num_channels, X, x, LIQUID_FFT_BACKWARD, 0); #else fftplan fft = fft_create_plan(num_channels, X, x, LIQUID_FFT_FORWARD, 0); #endif float complex y[num_samples]; // time-domain input float complex Y0[2*num_symbols][num_channels]; // channelizer output float complex Y1[2*num_symbols][num_channels]; // conventional output // generate input sequence for (i=0; i<num_samples; i++) { //y[i] = randnf() * cexpf(_Complex_I*randf()*2*M_PI); y[i] = (i==0) ? 1.0f : 0.0f; y[i] = cexpf(_Complex_I*sqrtf(2.0f)*i*i); printf("y[%3u] = %12.8f + %12.8fj\n", i, crealf(y[i]), cimagf(y[i])); } // // run analysis filter bank // #if 0 unsigned int filter_index = 0; #else unsigned int filter_index = num_channels/2-1; #endif float complex y_hat; // input sample float complex * r; // buffer read pointer int toggle = 0; // flag indicating buffer/filter alignment // for (i=0; i<2*num_symbols; i++) { // load buffers in blocks of num_channels/2 for (j=0; j<num_channels/2; j++) { // grab sample y_hat = y[i*num_channels/2 + j]; // push sample into buffer at filter index windowcf_push(w[filter_index], y_hat); // decrement filter index filter_index = (filter_index + num_channels - 1) % num_channels; //filter_index = (filter_index + 1) % num_channels; } // execute filter outputs // reversing order of output (not sure why this is necessary) unsigned int offset = toggle ? num_channels/2 : 0; toggle = 1-toggle; for (j=0; j<num_channels; j++) { unsigned int buffer_index = (offset+j)%num_channels; unsigned int dotprod_index = j; windowcf_read(w[buffer_index], &r); //dotprod_crcf_execute(dp[dotprod_index], r, &X[num_channels-j-1]); dotprod_crcf_execute(dp[dotprod_index], r, &X[buffer_index]); } printf("***** i = %u\n", i); for (j=0; j<num_channels; j++) printf(" v2[%4u] = %12.8f + %12.8fj\n", j, crealf(X[j]), cimagf(X[j])); // execute DFT, store result in buffer 'x' fft_execute(fft); // scale fft output for (j=0; j<num_channels; j++) x[j] *= 1.0f / (num_channels); // move to output array for (j=0; j<num_channels; j++) Y0[i][j] = x[j]; } // destroy objects for (i=0; i<num_channels; i++) { dotprod_crcf_destroy(dp[i]); windowcf_destroy(w[i]); } fft_destroy_plan(fft); // // run traditional down-converter (inefficient) // // generate filter object firfilt_crcf f = firfilt_crcf_create(h, h_len); float dphi; // carrier frequency unsigned int n=0; for (i=0; i<num_channels; i++) { // reset filter firfilt_crcf_clear(f); // set center frequency dphi = 2.0f * M_PI * (float)i / (float)num_channels; // reset symbol counter n=0; for (j=0; j<num_samples; j++) { // push down-converted sample into filter firfilt_crcf_push(f, y[j]*cexpf(-_Complex_I*j*dphi)); // compute output at the appropriate sample time assert(n<2*num_symbols); if ( ((j+1)%(num_channels/2))==0 ) { firfilt_crcf_execute(f, &Y1[n][i]); n++; } } assert(n==2*num_symbols); } firfilt_crcf_destroy(f); // print filterbank channelizer printf("\n"); printf("filterbank channelizer:\n"); for (i=0; i<2*num_symbols; i++) { printf("%2u:", i); for (j=0; j<num_channels; j++) { printf("%6.3f+%6.3fj, ", crealf(Y0[i][j]), cimagf(Y0[i][j])); } printf("\n"); } #if 0 // print traditional channelizer printf("\n"); printf("traditional channelizer:\n"); for (i=0; i<2*num_symbols; i++) { printf("%2u:", i); for (j=0; j<num_channels; j++) { printf("%6.3f+%6.3fj, ", crealf(Y1[i][j]), cimagf(Y1[i][j])); } printf("\n"); } // // compare results // float mse[num_channels]; float complex d; for (i=0; i<num_channels; i++) { mse[i] = 0.0f; for (j=0; j<2*num_symbols; j++) { d = Y0[j][i] - Y1[j][i]; mse[i] += crealf(d*conjf(d)); } mse[i] /= num_symbols; } printf("\n"); printf(" e:"); for (i=0; i<num_channels; i++) printf("%12.4e ", sqrt(mse[i])); printf("\n"); #endif printf("done.\n"); return 0; }