// Helper function to keep code base small void resamp_crcf_bench(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations, unsigned int _P, unsigned int _Q) { // adjust number of iterations: cycles/trial ~ 500 + 100 Q *_num_iterations /= (500 + 100*_Q); // create resampling object; irrational rate is just less than Q/P float rate = (float)_Q/(float)_P*sqrt(3301.0f/3302.0f); unsigned int m = 12; // filter semi-length float bw = 0.45f; // filter bandwidth float As = 60.0f; // stop-band attenuation [dB] unsigned int npfb = 64; // number of polyphase filters resamp_crcf q = resamp_crcf_create(rate,m,bw,As,npfb); // buffering float complex buf_0[_P]; float complex buf_1[_Q*4]; unsigned int num_written; unsigned long int i; for (i=0; i<_P; i++) buf_0[i] = i % 7 ? 1 : -1; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { resamp_crcf_execute_block(q, buf_0, _P, buf_1, &num_written); resamp_crcf_execute_block(q, buf_0, _P, buf_1, &num_written); resamp_crcf_execute_block(q, buf_0, _P, buf_1, &num_written); resamp_crcf_execute_block(q, buf_0, _P, buf_1, &num_written); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; // destroy object resamp_crcf_destroy(q); }
int main(int argc, char*argv[]) { srand(time(NULL)); // options unsigned int k = 2; // samples/symbol (input) unsigned int k_out = 2; // samples/symbol (output) unsigned int m = 5; // filter delay (symbols) float beta = 0.5f; // filter excess bandwidth factor unsigned int num_filters = 32; // number of filters in the bank unsigned int num_symbols = 400; // number of data symbols float SNRdB = 30.0f; // signal-to-noise ratio // transmit/receive filter types liquid_firfilt_type ftype_tx = LIQUID_FIRFILT_RRC; liquid_firfilt_type ftype_rx = LIQUID_FIRFILT_RRC; float bt = 0.02f; // loop filter bandwidth float tau = -0.2f; // fractional symbol offset float r = 1.00f; // resampled rate // use random data or 101010 phasing pattern int random_data=1; int dopt; while ((dopt = getopt(argc,argv,"hT:k:K:m:b:B:s:w:n:t:r:")) != EOF) { switch (dopt) { 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 'K': k_out = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'b': beta = atof(optarg); break; case 'B': num_filters = atoi(optarg); break; case 's': SNRdB = atof(optarg); break; case 'w': bt = atof(optarg); break; case 'n': num_symbols = atoi(optarg); break; case 't': tau = atof(optarg); break; case 'r': r = atof(optarg); break; default: exit(1); } } // validate input if (k < 2) { fprintf(stderr,"error: k (samples/symbol) must be at least 2\n"); exit(1); } else if (m < 1) { fprintf(stderr,"error: m (filter delay) must be greater than 0\n"); exit(1); } else if (beta <= 0.0f || beta > 1.0f) { fprintf(stderr,"error: beta (excess bandwidth factor) must be in (0,1]\n"); exit(1); } else if (num_filters == 0) { fprintf(stderr,"error: number of polyphase filters must be greater than 0\n"); exit(1); } else if (bt <= 0.0f) { fprintf(stderr,"error: timing PLL bandwidth must be greater than 0\n"); exit(1); } else if (num_symbols == 0) { fprintf(stderr,"error: number of symbols must be greater than 0\n"); exit(1); } else if (tau < -1.0f || tau > 1.0f) { fprintf(stderr,"error: timing phase offset must be in [-1,1]\n"); exit(1); } else if (r < 0.5f || r > 2.0f) { fprintf(stderr,"error: timing frequency offset must be in [0.5,2]\n"); exit(1); } // compute delay while (tau < 0) tau += 1.0f; // ensure positive tau float g = k*tau; // number of samples offset int ds=floorf(g); // additional symbol delay float dt = (g - (float)ds); // fractional sample offset if (dt > 0.5f) { // force dt to be in [0.5,0.5] dt -= 1.0f; ds++; } unsigned int i, n=0; unsigned int num_samples = k*num_symbols; unsigned int num_samples_resamp = (unsigned int) ceilf(num_samples*r*1.1f) + 4; float complex s[num_symbols]; // data symbols float complex x[num_samples]; // interpolated samples float complex y[num_samples_resamp]; // resampled data (resamp_crcf) float complex z[k_out*num_symbols + 64];// synchronized samples float complex sym_out[num_symbols + 64];// synchronized symbols for (i=0; i<num_symbols; i++) { if (random_data) { // random signal (QPSK) s[i] = cexpf(_Complex_I*0.5f*M_PI*((rand() % 4) + 0.5f)); } else { s[i] = (i%2) ? 1.0f : -1.0f; // 101010 phasing pattern } } // // create and run interpolator // // design interpolating filter unsigned int h_len = 2*k*m+1; float h[h_len]; liquid_firdes_rnyquist(ftype_tx,k,m,beta,dt,h); firinterp_crcf q = firinterp_crcf_create(k,h,h_len); for (i=0; i<num_symbols; i++) { firinterp_crcf_execute(q, s[i], &x[n]); n+=k; } assert(n == num_samples); firinterp_crcf_destroy(q); // // run resampler // unsigned int resamp_len = 10*k; // resampling filter semi-length (filter delay) float resamp_bw = 0.45f; // resampling filter bandwidth float resamp_As = 60.0f; // resampling filter stop-band attenuation unsigned int resamp_npfb = 64; // number of filters in bank resamp_crcf f = resamp_crcf_create(r, resamp_len, resamp_bw, resamp_As, resamp_npfb); unsigned int num_samples_resampled = 0; unsigned int num_written; for (i=0; i<num_samples; i++) { #if 0 // bypass arbitrary resampler y[i] = x[i]; num_samples_resampled = num_samples; #else // TODO : compensate for resampler filter delay resamp_crcf_execute(f, x[i], &y[num_samples_resampled], &num_written); num_samples_resampled += num_written; #endif } resamp_crcf_destroy(f); // // add noise // float nstd = powf(10.0f, -SNRdB/20.0f); for (i=0; i<num_samples_resampled; i++) y[i] += nstd*(randnf() + _Complex_I*randnf()); // // create and run symbol synchronizer // symsync_crcf d = symsync_crcf_create_rnyquist(ftype_rx, k, m, beta, num_filters); symsync_crcf_set_lf_bw(d,bt); symsync_crcf_set_output_rate(d,k_out); unsigned int num_samples_sync=0; unsigned int nn; unsigned int num_symbols_sync = 0; float tau_hat[num_samples]; for (i=ds; i<num_samples_resampled; i++) { tau_hat[num_samples_sync] = symsync_crcf_get_tau(d); symsync_crcf_execute(d, &y[i], 1, &z[num_samples_sync], &nn); // decimate unsigned int j; for (j=0; j<nn; j++) { if ( (num_samples_sync%k_out)==0 ) sym_out[num_symbols_sync++] = z[num_samples_sync]; num_samples_sync++; } } symsync_crcf_destroy(d); // print last several symbols to screen printf("output symbols:\n"); printf(" ...\n"); for (i=num_symbols_sync-10; i<num_symbols_sync; i++) printf(" sym_out(%2u) = %8.4f + j*%8.4f;\n", i+1, crealf(sym_out[i]), cimagf(sym_out[i])); // // export output file // FILE* fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s, auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"close all;\nclear all;\n\n"); fprintf(fid,"k=%u;\n",k); fprintf(fid,"m=%u;\n",m); fprintf(fid,"beta=%12.8f;\n",beta); fprintf(fid,"k_out=%u;\n",k_out); fprintf(fid,"num_filters=%u;\n",num_filters); fprintf(fid,"num_symbols=%u;\n",num_symbols); for (i=0; i<h_len; i++) fprintf(fid,"h(%3u) = %12.5f;\n", i+1, h[i]); for (i=0; i<num_symbols; i++) fprintf(fid,"s(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(s[i]), cimagf(s[i])); for (i=0; i<num_samples; i++) fprintf(fid,"x(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(x[i]), cimagf(x[i])); for (i=0; i<num_samples_resampled; i++) fprintf(fid,"y(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(y[i]), cimagf(y[i])); for (i=0; i<num_samples_sync; i++) fprintf(fid,"z(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(z[i]), cimagf(z[i])); for (i=0; i<num_symbols_sync; i++) fprintf(fid,"sym_out(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(sym_out[i]), cimagf(sym_out[i])); for (i=0; i<num_samples_sync; i++) fprintf(fid,"tau_hat(%3u) = %12.8f;\n", i+1, tau_hat[i]); fprintf(fid,"\n\n"); fprintf(fid,"%% scale QPSK in-phase by sqrt(2)\n"); fprintf(fid,"z = z*sqrt(2);\n"); fprintf(fid,"\n\n"); fprintf(fid,"tz = [0:length(z)-1]/k_out;\n"); fprintf(fid,"iz = 1:k_out:length(z);\n"); fprintf(fid,"figure;\n"); fprintf(fid,"plot(tz, real(z), '-',...\n"); fprintf(fid," tz(iz), real(z(iz)),'or');\n"); fprintf(fid,"xlabel('Time');\n"); fprintf(fid,"ylabel('Output Signal (real)');\n"); fprintf(fid,"grid on;\n"); fprintf(fid,"legend('output time series','optimum timing','location','northeast');\n"); fprintf(fid,"iz0 = iz( 1:round(length(iz)*0.5) );\n"); fprintf(fid,"iz1 = iz( round(length(iz)*0.5):length(iz) );\n"); fprintf(fid,"figure;\n"); fprintf(fid,"hold on;\n"); fprintf(fid,"plot(real(z(iz0)),imag(z(iz0)),'x','MarkerSize',4,'Color',[0.6 0.6 0.6]);\n"); fprintf(fid,"plot(real(z(iz1)),imag(z(iz1)),'o','MarkerSize',4,'Color',[0 0.25 0.5]);\n"); fprintf(fid,"hold off;\n"); fprintf(fid,"axis square;\n"); fprintf(fid,"grid on;\n"); fprintf(fid,"axis([-1 1 -1 1]*2.0);\n"); fprintf(fid,"xlabel('In-phase');\n"); fprintf(fid,"ylabel('Quadrature');\n"); fprintf(fid,"legend(['first 50%%'],['last 50%%'],'location','northeast');\n"); fprintf(fid,"figure;\n"); fprintf(fid,"tt = 0:(length(tau_hat)-1);\n"); fprintf(fid,"b = floor(num_filters*tau_hat + 0.5);\n"); fprintf(fid,"stairs(tt,tau_hat*num_filters);\n"); fprintf(fid,"hold on;\n"); fprintf(fid,"plot(tt,b,'-k','Color',[0 0 0]);\n"); fprintf(fid,"hold off;\n"); fprintf(fid,"xlabel('time');\n"); fprintf(fid,"ylabel('filterbank index');\n"); fprintf(fid,"grid on;\n"); fprintf(fid,"axis([0 length(tau_hat) -1 num_filters]);\n"); fclose(fid); printf("results written to %s.\n", OUTPUT_FILENAME); // clean it up printf("done.\n"); return 0; }
int main(int argc, char*argv[]) { // options float r = 1.1f; // resampling rate (output/input) unsigned int m = 13; // resampling filter semi-length (filter delay) float As = 60.0f; // resampling filter stop-band attenuation [dB] float bw = 0.45f; // resampling filter bandwidth unsigned int npfb = 64; // number of filters in bank (timing resolution) unsigned int n = 400; // number of input samples float fc = 0.044f; // complex sinusoid frequency int dopt; while ((dopt = getopt(argc,argv,"hr:m:b:s:p:n:f:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'r': r = atof(optarg); break; case 'm': m = atoi(optarg); break; case 'b': bw = atof(optarg); break; case 's': As = atof(optarg); break; case 'p': npfb = atoi(optarg); break; case 'n': n = atoi(optarg); break; case 'f': fc = atof(optarg); break; default: exit(1); } } // validate input if (r <= 0.0f) { fprintf(stderr,"error: %s, resampling rate must be greater than zero\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 (bw == 0.0f || bw >= 0.5f) { fprintf(stderr,"error: %s, filter bandwidth must be in (0,0.5)\n", argv[0]); exit(1); } else if (As < 0.0f) { fprintf(stderr,"error: %s, filter stop-band attenuation must be greater than zero\n", argv[0]); exit(1); } else if (npfb == 0) { fprintf(stderr,"error: %s, filter bank size must be greater than zero\n", argv[0]); exit(1); } else if (n == 0) { fprintf(stderr,"error: %s, number of input samples must be greater than zero\n", argv[0]); exit(1); } unsigned int i; // number of input samples (zero-padded) unsigned int nx = n + m; // output buffer with extra padding for good measure unsigned int y_len = (unsigned int) ceilf(1.1 * nx * r) + 4; // arrays float complex x[nx]; float complex y[y_len]; // create resampler resamp_crcf q = resamp_crcf_create(r,m,bw,As,npfb); // generate input signal float wsum = 0.0f; for (i=0; i<nx; i++) { // compute window float w = i < n ? kaiser(i, n, 10.0f, 0.0f) : 0.0f; // apply window to complex sinusoid x[i] = cexpf(_Complex_I*2*M_PI*fc*i) * w; // accumulate window wsum += w; } // resample unsigned int ny=0; #if 0 // execute one sample at a time unsigned int nw; for (i=0; i<nx; i++) { // execute resampler, storing in output buffer resamp_crcf_execute(q, x[i], &y[ny], &nw); // increment output size ny += nw; } #else // execute on block of samples resamp_crcf_execute_block(q, x, nx, y, &ny); #endif // clean up allocated objects resamp_crcf_destroy(q); // // analyze resulting signal // // check that the actual resampling rate is close to the target float r_actual = (float)ny / (float)nx; float fy = fc / r; // expected output frequency // run FFT and ensure that carrier has moved and that image // frequencies and distortion have been adequately suppressed unsigned int nfft = 1 << liquid_nextpow2(ny); float complex yfft[nfft]; // fft input float complex Yfft[nfft]; // fft output for (i=0; i<nfft; i++) yfft[i] = i < ny ? y[i] : 0.0f; fft_run(nfft, yfft, Yfft, LIQUID_FFT_FORWARD, 0); fft_shift(Yfft, nfft); // run FFT shift // find peak frequency float Ypeak = 0.0f; float fpeak = 0.0f; float max_sidelobe = -1e9f; // maximum side-lobe [dB] float main_lobe_width = 0.07f; // TODO: figure this out from Kaiser's equations for (i=0; i<nfft; i++) { // normalized output frequency float f = (float)i/(float)nfft - 0.5f; // scale FFT output appropriately float Ymag = 20*log10f( cabsf(Yfft[i] / (r * wsum)) ); // find frequency location of maximum magnitude if (Ymag > Ypeak || i==0) { Ypeak = Ymag; fpeak = f; } // find peak side-lobe value, ignoring frequencies // within a certain range of signal frequency if ( fabsf(f-fy) > main_lobe_width ) max_sidelobe = Ymag > max_sidelobe ? Ymag : max_sidelobe; } // print results and check frequency location printf(" desired resampling rate : %12.8f\n", r); printf(" measured resampling rate : %12.8f (%u/%u)\n", r_actual, ny, nx); printf(" peak spectrum : %12.8f dB (expected 0.0 dB)\n", Ypeak); printf(" peak frequency : %12.8f (expected %-12.8f)\n", fpeak, fy); printf(" max sidelobe : %12.8f dB (expected at least %.2f dB)\n", max_sidelobe, -As); // // export results // 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,"m=%u;\n", m); fprintf(fid,"npfb=%u;\n", npfb); fprintf(fid,"r=%12.8f;\n", r); fprintf(fid,"nx = %u;\n", nx); fprintf(fid,"x = zeros(1,nx);\n"); for (i=0; i<nx; i++) fprintf(fid,"x(%3u) = %12.4e + j*%12.4e;\n", i+1, crealf(x[i]), cimagf(x[i])); fprintf(fid,"ny = %u;\n", ny); fprintf(fid,"y = zeros(1,ny);\n"); for (i=0; i<ny; i++) fprintf(fid,"y(%3u) = %12.4e + j*%12.4e;\n", i+1, crealf(y[i]), cimagf(y[i])); fprintf(fid,"\n\n"); fprintf(fid,"%% plot frequency-domain result\n"); fprintf(fid,"nfft=2^nextpow2(max(nx,ny));\n"); fprintf(fid,"%% estimate PSD, normalize by array length\n"); fprintf(fid,"X=20*log10(abs(fftshift(fft(x,nfft)/length(x))));\n"); fprintf(fid,"Y=20*log10(abs(fftshift(fft(y,nfft)/length(y))));\n"); fprintf(fid,"G=max(X);\n"); fprintf(fid,"X=X-G;\n"); fprintf(fid,"Y=Y-G;\n"); fprintf(fid,"f=[0:(nfft-1)]/nfft-0.5;\n"); fprintf(fid,"figure;\n"); fprintf(fid,"if r>1, fx = f/r; fy = f; %% interpolated\n"); fprintf(fid,"else, fx = f; fy = f*r; %% decimated\n"); fprintf(fid,"end;\n"); fprintf(fid,"plot(fx,X,'Color',[0.5 0.5 0.5],fy,Y,'LineWidth',2);\n"); fprintf(fid,"grid on;\n"); fprintf(fid,"xlabel('normalized frequency');\n"); fprintf(fid,"ylabel('PSD [dB]');\n"); fprintf(fid,"legend('original','resampled','location','northeast');"); fprintf(fid,"axis([-0.5 0.5 -120 20]);\n"); fprintf(fid,"\n\n"); fprintf(fid,"%% plot time-domain result\n"); fprintf(fid,"tx=[0:(length(x)-1)];\n"); fprintf(fid,"ty=[0:(length(y)-1)]/r-m;\n"); fprintf(fid,"figure;\n"); fprintf(fid,"subplot(2,1,1);\n"); fprintf(fid," plot(tx,real(x),'-s','Color',[0.5 0.5 0.5],'MarkerSize',1,...\n"); fprintf(fid," ty,real(y),'-s','Color',[0.5 0 0], 'MarkerSize',1);\n"); fprintf(fid," legend('original','resampled','location','northeast');"); fprintf(fid," xlabel('time');\n"); fprintf(fid," ylabel('real');\n"); fprintf(fid,"subplot(2,1,2);\n"); fprintf(fid," plot(tx,imag(x),'-s','Color',[0.5 0.5 0.5],'MarkerSize',1,...\n"); fprintf(fid," ty,imag(y),'-s','Color',[0 0.5 0], 'MarkerSize',1);\n"); fprintf(fid," legend('original','resampled','location','northeast');"); fprintf(fid," xlabel('time');\n"); fprintf(fid," ylabel('imag');\n"); fclose(fid); printf("results written to %s\n",OUTPUT_FILENAME); printf("done.\n"); return 0; }
int main(int argc, char*argv[]) { srand(time(NULL)); // options unsigned int k=2; // samples/symbol unsigned int m=3; // filter delay (symbols) float beta=0.9f; // filter excess bandwidth factor unsigned int order=2; unsigned int num_symbols=1024; float SNRdB = 30.0f; float bt=0.02f; // loop filter bandwidth float tau=0.2f; // fractional symbol offset float r = 1.00f; // resampled rate // use random data or 101010 phasing pattern int random_data=1; int dopt; while ((dopt = getopt(argc,argv,"uhk:m:b:o:s:w:n:t:r:")) != 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; case 'o': order = atoi(optarg); break; case 's': SNRdB = atof(optarg); break; case 'w': bt = atof(optarg); break; case 'n': num_symbols = atoi(optarg); break; case 't': tau = atof(optarg); break; case 'r': r = atof(optarg); break; default: exit(1); } } // validate input if (k < 2) { fprintf(stderr,"error: k (samples/symbol) must be at least 2\n"); return 1; } else if (m < 1) { fprintf(stderr,"error: m (filter delay) must be greater than 0\n"); return 1; } else if (beta <= 0.0f || beta > 1.0f) { fprintf(stderr,"error: beta (excess bandwidth factor) must be in (0,1]\n"); return 1; } else if (order == 0) { fprintf(stderr,"error: number of polyphase filters must be greater than 0\n"); return 1; } else if (bt <= 0.0f) { fprintf(stderr,"error: timing PLL bandwidth must be greater than 0\n"); return 1; } else if (num_symbols == 0) { fprintf(stderr,"error: number of symbols must be greater than 0\n"); return 1; } else if (tau < -1.0f || tau > 1.0f) { fprintf(stderr,"error: timing phase offset must be in [-1,1]\n"); return 1; } else if (r < 0.5f || r > 2.0f) { fprintf(stderr,"error: timing frequency offset must be in [0.5,2]\n"); return 1; } // compute delay while (tau < 0) tau += 1.0f; // ensure positive tau float g = k*tau; // number of samples offset int ds=floorf(g); // additional symbol delay float dt = (g - (float)ds); // fractional sample offset unsigned int i, n=0; unsigned int num_samples = k*num_symbols; unsigned int num_samples_resamp = (unsigned int) ceilf(num_samples*r*1.1f) + 4; float complex s[num_symbols]; // data symbols float complex x[num_samples]; // interpolated samples float complex y[num_samples_resamp]; // resampled data (resamp_crcf) float complex z[num_symbols + 64]; // synchronized symbols for (i=0; i<num_symbols; i++) { if (random_data) { // random signal (QPSK) s[i] = cexpf(_Complex_I*0.5f*M_PI*((rand() % 4) + 0.5f)); } else { s[i] = (i%2) ? 1.0f : -1.0f; // 101010 phasing pattern } } // // create and run interpolator // // design interpolating filter unsigned int h_len = 2*k*m + 1; float h[h_len]; liquid_firdes_rcos(k,m,beta,dt,h); interp_crcf q = interp_crcf_create(k,h,h_len); for (i=0; i<num_symbols; i++) { interp_crcf_execute(q, s[i], &x[n]); n+=k; } assert(n == num_samples); interp_crcf_destroy(q); // // run resampler // unsigned int resamp_len = 10*k; // resampling filter semi-length (filter delay) float resamp_bw = 0.45f; // resampling filter bandwidth float resamp_As = 60.0f; // resampling filter stop-band attenuation unsigned int resamp_npfb = 64; // number of filters in bank resamp_crcf f = resamp_crcf_create(r, resamp_len, resamp_bw, resamp_As, resamp_npfb); unsigned int num_samples_resampled = 0; unsigned int num_written; for (i=0; i<num_samples; i++) { #if 0 // bypass arbitrary resampler y[i] = x[i]; num_samples_resampled = num_samples; #else // TODO : compensate for resampler filter delay resamp_crcf_execute(f, x[i], &y[num_samples_resampled], &num_written); num_samples_resampled += num_written; #endif } resamp_crcf_destroy(f); // // add noise // float nstd = powf(10.0f, -SNRdB/20.0f) / sqrtf(2.0f); for (i=0; i<num_samples_resampled; i++) y[i] += nstd*(randnf() + _Complex_I*randnf()); // // create and run symbol synchronizer // // create symbol synchronizer symsynclp_crcf d = symsynclp_crcf_create(k, order); symsynclp_crcf_set_lf_bw(d,bt); unsigned int num_symbols_sync=0; unsigned int nn; float tau_hat[num_samples]; for (i=ds; i<num_samples_resampled; i++) { tau_hat[num_symbols_sync] = symsynclp_crcf_get_tau(d); symsynclp_crcf_execute(d, &y[i], 1, &z[num_symbols_sync], &nn); num_symbols_sync += nn; } symsynclp_crcf_destroy(d); // print last several symbols to screen printf("z(t) :\n"); for (i=num_symbols_sync-10; i<num_symbols_sync; i++) printf(" z(%2u) = %8.4f + j*%8.4f;\n", i+1, crealf(z[i]), cimagf(z[i])); // // export output file // FILE* fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s, auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"close all;\nclear all;\n\n"); fprintf(fid,"k=%u;\n",k); fprintf(fid,"m=%u;\n",m); fprintf(fid,"beta=%12.8f;\n",beta); fprintf(fid,"order=%u;\n",order); fprintf(fid,"num_symbols=%u;\n",num_symbols); for (i=0; i<h_len; i++) fprintf(fid,"h(%3u) = %12.5f;\n", i+1, h[i]); for (i=0; i<num_symbols; i++) fprintf(fid,"s(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(s[i]), cimagf(s[i])); for (i=0; i<num_samples; i++) fprintf(fid,"x(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(x[i]), cimagf(x[i])); for (i=0; i<num_samples_resampled; i++) fprintf(fid,"y(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(y[i]), cimagf(y[i])); for (i=0; i<num_symbols_sync; i++) fprintf(fid,"z(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(z[i]), cimagf(z[i])); for (i=0; i<num_symbols_sync; i++) fprintf(fid,"tau_hat(%3u) = %12.8f;\n", i+1, tau_hat[i]); fprintf(fid,"\n\n"); fprintf(fid,"ms = 8; %% marker size\n"); fprintf(fid,"zp = filter(h,1,y);\n"); fprintf(fid,"figure;\nhold on;\n"); fprintf(fid,"plot([0:length(s)-1], real(s), 'ob', 'MarkerSize',ms);\n"); fprintf(fid,"plot([0:length(y)-1]/k -m, real(y), '-', 'MarkerSize',ms, 'Color',[0.8 0.8 0.8]);\n"); fprintf(fid,"plot([0:length(zp)-1]/k -k*m, real(zp/k), '-b', 'MarkerSize',ms);\n"); fprintf(fid,"plot([0:length(z)-1] -k*m+1,real(z), 'xr', 'MarkerSize',ms);\n"); fprintf(fid,"hold off;\n"); fprintf(fid,"xlabel('Symbol Index');\n"); fprintf(fid,"ylabel('Output Signal');\n"); fprintf(fid,"grid on;\n"); fprintf(fid,"legend('sym in','interp','mf','sym out',0);\n"); fprintf(fid,"t0=1:floor(0.25*length(z));\n"); fprintf(fid,"t1=ceil(0.25*length(z)):length(z);\n"); fprintf(fid,"figure;\n"); fprintf(fid,"hold on;\n"); fprintf(fid,"plot(real(z(t0)),imag(z(t0)),'x','MarkerSize',ms,'Color',[0.6 0.6 0.6]);\n"); fprintf(fid,"plot(real(z(t1)),imag(z(t1)),'x','MarkerSize',ms,'Color',[0 0.25 0.5]);\n"); fprintf(fid,"hold off;\n"); fprintf(fid,"axis square; grid on;\n"); fprintf(fid,"axis([-1 1 -1 1]*1.2);\n"); fprintf(fid,"xlabel('In-phase');\n"); fprintf(fid,"ylabel('Quadrature');\n"); fprintf(fid,"legend(['first 25%%'],['last 75%%'],1);\n"); fprintf(fid,"figure;\n"); fprintf(fid,"tt = 0:(length(tau_hat)-1);\n"); fprintf(fid,"plot(tt,tau_hat,'-k','Color',[0 0 0]);\n"); fprintf(fid,"xlabel('time');\n"); fprintf(fid,"ylabel('tau-hat');\n"); fprintf(fid,"grid on;\n"); fprintf(fid,"axis([0 length(tau_hat) 0 1]);\n"); fclose(fid); printf("results written to %s.\n", OUTPUT_FILENAME); // clean it up printf("done.\n"); return 0; }
int main() { // options unsigned int h_len = 7; // filter semi-length (filter delay) float r=1/sqrtf(2); // resampling rate (output/input) float bw=0.25f; // resampling filter bandwidth float As=60.0f; // resampling filter stop-band attenuation [dB] unsigned int npfb=32; // number of filters in bank (timing resolution) unsigned int n=180; // number of input samples // number of input samples (adjusted for filter delay) unsigned int nx = n + h_len; // generate input sequence : windowed sum of complex sinusoids unsigned int i; float complex x[nx]; for (i=0; i<nx; i++) { float complex jphi = _Complex_I*2.0f*M_PI*i; x[i] = cexpf(jphi*0.02f) + 1.4f*cexpf(jphi*0.07f); // window edge size unsigned int t = (unsigned int)(0.1*n); if (i < n) { // edge-rounded window if (i < t) x[i] *= blackmanharris(i,2*t); else if (i >= n-t) x[i] *= blackmanharris(n-i-1,2*t); } else { x[i] = 0.; } } // output buffer with extra padding for good measure unsigned int y_len = (unsigned int) ceilf(1.1*r*nx) + 16; float complex y[y_len]; // create resampler resamp_crcf f = resamp_crcf_create(r,h_len,bw,As,npfb); unsigned int num_written; unsigned int ny=0; for (i=0; i<nx; i++) { // execute resampler, storing in output buffer resamp_crcf_execute(f, x[i], &y[ny], &num_written); ny += num_written; } printf(" %u / %u\n", ny, nx); // clean up allocated objects resamp_crcf_destroy(f); // open/initialize output file FILE*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 [-3:3]\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 pointsize 0.6\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 7 linetype 1 linewidth 1 linecolor rgb '#999999' title 'original',\\\n"); fprintf(fid," '-' using 1:2 with points pointtype 7 linecolor rgb '#008000' title 'resampled'\n"); // export output for (i=0; i<nx; i++) { //fprintf(fid,"%6u %12.4e %12.4e\n", i, cos(2*M_PI*0.04*i), sin(2*M_PI*0.04*i)); fprintf(fid,"%6u %12.4e %12.4e\n", i, crealf(x[i]), cimagf(x[i])); } fprintf(fid,"e\n"); float t; for (i=0; i<ny; i++) { t = (float)(i) / r - (float)(h_len); fprintf(fid,"%12.4e %12.4e %12.4e\n", t, 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 7 linetype 1 linewidth 1 linecolor rgb '#999999' title 'original',\\\n"); fprintf(fid," '-' using 1:3 with points pointtype 7 linecolor rgb '#800000' title 'resampled'\n"); // export output for (i=0; i<nx; i++) { //fprintf(fid,"%6u %12.4e %12.4e\n", i, cos(2*M_PI*0.04*i), sin(2*M_PI*0.04*i)); fprintf(fid,"%6u %12.4e %12.4e\n", i, crealf(x[i]), cimagf(x[i])); } fprintf(fid,"e\n"); for (i=0; i<ny; i++) { t = (float)(i) / r - (float)(h_len); fprintf(fid,"%12.4e %12.4e %12.4e\n", t, crealf(y[i]), cimagf(y[i])); } fprintf(fid,"e\n"); fprintf(fid,"unset multiplot\n"); // close output file fclose(fid); 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_HANN,0); liquid_doc_compute_psdcf(y,ny,Y,nfft,LIQUID_DOC_PSDWINDOW_HANN,0); fft_shift(X,nfft); fft_shift(Y,nfft); float scaling_factor = 20*log10f(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 Input 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; fprintf(fid,"%12.8f %12.4e\n", fx, 20*log10f(cabsf(X[i])) - scaling_factor); } fprintf(fid,"e\n"); for (i=0; i<nfft; i++) { float fy = ((float)(i) / (float)nfft - 0.5f)*r; fprintf(fid,"%12.8f %12.4e\n", fy, 20*log10f(cabsf(Y[i])) - scaling_factor - 20*log10(r)); } fprintf(fid,"e\n"); fclose(fid); printf("done.\n"); return 0; }
int main(int argc, char*argv[]) { srand(time(NULL)); // options unsigned int k=2; // samples/symbol (input) unsigned int k_out=2; // samples/symbol (output) unsigned int m=4; // filter delay (symbols) float beta=0.3f; // filter excess bandwidth factor unsigned int num_filters=64; // number of filters in the bank unsigned int num_symbols=500; // number of data symbols float SNRdB = 30.0f; // signal-to-noise ratio liquid_rnyquist_type ftype_tx = LIQUID_RNYQUIST_RRC; liquid_rnyquist_type ftype_rx = LIQUID_RNYQUIST_RRC; float bt=0.01f; // loop filter bandwidth float tau=-0.4f; // fractional symbol offset float r = 1.00f; // resampled rate char filename_base[256] = "figures.gen/filter_symsync_crcf"; int dopt; while ((dopt = getopt(argc,argv,"hf:k:K:m:b:B:s:w:n:t:r:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'f': strncpy(filename_base,optarg,256); break; case 'k': k = atoi(optarg); break; case 'K': k_out = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'b': beta = atof(optarg); break; case 'B': num_filters = atoi(optarg); break; case 's': SNRdB = atof(optarg); break; case 'w': bt = atof(optarg); break; case 'n': num_symbols = atoi(optarg); break; case 't': tau = atof(optarg); break; case 'r': r = atof(optarg); break; default: exit(1); } } // validate input if (k < 2) { fprintf(stderr,"error: k (samples/symbol) must be at least 2\n"); exit(1); } else if (m < 1) { fprintf(stderr,"error: m (filter delay) must be greater than 0\n"); exit(1); } else if (beta <= 0.0f || beta > 1.0f) { fprintf(stderr,"error: beta (excess bandwidth factor) must be in (0,1]\n"); exit(1); } else if (num_filters == 0) { fprintf(stderr,"error: number of polyphase filters must be greater than 0\n"); exit(1); } else if (bt <= 0.0f) { fprintf(stderr,"error: timing PLL bandwidth must be greater than 0\n"); exit(1); } else if (num_symbols == 0) { fprintf(stderr,"error: number of symbols must be greater than 0\n"); exit(1); } else if (tau < -1.0f || tau > 1.0f) { fprintf(stderr,"error: timing phase offset must be in [-1,1]\n"); exit(1); } else if (r < 0.5f || r > 2.0f) { fprintf(stderr,"error: timing frequency offset must be in [0.5,2]\n"); exit(1); } // compute delay while (tau < 0) tau += 1.0f; // ensure positive tau float g = k*tau; // number of samples offset int ds=floorf(g); // additional symbol delay float dt = (g - (float)ds); // fractional sample offset if (dt > 0.5f) { // force dt to be in [0.5,0.5] dt -= 1.0f; ds++; } unsigned int i, n=0; // derived values unsigned int num_samples = k*num_symbols; unsigned int num_samples_resamp = (unsigned int) ceilf(num_samples*r*1.1f) + 4; // arrays float complex s[num_symbols]; // data symbols float complex x[num_samples]; // interpolated samples float complex y[num_samples_resamp]; // resampled data (resamp_crcf) float complex z[k_out*num_symbols + 64];// synchronized samples float complex sym_out[num_symbols + 64];// synchronized symbols // random signal (QPSK) for (i=0; i<num_symbols; i++) { s[i] = ( rand() % 2 ? M_SQRT1_2 : -M_SQRT1_2 ) + ( rand() % 2 ? M_SQRT1_2 : -M_SQRT1_2 ) * _Complex_I; } // // create and run interpolator // // design interpolating filter unsigned int h_len = 2*k*m+1; float h[h_len]; liquid_firdes_rnyquist(ftype_tx,k,m,beta,dt,h); interp_crcf q = interp_crcf_create(k,h,h_len); for (i=0; i<num_symbols; i++) { interp_crcf_execute(q, s[i], &x[n]); n+=k; } assert(n == num_samples); interp_crcf_destroy(q); // // run resampler // unsigned int resamp_len = 10*k; // resampling filter semi-length (filter delay) float resamp_bw = 0.45f; // resampling filter bandwidth float resamp_As = 60.0f; // resampling filter stop-band attenuation unsigned int resamp_npfb = 64; // number of filters in bank resamp_crcf f = resamp_crcf_create(r, resamp_len, resamp_bw, resamp_As, resamp_npfb); unsigned int num_samples_resampled = 0; unsigned int num_written; for (i=0; i<num_samples; i++) { #if 0 // bypass arbitrary resampler y[i] = x[i]; num_samples_resampled = num_samples; #else // TODO : compensate for resampler filter delay resamp_crcf_execute(f, x[i], &y[num_samples_resampled], &num_written); num_samples_resampled += num_written; #endif } resamp_crcf_destroy(f); // // add noise // float nstd = powf(10.0f, -SNRdB/20.0f); for (i=0; i<num_samples_resampled; i++) y[i] += nstd*(randnf() + _Complex_I*randnf()); // // create and run symbol synchronizer // symsync_crcf d = symsync_crcf_create_rnyquist(ftype_rx, k, m, beta, num_filters); symsync_crcf_set_lf_bw(d,bt); symsync_crcf_set_output_rate(d,k_out); unsigned int num_samples_sync=0; unsigned int nn; unsigned int num_symbols_sync = 0; float tau_hat[num_samples]; for (i=ds; i<num_samples_resampled; i++) { tau_hat[num_samples_sync] = symsync_crcf_get_tau(d); symsync_crcf_execute(d, &y[i], 1, &z[num_samples_sync], &nn); // decimate unsigned int j; for (j=0; j<nn; j++) { if ( (num_samples_sync%k_out)==0 ) sym_out[num_symbols_sync++] = z[num_samples_sync]; num_samples_sync++; } } symsync_crcf_destroy(d); // print last several symbols to screen printf("output symbols:\n"); for (i=num_symbols_sync-10; i<num_symbols_sync; i++) printf(" sym_out(%2u) = %8.4f + j*%8.4f;\n", i+1, crealf(sym_out[i]), cimagf(sym_out[i])); // // export output // FILE * fid = NULL; char filename[300]; // // const: constellation // strncpy(filename, filename_base, 256); strcat(filename, "_const.gnu"); fid = fopen(filename,"w"); if (!fid) { fprintf(stderr,"error: %s, could not open file '%s' for writing\n", argv[0], filename); return 1; } fprintf(fid,"# %s: auto-generated file\n\n", filename); fprintf(fid,"reset\n"); fprintf(fid,"set terminal postscript eps enhanced color solid rounded\n"); fprintf(fid,"set size ratio 1\n"); fprintf(fid,"set xrange [-1.5:1.5];\n"); fprintf(fid,"set yrange [-1.5:1.5];\n"); fprintf(fid,"set xlabel 'In-phase'\n"); fprintf(fid,"set ylabel 'Quadrature phase'\n"); fprintf(fid,"set grid xtics ytics\n"); fprintf(fid,"set grid linetype 1 linecolor rgb '%s' linewidth 1\n",LIQUID_DOC_COLOR_GRID); fprintf(fid,"plot '-' using 1:2 with points pointtype 7 pointsize 0.5 linecolor rgb '%s' title 'first %u symbols',\\\n", LIQUID_DOC_COLOR_GRAY, num_symbols/2); fprintf(fid," '-' using 1:2 with points pointtype 7 pointsize 0.7 linecolor rgb '%s' title 'last %u symbols'\n", LIQUID_DOC_COLOR_RED, num_symbols/2); // first half of symbols for (i=2*m; i<num_symbols_sync/2; i++) fprintf(fid," %12.4e %12.4e\n", crealf(sym_out[i]), cimagf(sym_out[i])); fprintf(fid,"e\n"); // second half of symbols for ( ; i<num_symbols_sync; i++) fprintf(fid," %12.4e %12.4e\n", crealf(sym_out[i]), cimagf(sym_out[i])); fprintf(fid,"e\n"); fclose(fid); printf("results written to '%s'\n", filename); // // time series // strncpy(filename, filename_base, 256); strcat(filename, "_time.gnu"); fid = fopen(filename,"w"); if (!fid) { fprintf(stderr,"error: %s, could not open file '%s' for writing\n", argv[0], filename); return 1; } fprintf(fid,"# %s: auto-generated file\n\n", filename); fprintf(fid,"reset\n"); fprintf(fid,"set terminal postscript eps enhanced color solid rounded\n"); fprintf(fid,"set xrange [0:%u];\n",num_symbols); fprintf(fid,"set yrange [-1.5:1.5]\n"); fprintf(fid,"set size ratio 0.3\n"); fprintf(fid,"set xlabel 'Symbol 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 pointsize 0.6\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"); // real fprintf(fid,"# real\n"); fprintf(fid,"set ylabel 'Real'\n"); fprintf(fid,"plot '-' using 1:2 with lines linetype 1 linewidth 1 linecolor rgb '#999999' notitle,\\\n"); fprintf(fid," '-' using 1:2 with points pointtype 7 linecolor rgb '%s' notitle'\n", LIQUID_DOC_COLOR_BLUE); // for (i=0; i<num_samples_sync; i++) fprintf(fid,"%12.8f %12.4e\n", (float)i/(float)k_out, crealf(z[i])); fprintf(fid,"e\n"); // for (i=0; i<num_samples_sync; i+=k) fprintf(fid,"%12.8f %12.4e\n", (float)i/(float)k_out, crealf(z[i])); fprintf(fid,"e\n"); // imag fprintf(fid,"# imag\n"); fprintf(fid,"set ylabel 'Imag'\n"); fprintf(fid,"plot '-' using 1:2 with lines linetype 1 linewidth 1 linecolor rgb '#999999' notitle,\\\n"); fprintf(fid," '-' using 1:2 with points pointtype 7 linecolor rgb '%s' notitle'\n", LIQUID_DOC_COLOR_GREEN); // for (i=0; i<num_samples_sync; i++) fprintf(fid,"%12.8f %12.4e\n", (float)i/(float)k_out, cimagf(z[i])); fprintf(fid,"e\n"); // for (i=0; i<num_samples_sync; i+=k) fprintf(fid,"%12.8f %12.4e\n", (float)i/(float)k_out, cimagf(z[i])); fprintf(fid,"e\n"); fprintf(fid,"unset multiplot\n"); // close output file fclose(fid); printf("results written to '%s'\n", filename); // clean it up return 0; }