// create square-root Nyquist decimator // _type : filter type (e.g. LIQUID_RNYQUIST_RRC) // _M : samples/symbol _M > 1 // _m : filter delay (symbols), _m > 0 // _beta : excess bandwidth factor, 0 < _beta < 1 // _dt : fractional sample delay, 0 <= _dt < 1 FIRDECIM() FIRDECIM(_create_rnyquist)(int _type, unsigned int _M, unsigned int _m, float _beta, float _dt) { // validate input if (_M < 2) { fprintf(stderr,"error: decim_%s_create_rnyquist(), decimation factor must be greater than 1\n", EXTENSION_FULL); exit(1); } else if (_m == 0) { fprintf(stderr,"error: decim_%s_create_rnyquist(), filter delay must be greater than 0\n", EXTENSION_FULL); exit(1); } else if (_beta < 0.0f || _beta > 1.0f) { fprintf(stderr,"error: decim_%s_create_rnyquist(), filter excess bandwidth factor must be in [0,1]\n", EXTENSION_FULL); exit(1); } else if (_dt < -1.0f || _dt > 1.0f) { fprintf(stderr,"error: decim_%s_create_rnyquist(), filter fractional sample delay must be in [-1,1]\n", EXTENSION_FULL); exit(1); } // generate square-root Nyquist filter unsigned int h_len = 2*_M*_m + 1; float h[h_len]; liquid_firdes_rnyquist(_type,_M,_m,_beta,_dt,h); // copy coefficients to type-specific array (e.g. float complex) unsigned int i; TC hc[h_len]; for (i=0; i<h_len; i++) hc[i] = h[i]; // return decimator object return FIRDECIM(_create)(_M, hc, h_len); }
// create square-root Nyquist symbol synchronizer // _type : filter type (e.g. LIQUID_RNYQUIST_RRC) // _k : samples/symbol // _m : symbol delay // _beta : rolloff factor (0 < beta <= 1) // _M : number of filters in the bank SYMSYNC() SYMSYNC(_create_rnyquist)(int _type, unsigned int _k, unsigned int _m, float _beta, unsigned int _M) { // validate input if (_k < 2) { fprintf(stderr,"error: symsync_%s_create_rnyquist(), samples/symbol must be at least 2\n", EXTENSION_FULL); exit(1); } else if (_m == 0) { fprintf(stderr,"error: symsync_%s_create_rnyquist(), 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_rnyquist(), 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 square-root Nyquist pulse-shaping filter liquid_firdes_rnyquist(_type, _k*_M, _m, _beta, 0, Hf); // copy coefficients to type-specific array TC H[H_len]; unsigned int i; for (i=0; i<H_len; i++) H[i] = Hf[i]; // create object and return return SYMSYNC(_create)(_k, _M, H, H_len); }
// create square-root Nyquist filterbank // _type : filter type (e.g. LIQUID_RNYQUIST_RRC) // _M : number of filters in the bank // _k : samples/symbol _k > 1 // _m : filter delay (symbols), _m > 0 // _beta : excess bandwidth factor, 0 < _beta < 1 FIRPFB() FIRPFB(_create_rnyquist)(int _type, unsigned int _M, unsigned int _k, unsigned int _m, float _beta) { // validate input if (_M == 0) { fprintf(stderr,"error: firpfb_%s_create_rnyquist(), number of filters must be greater than zero\n", EXTENSION_FULL); exit(1); } else if (_k < 2) { fprintf(stderr,"error: firpfb_%s_create_rnyquist(), filter samples/symbol must be greater than 1\n", EXTENSION_FULL); exit(1); } else if (_m == 0) { fprintf(stderr,"error: firpfb_%s_create_rnyquist(), filter delay must be greater than 0\n", EXTENSION_FULL); exit(1); } else if (_beta < 0.0f || _beta > 1.0f) { fprintf(stderr,"error: firpfb_%s_create_rnyquist(), filter excess bandwidth factor must be in [0,1]\n", EXTENSION_FULL); exit(1); } // generate square-root Nyquist filter unsigned int H_len = 2*_M*_k*_m + 1; float Hf[H_len]; liquid_firdes_rnyquist(_type,_M*_k,_m,_beta,0,Hf); // copy coefficients to type-specific array (e.g. float complex) unsigned int i; TC Hc[H_len]; for (i=0; i<H_len; i++) Hc[i] = Hf[i]; // return filterbank object return FIRPFB(_create)(_M, Hc, H_len); }
// create from square-root Nyquist prototype // _type : filter type (e.g. LIQUID_RNYQUIST_RRC) // _k : nominal samples/symbol, _k > 1 // _m : filter delay [symbols], _m > 0 // _beta : rolloff factor, 0 < beta <= 1 // _mu : fractional sample offset,-0.5 < _mu < 0.5 FIRFILT() FIRFILT(_create_rnyquist)(int _type, unsigned int _k, unsigned int _m, float _beta, float _mu) { // validate input if (_k < 2) { fprintf(stderr,"error: firfilt_%s_create_rnyquist(), filter samples/symbol must be greater than 1\n", EXTENSION_FULL); exit(1); } else if (_m == 0) { fprintf(stderr,"error: firfilt_%s_create_rnyquist(), filter delay must be greater than 0\n", EXTENSION_FULL); exit(1); } else if (_beta < 0.0f || _beta > 1.0f) { fprintf(stderr,"error: firfilt_%s_create_rnyquist(), filter excess bandwidth factor must be in [0,1]\n", EXTENSION_FULL); exit(1); } // generate square-root Nyquist filter unsigned int h_len = 2*_k*_m + 1; float hf[h_len]; liquid_firdes_rnyquist(_type,_k,_m,_beta,_mu,hf); // copy coefficients to type-specific array (e.g. float complex) unsigned int i; TC hc[h_len]; for (i=0; i<h_len; i++) hc[i] = hf[i]; // return filterbank object return FIRFILT(_create)(hc, h_len); }
// create firpfb derivative square-root Nyquist filterbank // _type : filter type (e.g. LIQUID_RNYQUIST_RRC) // _M : number of filters in the bank // _k : samples/symbol _k > 1 // _m : filter delay (symbols), _m > 0 // _beta : excess bandwidth factor, 0 < _beta < 1 FIRPFB() FIRPFB(_create_drnyquist)(int _type, unsigned int _M, unsigned int _k, unsigned int _m, float _beta) { // validate input if (_M == 0) { fprintf(stderr,"error: firpfb_%s_create_drnyquist(), number of filters must be greater than zero\n", EXTENSION_FULL); exit(1); } else if (_k < 2) { fprintf(stderr,"error: firpfb_%s_create_drnyquist(), filter samples/symbol must be greater than 1\n", EXTENSION_FULL); exit(1); } else if (_m == 0) { fprintf(stderr,"error: firpfb_%s_create_drnyquist(), filter delay must be greater than 0\n", EXTENSION_FULL); exit(1); } else if (_beta < 0.0f || _beta > 1.0f) { fprintf(stderr,"error: firpfb_%s_create_drnyquist(), filter excess bandwidth factor must be in [0,1]\n", EXTENSION_FULL); exit(1); } // generate square-root Nyquist filter unsigned int H_len = 2*_M*_k*_m + 1; float Hf[H_len]; liquid_firdes_rnyquist(_type,_M*_k,_m,_beta,0,Hf); // compute derivative filter float dHf[H_len]; float HdH_max = 0.0f; unsigned int i; for (i=0; i<H_len; i++) { if (i==0) { dHf[i] = Hf[i+1] - Hf[H_len-1]; } else if (i==H_len-1) { dHf[i] = Hf[0] - Hf[i-1]; } else { dHf[i] = Hf[i+1] - Hf[i-1]; } // find maximum of h*dh if ( fabsf(Hf[i]*dHf[i]) > HdH_max ) HdH_max = fabsf(Hf[i]*dHf[i]); } // copy coefficients to type-specific array (e.g. float complex) // and apply scaling factor for normalized response TC Hc[H_len]; for (i=0; i<H_len; i++) Hc[i] = dHf[i] * 0.06f / HdH_max; // return filterbank object return FIRPFB(_create)(_M, Hc, H_len); }
// create square-root Nyquist interpolator // _type : filter type (e.g. LIQUID_RNYQUIST_RRC) // _k : samples/symbol _k > 1 // _m : filter delay (symbols), _m > 0 // _beta : excess bandwidth factor, 0 < _beta < 1 // _dt : fractional sample delay, 0 <= _dt < 1 EQLMS() EQLMS(_create_rnyquist)(int _type, unsigned int _k, unsigned int _m, float _beta, float _dt) { // validate input if (_k < 2) { fprintf(stderr,"error: eqlms_%s_create_rnyquist(), samples/symbol must be greater than 1\n", EXTENSION_FULL); exit(1); } else if (_m == 0) { fprintf(stderr,"error: eqlms_%s_create_rnyquist(), filter delay must be greater than 0\n", EXTENSION_FULL); exit(1); } else if (_beta < 0.0f || _beta > 1.0f) { fprintf(stderr,"error: eqlms_%s_create_rnyquist(), filter excess bandwidth factor must be in [0,1]\n", EXTENSION_FULL); exit(1); } else if (_dt < -1.0f || _dt > 1.0f) { fprintf(stderr,"error: eqlms_%s_create_rnyquist(), filter fractional sample delay must be in [-1,1]\n", EXTENSION_FULL); exit(1); } // generate square-root Nyquist filter unsigned int h_len = 2*_k*_m + 1; float h[h_len]; liquid_firdes_rnyquist(_type,_k,_m,_beta,_dt,h); // copy coefficients to type-specific array (e.g. float complex) // and scale by samples/symbol unsigned int i; T hc[h_len]; for (i=0; i<h_len; i++) hc[i] = h[i] / (float)_k; // return equalizer object return EQLMS(_create)(hc, h_len); }
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 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; }
int main(int argc, char*argv[]) { srand(time(NULL)); // options unsigned int num_symbols=500; // number of symbols to observe float SNRdB = 30.0f; // signal-to-noise ratio [dB] unsigned int hc_len=5; // channel filter length unsigned int k=2; // matched filter samples/symbol unsigned int m=3; // matched filter delay (symbols) float beta=0.3f; // matched filter excess bandwidth factor unsigned int p=3; // equalizer length (symbols, hp_len = 2*k*p+1) float mu = 0.08f; // learning rate // modulation type/depth modulation_scheme ms = LIQUID_MODEM_QPSK; int dopt; while ((dopt = getopt(argc,argv,"hn:s:c:k:m:b:p:u:M:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'n': num_symbols = atoi(optarg); break; case 's': SNRdB = atof(optarg); break; case 'c': hc_len = atoi(optarg); break; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'b': beta = atof(optarg); break; case 'p': p = atoi(optarg); break; case 'u': mu = atof(optarg); break; case 'M': ms = liquid_getopt_str2mod(optarg); if (ms == LIQUID_MODEM_UNKNOWN) { fprintf(stderr,"error: %s, unknown/unsupported modulation scheme '%s'\n", argv[0], optarg); return 1; } break; default: exit(1); } } // validate input if (num_symbols == 0) { fprintf(stderr,"error: %s, number of symbols must be greater than zero\n", argv[0]); exit(1); } else if (hc_len == 0) { fprintf(stderr,"error: %s, channel must have at least 1 tap\n", argv[0]); exit(1); } else if (k < 2) { fprintf(stderr,"error: %s, samples/symbol must be at least 2\n", argv[0]); exit(1); } else if (m == 0) { fprintf(stderr,"error: %s, filter semi-length must be at least 1 symbol\n", argv[0]); exit(1); } else if (beta < 0.0f || beta > 1.0f) { fprintf(stderr,"error: %s, filter excess bandwidth must be in [0,1]\n", argv[0]); exit(1); } else if (p == 0) { fprintf(stderr,"error: %s, equalizer semi-length must be at least 1 symbol\n", argv[0]); exit(1); } else if (mu < 0.0f || mu > 1.0f) { fprintf(stderr,"error: %s, equalizer learning rate must be in [0,1]\n", argv[0]); exit(1); } // derived values unsigned int hm_len = 2*k*m+1; // matched filter length unsigned int hp_len = 2*k*p+1; // equalizer filter length unsigned int num_samples = k*num_symbols; // bookkeeping variables float complex sym_tx[num_symbols]; // transmitted data sequence float complex x[num_samples]; // interpolated time series float complex y[num_samples]; // channel output float complex z[num_samples]; // equalized output float hm[hm_len]; // matched filter response float complex hc[hc_len]; // channel filter coefficients float complex hp[hp_len]; // equalizer filter coefficients unsigned int i; // generate matched filter response liquid_firdes_rnyquist(LIQUID_FIRFILT_RRC, k, m, beta, 0.0f, hm); firinterp_crcf interp = firinterp_crcf_create(k, hm, hm_len); // create the modem objects modem mod = modem_create(ms); modem demod = modem_create(ms); unsigned int M = 1 << modem_get_bps(mod); // generate channel impulse response, filter hc[0] = 1.0f; for (i=1; i<hc_len; i++) hc[i] = 0.09f*(randnf() + randnf()*_Complex_I); firfilt_cccf fchannel = firfilt_cccf_create(hc, hc_len); // generate random symbols for (i=0; i<num_symbols; i++) modem_modulate(mod, rand()%M, &sym_tx[i]); // interpolate for (i=0; i<num_symbols; i++) firinterp_crcf_execute(interp, sym_tx[i], &x[i*k]); // push through channel float nstd = powf(10.0f, -SNRdB/20.0f); for (i=0; i<num_samples; i++) { firfilt_cccf_push(fchannel, x[i]); firfilt_cccf_execute(fchannel, &y[i]); // add noise y[i] += nstd*(randnf() + randnf()*_Complex_I)*M_SQRT1_2; } // push through equalizer // create equalizer, intialized with square-root Nyquist filter eqlms_cccf eq = eqlms_cccf_create_rnyquist(LIQUID_FIRFILT_RRC, k, p, beta, 0.0f); eqlms_cccf_set_bw(eq, mu); // get initialized weights eqlms_cccf_get_weights(eq, hp); // filtered error vector magnitude (emperical RMS error) float evm_hat = 0.03f; float complex d_hat = 0.0f; for (i=0; i<num_samples; i++) { // print filtered evm (emperical rms error) if ( ((i+1)%50)==0 ) printf("%4u : rms error = %12.8f dB\n", i+1, 10*log10(evm_hat)); eqlms_cccf_push(eq, y[i]); eqlms_cccf_execute(eq, &d_hat); // store output z[i] = d_hat; // decimate by k if ( (i%k) != 0 ) continue; // estimate transmitted signal unsigned int sym_out; // output symbol float complex d_prime; // estimated input sample modem_demodulate(demod, d_hat, &sym_out); modem_get_demodulator_sample(demod, &d_prime); // update equalizer eqlms_cccf_step(eq, d_prime, d_hat); // update filtered evm estimate float evm = crealf( (d_prime-d_hat)*conjf(d_prime-d_hat) ); evm_hat = 0.98f*evm_hat + 0.02f*evm; } // get equalizer weights eqlms_cccf_get_weights(eq, hp); // destroy objects eqlms_cccf_destroy(eq); firinterp_crcf_destroy(interp); firfilt_cccf_destroy(fchannel); modem_destroy(mod); modem_destroy(demod); // // export output // 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,"num_symbols = %u;\n", num_symbols); fprintf(fid,"num_samples = num_symbols*k;\n"); // save transmit matched-filter response fprintf(fid,"hm_len = 2*k*m+1;\n"); fprintf(fid,"hm = zeros(1,hm_len);\n"); for (i=0; i<hm_len; i++) fprintf(fid,"hm(%4u) = %12.4e;\n", i+1, hm[i]); // save channel impulse response fprintf(fid,"hc_len = %u;\n", hc_len); fprintf(fid,"hc = zeros(1,hc_len);\n"); for (i=0; i<hc_len; i++) fprintf(fid,"hc(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(hc[i]), cimagf(hc[i])); // save equalizer response fprintf(fid,"hp_len = %u;\n", hp_len); fprintf(fid,"hp = zeros(1,hp_len);\n"); for (i=0; i<hp_len; i++) fprintf(fid,"hp(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(hp[i]), cimagf(hp[i])); // save sample sets fprintf(fid,"x = zeros(1,num_samples);\n"); fprintf(fid,"y = zeros(1,num_samples);\n"); fprintf(fid,"z = zeros(1,num_samples);\n"); for (i=0; i<num_samples; i++) { fprintf(fid,"x(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(x[i]), cimagf(x[i])); fprintf(fid,"y(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(y[i]), cimagf(y[i])); fprintf(fid,"z(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(z[i]), cimagf(z[i])); } // plot time response fprintf(fid,"t = 0:(num_samples-1);\n"); fprintf(fid,"tsym = 1:k:num_samples;\n"); fprintf(fid,"figure;\n"); fprintf(fid,"plot(t,real(z),...\n"); fprintf(fid," t(tsym),real(z(tsym)),'x');\n"); // plot constellation fprintf(fid,"tsym0 = tsym(1:(length(tsym)/2));\n"); fprintf(fid,"tsym1 = tsym((length(tsym)/2):end);\n"); fprintf(fid,"figure;\n"); fprintf(fid,"plot(real(z(tsym0)),imag(z(tsym0)),'x','Color',[1 1 1]*0.7,...\n"); fprintf(fid," real(z(tsym1)),imag(z(tsym1)),'x','Color',[1 1 1]*0.0);\n"); fprintf(fid,"xlabel('In-Phase');\n"); fprintf(fid,"ylabel('Quadrature');\n"); fprintf(fid,"axis([-1 1 -1 1]*1.5);\n"); fprintf(fid,"axis square;\n"); fprintf(fid,"grid on;\n"); // compute composite response fprintf(fid,"g = real(conv(conv(hm,hc),hp));\n"); // plot responses fprintf(fid,"nfft = 1024;\n"); fprintf(fid,"f = [0:(nfft-1)]/nfft - 0.5;\n"); fprintf(fid,"Hm = 20*log10(abs(fftshift(fft(hm/k,nfft))));\n"); fprintf(fid,"Hc = 20*log10(abs(fftshift(fft(hc, nfft))));\n"); fprintf(fid,"Hp = 20*log10(abs(fftshift(fft(hp, nfft))));\n"); fprintf(fid,"G = 20*log10(abs(fftshift(fft(g/k, nfft))));\n"); fprintf(fid,"figure;\n"); fprintf(fid,"plot(f,Hm, f,Hc, f,Hp, f,G,'-k','LineWidth',2, [-0.5/k 0.5/k],[-6.026 -6.026],'or');\n"); fprintf(fid,"xlabel('Normalized Frequency');\n"); fprintf(fid,"ylabel('Power Spectral Density');\n"); fprintf(fid,"legend('transmit','channel','equalizer','composite','half-power points',1);\n"); fprintf(fid,"axis([-0.5 0.5 -12 8]);\n"); fprintf(fid,"grid on;\n"); fclose(fid); printf("results written to '%s'\n", OUTPUT_FILENAME); return 0; }
int main(int argc, char*argv[]) { // options unsigned int num_symbols=500; // number of symbols to observe float SNRdB = 30.0f; // signal-to-noise ratio [dB] unsigned int hc_len=5; // channel filter length unsigned int k=2; // matched filter samples/symbol unsigned int m=3; // matched filter delay (symbols) float beta=0.3f; // matched filter excess bandwidth factor unsigned int p=3; // equalizer length (symbols, gr_len = 2*k*p+1) float mu = 0.09f; // LMS learning rate // modulation type/depth modulation_scheme ms = LIQUID_MODEM_QPSK; // plotting options unsigned int nfft = 512; // fft size float gnuplot_version = 4.2; char filename_base[256] = "figures.gen/eqlms_cccf_blind"; int dopt; while ((dopt = getopt(argc,argv,"hf:g:n:s:c:k:m:b:p:u:M:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'f': strncpy(filename_base,optarg,256); break; case 'g': gnuplot_version = atoi(optarg); break; case 'n': num_symbols = atoi(optarg); break; case 's': SNRdB = atof(optarg); break; case 'c': hc_len = atoi(optarg); break; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'b': beta = atof(optarg); break; case 'p': p = atoi(optarg); break; case 'u': mu = atof(optarg); break; case 'M': ms = liquid_getopt_str2mod(optarg); if (ms == LIQUID_MODEM_UNKNOWN) { fprintf(stderr,"error: %s, unknown/unsupported modulation scheme '%s'\n", argv[0], optarg); return 1; } break; default: exit(1); } } // validate input if (num_symbols == 0) { fprintf(stderr,"error: %s, number of symbols must be greater than zero\n", argv[0]); exit(1); } else if (hc_len == 0) { fprintf(stderr,"error: %s, channel must have at least 1 tap\n", argv[0]); exit(1); } else if (k < 2) { fprintf(stderr,"error: %s, samples/symbol must be at least 2\n", argv[0]); exit(1); } else if (m == 0) { fprintf(stderr,"error: %s, filter semi-length must be at least 1 symbol\n", argv[0]); exit(1); } else if (beta < 0.0f || beta > 1.0f) { fprintf(stderr,"error: %s, filter excess bandwidth must be in [0,1]\n", argv[0]); exit(1); } else if (p == 0) { fprintf(stderr,"error: %s, equalizer semi-length must be at least 1 symbol\n", argv[0]); exit(1); } else if (mu < 0.0f || mu > 1.0f) { fprintf(stderr,"error: %s, equalizer learning rate must be in [0,1]\n", argv[0]); exit(1); } // set 'random' seed on options srand( hc_len + p + nfft ); // derived values unsigned int gt_len = 2*k*m+1; // matched filter length unsigned int gr_len = 2*k*p+1; // equalizer filter length unsigned int num_samples = k*num_symbols; // bookkeeping variables float complex sym_tx[num_symbols]; // transmitted data sequence float complex x[num_samples]; // interpolated time series float complex y[num_samples]; // channel output float complex z[num_samples]; // equalized output // least mean-squares (LMS) equalizer float mse[num_symbols]; // equalizer mean-squared error float complex gr[gr_len]; // equalizer filter coefficients unsigned int i; // generate matched filter response float gtf[gt_len]; // matched filter response liquid_firdes_rnyquist(LIQUID_RNYQUIST_RRC, k, m, beta, 0.0f, gtf); // convert to complex coefficients float complex gt[gt_len]; for (i=0; i<gt_len; i++) gt[i] = gtf[i]; //+ 0.1f*(randnf() + _Complex_I*randnf()); // create interpolator interp_cccf interp = interp_cccf_create(k, gt, gt_len); // create the modem objects modem mod = modem_create(ms); modem demod = modem_create(ms); unsigned int bps = modem_get_bps(mod); unsigned int M = 1 << bps; // generate channel impulse response, filter #if 0 float complex hc[hc_len]; // channel filter coefficients hc[0] = 1.0f; for (i=1; i<hc_len; i++) hc[i] = 0.09f*(randnf() + randnf()*_Complex_I); #else // use fixed channel hc_len = 8; float complex hc[hc_len]; // channel filter coefficients hc[0] = 1.00000000+ 0.00000000*_Complex_I; hc[1] = 0.08077553+ -0.00247592*_Complex_I; hc[2] = 0.03625883+ -0.09219734*_Complex_I; hc[3] = 0.05764082+ 0.03277601*_Complex_I; hc[4] = -0.04773349+ -0.18766306*_Complex_I; hc[5] = -0.00101735+ -0.00270737*_Complex_I; hc[6] = -0.05796884+ -0.12665297*_Complex_I; hc[7] = 0.03805391+ -0.07609370*_Complex_I; #endif firfilt_cccf fchannel = firfilt_cccf_create(hc, hc_len); firfilt_cccf_print(fchannel); // generate random symbols for (i=0; i<num_symbols; i++) modem_modulate(mod, rand()%M, &sym_tx[i]); // interpolate for (i=0; i<num_symbols; i++) interp_cccf_execute(interp, sym_tx[i], &x[i*k]); // push through channel float nstd = powf(10.0f, -SNRdB/20.0f); for (i=0; i<num_samples; i++) { firfilt_cccf_push(fchannel, x[i]); firfilt_cccf_execute(fchannel, &y[i]); // add noise y[i] += nstd*(randnf() + randnf()*_Complex_I)*M_SQRT1_2; } // push through equalizers float grf[gr_len]; liquid_firdes_rnyquist(LIQUID_RNYQUIST_RRC, k, p, beta, 0.0f, grf); for (i=0; i<gr_len; i++) { gr[i] = grf[i] / (float)k; } // create LMS equalizer eqlms_cccf eq = eqlms_cccf_create(gr, gr_len); eqlms_cccf_set_bw(eq, mu); // filtered error vector magnitude (emperical MSE) //float zeta=0.05f; // smoothing factor (small zeta -> smooth MSE) float complex d_hat = 0.0f; unsigned int num_symbols_rx=0; for (i=0; i<num_samples; i++) { // push samples into equalizers eqlms_cccf_push(eq, y[i]); // compute outputs eqlms_cccf_execute(eq, &d_hat); // store outputs z[i] = d_hat; // check to see if buffer is full if ( i < gr_len) continue; // decimate by k if ( (i%k) != 0 ) continue; // estimate transmitted signal unsigned int sym_out; // output symbol float complex d_prime; // estimated input sample // LMS modem_demodulate(demod, d_hat, &sym_out); modem_get_demodulator_sample(demod, &d_prime); // update equalizers eqlms_cccf_step(eq, d_prime, d_hat); #if 0 // update filtered evm estimate float evm = crealf( (d_prime-d_hat)*conjf(d_prime-d_hat) ); if (num_symbols_rx == 0) { mse[num_symbols_rx] = evm; } else { mse[num_symbols_rx] = mse[num_symbols_rx-1]*(1-zeta) + evm*zeta; } #else // compute ISI for entire system eqlms_cccf_get_weights(eq, gr); mse[num_symbols_rx] = eqlms_cccf_isi(k, gt, gt_len, hc, hc_len, gr, gr_len); #endif // print filtered evm (emperical rms error) if ( ((num_symbols_rx+1)%100) == 0 ) printf("%4u : mse = %12.8f dB\n", num_symbols_rx+1, 20*log10f(mse[num_symbols_rx])); // increment output symbol counter num_symbols_rx++; } // get equalizer weights eqlms_cccf_get_weights(eq, gr); // destroy objects eqlms_cccf_destroy(eq); interp_cccf_destroy(interp); firfilt_cccf_destroy(fchannel); modem_destroy(mod); modem_destroy(demod); // // 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 50%%',\\\n", LIQUID_DOC_COLOR_GRAY); fprintf(fid," '-' using 1:2 with points pointtype 7 pointsize 0.7 linecolor rgb '%s' title 'last 50%%'\n", LIQUID_DOC_COLOR_RED); // first half of symbols for (i=2*p; i<num_symbols/2; i+=k) fprintf(fid," %12.4e %12.4e\n", crealf(y[i]), cimagf(y[i])); fprintf(fid,"e\n"); // second half of symbols for ( ; i<num_symbols; i+=k) fprintf(fid," %12.4e %12.4e\n", crealf(z[i]), cimagf(z[i])); fprintf(fid,"e\n"); fclose(fid); printf("results written to '%s'\n", filename); // // mse : mean-squared error // strncpy(filename, filename_base, 256); strcat(filename, "_mse.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 0.3\n"); fprintf(fid,"set xrange [0:%u];\n", num_symbols); fprintf(fid,"set yrange [1e-3:1e-1];\n"); fprintf(fid,"set format y '10^{%%L}'\n"); fprintf(fid,"set log y\n"); fprintf(fid,"set xlabel 'symbol index'\n"); fprintf(fid,"set ylabel 'mean-squared error'\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 lines linewidth 4 linetype 1 linecolor rgb '%s' title 'LMS MSE'\n", LIQUID_DOC_COLOR_RED); // LMS for (i=0; i<num_symbols_rx; i++) fprintf(fid," %4u %16.8e\n", i, mse[i]); fprintf(fid,"e\n"); fclose(fid); printf("results written to '%s'\n", filename); // // psd : power spectral density // // scale transmit filter appropriately for (i=0; i<gt_len; i++) gt[i] /= (float)k; float complex Gt[nfft]; // transmit matched filter float complex Hc[nfft]; // channel response float complex Gr[nfft]; // equalizer response liquid_doc_compute_psdcf(gt, gt_len, Gt, nfft, LIQUID_DOC_PSDWINDOW_NONE, 0); liquid_doc_compute_psdcf(hc, hc_len, Hc, nfft, LIQUID_DOC_PSDWINDOW_NONE, 0); liquid_doc_compute_psdcf(gr, gr_len, Gr, nfft, LIQUID_DOC_PSDWINDOW_NONE, 0); fft_shift(Gt, nfft); fft_shift(Hc, nfft); fft_shift(Gr, nfft); float freq[nfft]; for (i=0; i<nfft; i++) freq[i] = (float)(i) / (float)nfft - 0.5f; strncpy(filename, filename_base, 256); strcat(filename, "_freq.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 0.6\n"); fprintf(fid,"set xrange [-0.5:0.5];\n"); fprintf(fid,"set yrange [-10:6]\n"); fprintf(fid,"set xlabel 'Normalized 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 grid linetype 1 linecolor rgb '%s' lw 1\n",LIQUID_DOC_COLOR_GRID); fprintf(fid,"plot '-' using 1:2 with lines linetype 1 linewidth 1.5 linecolor rgb '%s' title 'transmit',\\\n", LIQUID_DOC_COLOR_GRAY); fprintf(fid," '-' using 1:2 with lines linetype 1 linewidth 1.5 linecolor rgb '%s' title 'channel',\\\n", LIQUID_DOC_COLOR_RED); fprintf(fid," '-' using 1:2 with lines linetype 1 linewidth 1.5 linecolor rgb '%s' title 'equalizer',\\\n", LIQUID_DOC_COLOR_GREEN); fprintf(fid," '-' using 1:2 with lines linetype 1 linewidth 4.0 linecolor rgb '%s' title 'composite',\\\n", LIQUID_DOC_COLOR_BLUE); fprintf(fid," '-' using 1:2 with points pointtype 7 pointsize 0.6 linecolor rgb '%s' notitle\n", LIQUID_DOC_COLOR_BLUE); // received signal for (i=0; i<nfft; i++) fprintf(fid,"%12.8f %12.4e\n", freq[i], 20*log10f(cabsf(Gt[i])) ); fprintf(fid,"e\n"); // channel for (i=0; i<nfft; i++) fprintf(fid,"%12.8f %12.4e\n", freq[i], 20*log10f(cabsf(Hc[i])) ); fprintf(fid,"e\n"); // equalizer for (i=0; i<nfft; i++) fprintf(fid,"%12.8f %12.4e\n", freq[i], 20*log10f(cabsf(Gr[i])) ); fprintf(fid,"e\n"); // composite for (i=0; i<nfft; i++) fprintf(fid,"%12.8f %12.4e\n", freq[i], 20*log10f( cabsf(Gt[i])*cabsf(Hc[i])*cabsf(Gr[i])) ); fprintf(fid,"e\n"); // composite fprintf(fid,"%12.8f %12.4e\n", -0.5f/(float)k, 20*log10f(0.5f)); fprintf(fid,"%12.8f %12.4e\n", 0.5f/(float)k, 20*log10f(0.5f)); fprintf(fid,"e\n"); fclose(fid); printf("results written to '%s'\n", filename); // // time... // 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; i++) fprintf(fid,"%12.8f %12.4e\n", (float)i/(float)k, crealf(z[i])); fprintf(fid,"e\n"); // for (i=0; i<num_samples; i+=k) fprintf(fid,"%12.8f %12.4e\n", (float)i/(float)k, 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; i++) fprintf(fid,"%12.8f %12.4e\n", (float)i/(float)k, cimagf(z[i])); fprintf(fid,"e\n"); // for (i=0; i<num_samples; i+=k) fprintf(fid,"%12.8f %12.4e\n", (float)i/(float)k, cimagf(z[i])); fprintf(fid,"e\n"); fprintf(fid,"unset multiplot\n"); // close output file fclose(fid); printf("results written to '%s'\n", filename); return 0; }
int main(int argc, char*argv[]) { srand(time(NULL)); // options unsigned int k=2; // samples/symbol (input) unsigned int m=3; // filter delay (symbols) float beta=0.5f; // filter excess bandwidth factor unsigned int npfb=32; // number of filters in the bank unsigned int p=3; // equalizer length (symbols, hp_len = 2*k*p+1) float mu = 0.05f; // equalizer learning rate unsigned int num_symbols=500; // number of data symbols unsigned int hc_len=5; // channel filter length float SNRdB = 30.0f; // signal-to-noise ratio liquid_rnyquist_type ftype = LIQUID_RNYQUIST_ARKAISER; float bt=0.05f; // symbol synchronizer loop filter bandwidth float tau=-0.1f; // fractional symbol offset int dopt; while ((dopt = getopt(argc,argv,"uhk:m:b:n:B:w:p:W:s:c:t:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; // transmit filter properties 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; // symsync properties case 'B': npfb = atoi(optarg); break; case 'w': bt = atof(optarg); break; // equalizer properties case 'p': p = atoi(optarg); break; case 'W': mu = atof(optarg); break; // equalizer properties case 's': SNRdB = atof(optarg); break; case 'c': hc_len = atoi(optarg); break; case 't': tau = atof(optarg); break; default: exit(1); } } // validate input if (k < 2) { fprintf(stderr,"error: %s,k (samples/symbol) must be at least 2\n", argv[0]); exit(1); } else if (m < 1) { fprintf(stderr,"error: %s,m (filter delay) must be greater than 0\n", argv[0]); exit(1); } else if (beta <= 0.0f || beta > 1.0f) { fprintf(stderr,"error: %s,beta (excess bandwidth factor) must be in (0,1]\n", argv[0]); exit(1); } else if (num_symbols == 0) { fprintf(stderr,"error: %s,number of symbols must be greater than 0\n", argv[0]); exit(1); } else if (npfb == 0) { fprintf(stderr,"error: %s,number of polyphase filters must be greater than 0\n", argv[0]); exit(1); } else if (bt < 0.0f) { fprintf(stderr,"error: %s,timing PLL bandwidth cannot be negative\n", argv[0]); exit(1); } else if (p == 0) { fprintf(stderr,"error: %s, equalizer order must be at least 1\n", argv[0]); exit(1); } else if (mu < 0.0f || mu > 1.0f) { fprintf(stderr,"error: %s, equalizer learning rate must be in [0,1]\n", argv[0]); exit(1); } else if (hc_len < 1) { fprintf(stderr,"error: %s, channel response must have at least 1 tap\n", argv[0]); exit(1); } else if (tau < -1.0f || tau > 1.0f) { fprintf(stderr,"error: %s,timing phase offset must be in [-1,1]\n", argv[0]); exit(1); } // derived values unsigned int ht_len = 2*k*m+1; // transmit filter order unsigned int hp_len = 2*k*p+1; // equalizer order float nstd = powf(10.0f, -SNRdB/20.0f); float dt = tau; // fractional sample offset unsigned int ds = 0; // full sample delay unsigned int i; unsigned int num_samples = k*num_symbols; float complex s[num_symbols]; // data symbols float complex x[num_samples]; // interpolated samples float complex y[num_samples]; // channel output float complex z[k*num_symbols + 64]; // synchronized samples float complex sym_out[num_symbols + 64]; // synchronized symbols 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 float ht[ht_len]; liquid_firdes_rnyquist(ftype,k,m,beta,dt,ht); interp_crcf q = interp_crcf_create(k, ht, ht_len); for (i=0; i<num_symbols; i++) interp_crcf_execute(q, s[i], &x[i*k]); interp_crcf_destroy(q); // // channel // // generate channel impulse response, filter float complex hc[hc_len]; hc[0] = 1.0f; for (i=1; i<hc_len; i++) hc[i] = 0.07f*(randnf() + randnf()*_Complex_I); firfilt_cccf fchannel = firfilt_cccf_create(hc, hc_len); // push through channel for (i=0; i<num_samples; i++) { firfilt_cccf_push(fchannel, x[i]); firfilt_cccf_execute(fchannel, &y[i]); // add noise y[i] += nstd*(randnf() + randnf()*_Complex_I)*M_SQRT1_2; } firfilt_cccf_destroy(fchannel); // // symbol timing recovery // // create symbol synchronizer symsync_crcf d = symsync_crcf_create_rnyquist(ftype, k, m, beta, npfb); symsync_crcf_set_lf_bw(d,bt); symsync_crcf_set_output_rate(d,k); unsigned int num_samples_sync=0; unsigned int nw; for (i=ds; i<num_samples; i++) { // push through symbol synchronizer symsync_crcf_execute(d, &y[i], 1, &z[num_samples_sync], &nw); num_samples_sync += nw; } printf("num samples : %6u (%6u synchronized)\n", num_samples, num_samples_sync); symsync_crcf_destroy(d); // // equalizer/decimator // // create equalizer (zeros with impulse in center) float complex hp[hp_len]; for (i=0; i<hp_len; i++) hp[i] = (i==k*p) ? 1.0f : 0.0f; eqlms_cccf eq = eqlms_cccf_create(hp, hp_len); eqlms_cccf_set_bw(eq, mu); // push through equalizer and decimate unsigned int num_symbols_sync = 0; float complex d_hat = 0.0f; for (i=0; i<num_samples_sync; i++) { // push sample into equalizer eqlms_cccf_push(eq, z[i]); // decimate by k if ( (i%k) != 0) continue; // compute output eqlms_cccf_execute(eq, &d_hat); sym_out[num_symbols_sync++] = d_hat; // check if buffer is full if ( i < hp_len ) continue; // estimate transmitted signal float complex d_prime = (crealf(d_hat) > 0.0f ? M_SQRT1_2 : -M_SQRT1_2) + (cimagf(d_hat) > 0.0f ? M_SQRT1_2 : -M_SQRT1_2) * _Complex_I; // update equalizer eqlms_cccf_step(eq, d_prime, d_hat); } // get equalizer weights eqlms_cccf_get_weights(eq, hp); // destroy equalizer object eqlms_cccf_destroy(eq); // 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 // 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,"npfb=%u;\n",npfb); fprintf(fid,"num_symbols=%u;\n",num_symbols); for (i=0; i<ht_len; i++) fprintf(fid,"ht(%3u) = %12.5f;\n", i+1, ht[i]); for (i=0; i<hc_len; i++) fprintf(fid,"hc(%3u) = %12.5f + j*%12.8f;\n", i+1, crealf(hc[i]), cimagf(hc[i])); for (i=0; i<hp_len; i++) fprintf(fid,"hp(%3u) = %12.5f + j*%12.8f;\n", i+1, crealf(hp[i]), cimagf(hp[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; 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])); #if 0 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;\n"); fprintf(fid,"iz = 1:k: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','optimim timing',1);\n"); #endif // plot frequency response 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,"Hc = 20*log10(abs(fftshift(fft(hc, nfft))));\n"); fprintf(fid,"Hp = 20*log10(abs(fftshift(fft(hp, nfft))));\n"); fprintf(fid,"figure;\n"); fprintf(fid,"plot(f,Ht, f,Hc, f,Hp);\n"); fprintf(fid,"axis([-0.5 0.5 -20 10]);\n"); fprintf(fid,"grid on;\n"); fprintf(fid,"legend('transmit','channel','equalizer',1);\n"); fprintf(fid,"i0 = [1:round(length(sym_out)/2)];\n"); fprintf(fid,"i1 = [round(length(sym_out)/2):length(sym_out)];\n"); fprintf(fid,"figure;\n"); fprintf(fid,"plot(real(sym_out(i0)),imag(sym_out(i0)),'x','MarkerSize',4,'Color',[0.60 0.60 0.60],...\n"); fprintf(fid," real(sym_out(i1)),imag(sym_out(i1)),'x','MarkerSize',4,'Color',[0.00 0.25 0.50]);\n"); fprintf(fid,"axis square;\n"); fprintf(fid,"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 50%%'],['last 50%%'],1);\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[]) { 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; }