// liquid_filter_crosscorr() // // Compute cross-correlation of two filters at a specific lag. // // _h : filter coefficients [size: _h_len] // _h_len : filter length // _g : filter coefficients [size: _g_len] // _g_len : filter length // _lag : cross-correlation lag (samples) float liquid_filter_crosscorr(float * _h, unsigned int _h_len, float * _g, unsigned int _g_len, int _lag) { // cross-correlation is odd symmetric if (_h_len < _g_len) { return liquid_filter_crosscorr(_g, _g_len, _h, _h_len, -_lag); } // at this point _h_len > _g_len // assert(_h_len > _g_len); if (_lag <= -(int)_g_len) return 0.0f; if (_lag >= (int)_h_len) return 0.0f; int ig = _lag < 0 ? -_lag : 0; // starting index for _g int ih = _lag > 0 ? _lag : 0; // starting index for _h // compute length of overlap // condition 1: condition 2: condition 3: // [------ h ------] [------ h ------] [------ h ------] // [-- g --] [-- g --] [-- g --] // >| n |< >| n |< >| n |< // int n; if (_lag < 0) n = (int)_g_len + _lag; else if (_lag < (_h_len-_g_len)) n = _g_len; else n = _h_len - _lag; // compute cross-correlation float rxy=0.0f; // initialize auto-correlation to zero int i; for (i=0; i< n; i++) rxy += _h[ih+i] * _g[ig+i]; return rxy; }
int main(int argc, char*argv[]) { // options unsigned int k=4; // filter samples/symbol unsigned int m=3; // filter delay [symbols] float beta = 0.3f; // filter excess bandwidth factor // 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': beta = 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 (beta <= 0.0f || beta >= 1.0f) { fprintf(stderr,"error: %s, beta 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 // // start of filter design procedure // float H_prime[h_len]; // frequency response of Nyquist filter float complex h_tx[h_len]; // impulse response of square-root Nyquist filter float complex H_tx[h_len]; // frequency response of square-root Nyquist filter // compute frequency response of Nyquist filter for (i=0; i<h_len; i++) { float f = (float)i / (float)h_len; if (f > 0.5f) f = f - 1.0f; H_prime[i] = firdes_freqresponse_fexp(f,k,beta); } // compute square-root response, copy to fft input for (i=0; i<h_len; i++) H_tx[i] = sqrtf(H_prime[i]); // compute ifft and copy response fft_run(h_len, H_tx, h_tx, LIQUID_FFT_BACKWARD, 0); for (i=0; i<h_len; i++) ht[i] = crealf( h_tx[(i+k*m+1)%h_len] ) / (float)(h_len); // copy receive... for (i=0; i<h_len; i++) hr[i] = ht[i]; #if 0 // print results for (i=0; i<h_len; i++) printf("H_prime(%3u) = %12.8f;\n", i+1, H_prime[i]); #endif // // end of filter design procedure // // print results to screen printf("fexp 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", beta); 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]); for (i=0; i<h_len; i++) fprintf(fid,"hr(%3u) = %12.4e;\n", i+1, hr[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,"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,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','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('fexp 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('fexp 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(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(int argc, char*argv[]) { // options unsigned int k=2; // samples/symbol unsigned int m=3; // symbol delay float beta=0.7f; // excess bandwidth factor unsigned int num_symbols=16; int ftype_tx = LIQUID_FIRFILT_RRC; int ftype_rx = LIQUID_FIRFILT_RRC; int dopt; while ((dopt = getopt(argc,argv,"uht:k:m:b:n:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 't': if (strcmp(optarg,"gmsk")==0) { ftype_tx = LIQUID_FIRFILT_GMSKTX; ftype_rx = LIQUID_FIRFILT_GMSKRX; } else { ftype_tx = liquid_getopt_str2firfilt(optarg); ftype_rx = liquid_getopt_str2firfilt(optarg); } if (ftype_tx == LIQUID_FIRFILT_UNKNOWN) { fprintf(stderr,"error: %s, unknown filter type '%s'\n", argv[0], optarg); exit(1); } break; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'b': beta = atof(optarg); break; case 'n': num_symbols = atoi(optarg); break; default: exit(1); } } 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 (beta <= 0.0f || beta >= 1.0f) { fprintf(stderr,"error: %s, beta must be in (0,1)\n", argv[0]); exit(1); } unsigned int i; // derived values unsigned int num_samples = num_symbols*k; unsigned int h_len = 2*k*m+1; // transmit/receive filter length unsigned int hc_len = 4*k*m+1; // composite filter length // arrays float ht[h_len]; // transmit filter float hr[h_len]; // receive filter float hc[hc_len]; // composite filter // design the filter(s) liquid_firdes_rnyquist(ftype_tx, k, m, beta, 0, ht); liquid_firdes_rnyquist(ftype_rx, k, m, beta, 0, hr); for (i=0; i<h_len; i++) printf("ht(%3u) = %12.8f;\n", i+1, ht[i]); for (i=0; i<h_len; i++) printf("hr(%3u) = %12.8f;\n", i+1, hr[i]); #if 0 // generate receive filter coefficients (reverse of transmit) float hr[h_len]; for (i=0; i<h_len; i++) hr[i] = ht[h_len-i-1]; #endif // compute composite filter response for (i=0; i<4*k*m+1; i++) { int lag = (int)i - (int)(2*k*m); hc[i] = liquid_filter_crosscorr(ht,h_len, hr,h_len, lag); } // compute filter inter-symbol interference float rxy0 = liquid_filter_crosscorr(ht,h_len, hr,h_len, 0); float isi_rms=0; 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(" isi (rms) : %12.8f dB\n", 20*log10f(isi_rms)); // compute relative stop-band energy unsigned int nfft = 2048; float As = liquid_filter_energy(ht, h_len, 0.5f*(1.0f + beta)/(float)k, nfft); printf(" As : %12.8f dB\n", 20*log10f(As)); // generate signal float sym_in[num_symbols]; float y[num_samples]; float sym_out[num_symbols]; // create interpolator and decimator firinterp_rrrf interp = firinterp_rrrf_create(k, ht, h_len); firdecim_rrrf decim = firdecim_rrrf_create( k, hr, h_len); for (i=0; i<num_symbols; i++) { // generate random symbol sym_in[i] = (rand() % 2) ? 1.0f : -1.0f; // interpolate firinterp_rrrf_execute(interp, sym_in[i], &y[i*k]); // decimate firdecim_rrrf_execute(decim, &y[i*k], &sym_out[i]); // normalize output sym_out[i] /= k; printf(" %3u : %8.5f", i, sym_out[i]); if (i>=2*m) printf(" *\n"); else printf("\n"); } // clean up objects firinterp_rrrf_destroy(interp); firdecim_rrrf_destroy(decim); // // export results // 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,"k = %u;\n", k); fprintf(fid,"m = %u;\n", m); fprintf(fid,"beta = %12.8f;\n", beta); fprintf(fid,"num_symbols = %u;\n", num_symbols); fprintf(fid,"num_samples = k*num_symbols;\n"); fprintf(fid,"y = zeros(1,num_samples);\n"); for (i=0; i<num_samples; i++) fprintf(fid," y(%3u) = %12.8f;\n", i+1, y[i]); for (i=0; i<h_len; i++) fprintf(fid,"ht(%3u) = %20.8e;\n", i+1, ht[i]); for (i=0; i<h_len; i++) fprintf(fid,"hr(%3u) = %20.8e;\n", i+1, hr[i]); for (i=0; i<hc_len; i++) fprintf(fid,"hc(%3u) = %20.8e;\n", i+1, hc[i]); fprintf(fid,"nfft=1024;\n"); fprintf(fid,"f = [0:(nfft-1)]/nfft - 0.5;\n"); fprintf(fid,"Ht = 20*log10(abs(fftshift(fft(ht/k, nfft))));\n"); fprintf(fid,"Hr = 20*log10(abs(fftshift(fft(hr/k, nfft))));\n"); fprintf(fid,"Hc = 20*log10(abs(fftshift(fft(hc/k^2, nfft))));\n"); fprintf(fid,"figure;\n"); fprintf(fid,"plot(f,Hc,'-','LineWidth',2,...\n"); fprintf(fid," [0.5/k],[-6],'or',...\n"); fprintf(fid," [0.5/k*(1-beta) 0.5/k*(1-beta)],[-100 10],'-r',...\n"); fprintf(fid," [0.5/k*(1+beta) 0.5/k*(1+beta)],[-100 10],'-r');\n"); fprintf(fid,"xlabel('normalized frequency');\n"); fprintf(fid,"ylabel('PSD');\n"); fprintf(fid,"axis([-0.5 0.5 -100 10]);\n"); fprintf(fid,"grid on;\n"); // compute composite filter fprintf(fid,"figure;\n"); fprintf(fid,"hc = conv(ht,hr)/k;\n"); fprintf(fid,"t = [(-2*k*m):(2*k*m)]/k;\n"); fprintf(fid,"i0 = [0:k:4*k*m]+1;\n"); fprintf(fid,"plot(t, hc, '-s',...\n"); fprintf(fid," t(i0),hc(i0),'or');\n"); fprintf(fid,"xlabel('symbol index');\n"); fprintf(fid,"ylabel('matched filter response');\n"); fprintf(fid,"grid on;\n"); fclose(fid); printf("results written to %s.\n", OUTPUT_FILENAME); printf("done.\n"); return 0; }