PfbSynthesizerComponent::PfbSynthesizerComponent(std::string name) : PhyComponent(name, // component name "pfbsynthesizer", // component type "A polyphase filterbank synthesizer", // description "Paul Sutton", // author "0.1") // version { taps.push_back(0.0f); channelizer = firpfbch_crcf_create(LIQUID_SYNTHESIZER, 1, 1, &taps[0]); registerParameter( "debug", "Running in debug mode?", "false", false, debug_x); registerParameter( "numchannels", "Number of channels", "8", false, nChans_x, Interval<int>(1,65536)); }
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() { // options unsigned int num_channels=4; // number of channels unsigned int p=3; // filter length (symbols) unsigned int num_symbols=6; // number of symbols // derived values unsigned int num_samples = num_channels * num_symbols; unsigned int i; unsigned int j; // generate synthesis filter // NOTE : these coefficients can be random; the purpose of this // exercise is to demonstrate mathematical equivalence unsigned int h_len = p*num_channels; float h[h_len]; for (i=0; i<h_len; i++) h[i] = randnf(); // generate analysis filter unsigned int g_len = p*num_channels; float g[g_len]; for (i=0; i<g_len; i++) g[i] = h[g_len-i-1]; // create synthesis/analysis filter objects firfilt_crcf fs = firfilt_crcf_create(h, h_len); firfilt_crcf fa = firfilt_crcf_create(g, g_len); // create synthesis/analysis filterbank channelizer objects firpfbch_crcf qs = firpfbch_crcf_create(LIQUID_SYNTHESIZER, num_channels, p, h); firpfbch_crcf qa = firpfbch_crcf_create(LIQUID_ANALYZER, num_channels, p, g); float complex x[num_samples]; // random input (noise) float complex Y0[num_symbols][num_channels]; // channelized output (filterbank) float complex Y1[num_symbols][num_channels]; // channelized output float complex z0[num_samples]; // time-domain output (filterbank) float complex z1[num_samples]; // time-domain output // generate input sequence (complex noise) for (i=0; i<num_samples; i++) x[i] = randnf() * cexpf(_Complex_I*randf()*2*M_PI); // // ANALYZERS // // // run analysis filter bank // for (i=0; i<num_symbols; i++) firpfbch_crcf_analyzer_execute(qa, &x[i*num_channels], &Y0[i][0]); // // run traditional down-converter (inefficient) // float dphi; // carrier frequency unsigned int n=0; for (i=0; i<num_channels; i++) { // reset filter firfilt_crcf_clear(fa); // 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(fa, x[j]*cexpf(-_Complex_I*j*dphi)); // compute output at the appropriate sample time assert(n<num_symbols); if ( ((j+1)%num_channels)==0 ) { firfilt_crcf_execute(fa, &Y1[n][i]); n++; } } assert(n==num_symbols); } // // SYNTHESIZERS // // // run synthesis filter bank // for (i=0; i<num_symbols; i++) firpfbch_crcf_synthesizer_execute(qs, &Y0[i][0], &z0[i*num_channels]); // // run traditional up-converter (inefficient) // // clear output array for (i=0; i<num_samples; i++) z1[i] = 0.0f; float complex y_hat; for (i=0; i<num_channels; i++) { // reset filter firfilt_crcf_clear(fs); // set center frequency dphi = 2.0f * M_PI * (float)i / (float)num_channels; // reset input symbol counter n=0; for (j=0; j<num_samples; j++) { // interpolate sequence if ( (j%num_channels)==0 ) { assert(n<num_symbols); firfilt_crcf_push(fs, Y1[n][i]); n++; } else { firfilt_crcf_push(fs, 0); } firfilt_crcf_execute(fs, &y_hat); // accumulate up-converted sample z1[j] += y_hat * cexpf(_Complex_I*j*dphi); } assert(n==num_symbols); } // destroy objects firfilt_crcf_destroy(fs); firfilt_crcf_destroy(fa); firpfbch_crcf_destroy(qs); firpfbch_crcf_destroy(qa); // // RESULTS // // // analyzers // // print filterbank channelizer printf("\n"); printf("filterbank channelizer:\n"); for (i=0; i<num_symbols; i++) { printf("%3u: ", i); for (j=0; j<num_channels; j++) { printf(" %8.5f+j%8.5f, ", crealf(Y0[i][j]), cimagf(Y0[i][j])); } printf("\n"); } // print traditional channelizer printf("\n"); printf("traditional channelizer:\n"); for (i=0; i<num_symbols; i++) { printf("%3u: ", i); for (j=0; j<num_channels; j++) { printf(" %8.5f+j%8.5f, ", crealf(Y1[i][j]), cimagf(Y1[i][j])); } printf("\n"); } float mse_analyzer[num_channels]; float complex d; for (i=0; i<num_channels; i++) { mse_analyzer[i] = 0.0f; for (j=0; j<num_symbols; j++) { d = Y0[j][i] - Y1[j][i]; mse_analyzer[i] += crealf(d*conjf(d)); } mse_analyzer[i] /= num_symbols; } printf("\n"); printf("rmse: "); for (i=0; i<num_channels; i++) printf("%12.4e ", sqrt(mse_analyzer[i])); printf("\n"); // // synthesizers // printf("\n"); printf("output: filterbank: traditional:\n"); for (i=0; i<num_samples; i++) { printf("%3u: %10.5f+%10.5fj %10.5f+%10.5fj\n", i, crealf(z0[i]), cimagf(z0[i]), crealf(z1[i]), cimagf(z1[i])); } float mse_synthesizer = 0.0f; for (i=0; i<num_samples; i++) { d = z0[i] - z1[i]; mse_synthesizer += crealf(d*conjf(d)); } mse_synthesizer /= num_samples; printf("\n"); printf("rmse: %12.4e\n", sqrtf(mse_synthesizer)); // // EXPORT DATA 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,"num_symbols=%u;\n", num_symbols); fprintf(fid,"num_samples = num_channels*num_symbols;\n"); fprintf(fid,"x = zeros(1,num_samples);\n"); fprintf(fid,"y0 = zeros(num_symbols,num_channels);\n"); fprintf(fid,"y1 = zeros(num_symbols,num_channels);\n"); fprintf(fid,"z0 = zeros(1,num_samples);\n"); fprintf(fid,"z1 = zeros(1,num_samples);\n"); // input for (i=0; i<num_samples; i++) fprintf(fid,"x(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(x[i]), cimag(x[i])); // analysis for (i=0; i<num_symbols; i++) { for (j=0; j<num_channels; j++) { fprintf(fid,"y0(%4u,%4u) = %12.4e + j*%12.4e;\n", i+1, j+1, crealf(Y0[i][j]), cimag(Y0[i][j])); fprintf(fid,"y1(%4u,%4u) = %12.4e + j*%12.4e;\n", i+1, j+1, crealf(Y1[i][j]), cimag(Y1[i][j])); } } // synthesis for (i=0; i<num_samples; i++) { fprintf(fid,"z0(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(z0[i]), cimag(z0[i])); fprintf(fid,"z1(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(z1[i]), cimag(z1[i])); } fprintf(fid,"z0 = z0 / num_channels;\n"); fprintf(fid,"z1 = z1 / num_channels;\n"); // plot results fprintf(fid,"\n\n"); fprintf(fid,"ts = 0:(num_symbols-1);\n"); fprintf(fid,"for i=1:num_channels,\n"); fprintf(fid,"figure;\n"); fprintf(fid,"title(['channel ' num2str(i)]);\n"); fprintf(fid,"subplot(2,1,1);\n"); fprintf(fid," plot(ts,real(y0(:,i)),'-x', ts,real(y1(:,i)),'s');\n"); //fprintf(fid," axis([0 (num_symbols-1) -2 2]);\n"); fprintf(fid,"subplot(2,1,2);\n"); fprintf(fid," plot(ts,imag(y0(:,i)),'-x', ts,imag(y1(:,i)),'s');\n"); //fprintf(fid," axis([0 (num_symbols-1) -2 2]);\n"); fprintf(fid,"end;\n"); fprintf(fid,"t = 0:(num_samples-1);\n"); fprintf(fid,"figure;\n"); fprintf(fid,"title('composite');\n"); fprintf(fid,"subplot(2,1,1);\n"); fprintf(fid," plot(t,real(z0),'-x', t,real(z1),'s');\n"); fprintf(fid,"subplot(2,1,2);\n"); fprintf(fid," plot(t,imag(z0),'-x', t,imag(z1),'s');\n"); fclose(fid); printf("results written to '%s'\n", OUTPUT_FILENAME); printf("done.\n"); 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; }
// // AUTOTEST: validate analysis correctness // void autotest_firpfbch_crcf_analysis() { float tol = 1e-4f; // error tolerance unsigned int num_channels=4; // number of channels unsigned int p=5; // filter length (symbols) unsigned int num_symbols=12; // number of symbols // 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 unsigned int h_len = p*num_channels; float h[h_len]; for (i=0; i<h_len; i++) h[i] = randnf(); // create filterbank object firpfbch_crcf q = firpfbch_crcf_create(LIQUID_ANALYZER, num_channels, p, h); // generate filter object firfilt_crcf f = firfilt_crcf_create(h, h_len); // allocate memory for arrays float complex y[num_samples]; // time-domain input float complex Y0[num_symbols][num_channels]; // channelized output float complex Y1[num_symbols][num_channels]; // channelized output // generate input sequence (complex noise) for (i=0; i<num_samples; i++) y[i] = randnf() * cexpf(_Complex_I*randf()*2*M_PI); // // run analysis filter bank // for (i=0; i<num_symbols; i++) firpfbch_crcf_analyzer_execute(q, &y[i*num_channels], &Y0[i][0]); // // run traditional down-converter (inefficient) // 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<num_symbols); if ( ((j+1)%num_channels)==0 ) { firfilt_crcf_execute(f, &Y1[n][i]); n++; } } assert(n==num_symbols); } // destroy objects firfilt_crcf_destroy(f); firpfbch_crcf_destroy(q); if (liquid_autotest_verbose) { // print filterbank channelizer printf("\n"); printf("filterbank channelizer:\n"); for (i=0; i<num_symbols; i++) { printf("%3u: ", i); for (j=0; j<num_channels; j++) { printf(" %8.5f+j%8.5f, ", crealf(Y0[i][j]), cimagf(Y0[i][j])); } printf("\n"); } // print traditional channelizer printf("\n"); printf("traditional channelizer:\n"); for (i=0; i<num_symbols; i++) { printf("%3u: ", i); for (j=0; j<num_channels; j++) { printf(" %8.5f+j%8.5f, ", crealf(Y1[i][j]), cimagf(Y1[i][j])); } printf("\n"); } } // compare results for (i=0; i<num_symbols; i++) { for (j=0; j<num_channels; j++) { CONTEND_DELTA( crealf(Y0[i][j]), crealf(Y1[i][j]), tol ); CONTEND_DELTA( cimagf(Y0[i][j]), cimagf(Y1[i][j]), tol ); } } }