int main(int argc, char*argv[]) { srand(time(NULL)); // options unsigned int k=2; // filter samples/symbol unsigned int m=4; // filter delay (symbols) float beta=0.3f; // bandwidth-time product float dt = 0.0f; // fractional sample timing offset unsigned int num_sync_symbols = 64; // number of data symbols float SNRdB = 30.0f; // signal-to-noise ratio [dB] float dphi = 0.0f; // carrier frequency offset float phi = 0.0f; // carrier phase offset unsigned int num_delay_symbols = 12; unsigned int num_dphi_hat = 21; // number of frequency offset estimates float dphi_hat_step = 0.01f; // frequency offset step size int dopt; while ((dopt = getopt(argc,argv,"uhk:m:n:b:t:F:P:s:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'n': num_sync_symbols = atoi(optarg); break; case 'b': beta = atof(optarg); break; case 't': dt = atof(optarg); break; case 'F': dphi = atof(optarg); break; case 'P': phi = atof(optarg); break; case 's': SNRdB = atof(optarg); break; default: exit(1); } } unsigned int i; // validate input if (beta <= 0.0f || beta >= 1.0f) { fprintf(stderr,"error: %s, bandwidth-time product must be in (0,1)\n", argv[0]); exit(1); } else if (dt < -0.5 || dt > 0.5) { fprintf(stderr,"error: %s, fractional sample offset must be in (0,1)\n", argv[0]); exit(1); } // derived values unsigned int num_symbols = num_delay_symbols + num_sync_symbols + 2*m; unsigned int num_samples = k*num_symbols; unsigned int num_sync_samples = k*num_sync_symbols; float nstd = powf(10.0f, -SNRdB/20.0f); // arrays float complex seq[num_sync_symbols]; // data sequence (symbols) float complex s0[num_sync_samples]; // data sequence (interpolated samples) float complex x[num_samples]; // transmitted signal float complex y[num_samples]; // received signal float rxy[num_dphi_hat][num_samples]; // pre-demod output matrix // generate sequence for (i=0; i<num_sync_symbols; i++) { float sym_i = rand() % 2 ? M_SQRT1_2 : -M_SQRT1_2; float sym_q = rand() % 2 ? M_SQRT1_2 : -M_SQRT1_2; seq[i] = sym_i + _Complex_I*sym_q; } // create interpolated sequence, compensating for filter delay firinterp_crcf interp_seq = firinterp_crcf_create_rnyquist(LIQUID_RNYQUIST_RRC,k,m,beta,0.0f); for (i=0; i<num_sync_symbols+m; i++) { if (i < m) firinterp_crcf_execute(interp_seq, seq[i], &s0[0]); else if (i < num_sync_symbols) firinterp_crcf_execute(interp_seq, seq[i], &s0[k*(i-m)]); else firinterp_crcf_execute(interp_seq, 0, &s0[k*(i-m)]); } firinterp_crcf_destroy(interp_seq); // compute g = E{ |s0|^2 } float g = 0.0f; for (i=0; i<num_sync_samples; i++) g += crealf( s0[i]*conjf(s0[i]) ); // create transmit interpolator and generate sequence firinterp_crcf interp_tx = firinterp_crcf_create_rnyquist(LIQUID_RNYQUIST_RRC,k,m,beta,dt); unsigned int n=0; for (i=0; i<num_delay_symbols; i++) { firinterp_crcf_execute(interp_tx, 0, &x[k*n]); n++; } for (i=0; i<num_sync_symbols; i++) { firinterp_crcf_execute(interp_tx, seq[i], &x[k*n]); n++; } for (i=0; i<2*m; i++) { firinterp_crcf_execute(interp_tx, 0, &x[k*n]); n++; } assert(n==num_symbols); firinterp_crcf_destroy(interp_tx); // add channel impairments for (i=0; i<num_samples; i++) { y[i] = x[i]*cexp(_Complex_I*(dphi*i + phi)) + nstd*( randnf() + _Complex_I*randnf() ); } float complex z; // filter output sample for (n=0; n<num_dphi_hat; n++) { float dphi_hat = ((float)n - 0.5*(float)(num_dphi_hat-1)) * dphi_hat_step; printf(" dphi_hat : %12.8f\n", dphi_hat); // create flipped, conjugated coefficients float complex s1[num_sync_samples]; for (i=0; i<num_sync_samples; i++) s1[i] = conjf( s0[num_sync_samples-i-1]*cexpf(_Complex_I*(dphi_hat*i)) ); // create matched filter and detect signal firfilt_cccf fsync = firfilt_cccf_create(s1, num_sync_samples); for (i=0; i<num_samples; i++) { firfilt_cccf_push(fsync, y[i]); firfilt_cccf_execute(fsync, &z); rxy[n][i] = cabsf(z) / g; } // destroy filter firfilt_cccf_destroy(fsync); } // print results //printf("rxy (max) : %12.8f\n", rxy_max); // // 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,"k = %u;\n", k); fprintf(fid,"m = %u;\n", m); fprintf(fid,"beta = %f;\n", beta); fprintf(fid,"num_sync_symbols = %u;\n", num_sync_symbols); fprintf(fid,"num_sync_samples = k*num_sync_symbols;\n"); fprintf(fid,"num_symbols = %u;\n", num_symbols); fprintf(fid,"num_samples = %u;\n", num_samples); fprintf(fid,"num_dphi_hat = %u;\n", num_dphi_hat); fprintf(fid,"dphi_hat_step = %f;\n", dphi_hat_step); // save sequence symbols fprintf(fid,"seq = zeros(1,num_sync_symbols);\n"); for (i=0; i<num_sync_symbols; i++) fprintf(fid,"seq(%4u) = %12.8f + j*%12.8f;\n", i+1, crealf(seq[i]), cimagf(seq[i])); // save interpolated sequence fprintf(fid,"s = zeros(1,num_sync_samples);\n"); for (i=0; i<num_sync_samples; i++) fprintf(fid,"s(%4u) = %12.8f + j*%12.8f;\n", i+1, crealf(s0[i]), cimagf(s0[i])); fprintf(fid,"x = zeros(1,num_samples);\n"); fprintf(fid,"y = zeros(1,num_samples);\n"); for (i=0; i<num_samples; i++) { fprintf(fid,"x(%6u) = %12.8f + j*%12.8f;\n", i+1, crealf(x[i]), cimagf(x[i])); fprintf(fid,"y(%6u) = %12.8f + j*%12.8f;\n", i+1, crealf(y[i]), cimagf(y[i])); } // save cross-correlation output fprintf(fid,"rxy = zeros(num_dphi_hat,num_samples);\n"); for (n=0; n<num_dphi_hat; n++) { for (i=0; i<num_samples; i++) { fprintf(fid,"rxy(%6u,%6u) = %12.8f;\n", n+1, i+1, rxy[n][i]); } } fprintf(fid,"t=[0:(num_samples-1)]/k;\n"); fprintf(fid,"figure;\n"); fprintf(fid,"plot(1:length(s),real(s), 1:length(s),imag(s));\n"); fprintf(fid,"dphi_hat = ( [0:(num_dphi_hat-1)] - (num_dphi_hat-1)/2 ) * dphi_hat_step;\n"); fprintf(fid,"mesh(dphi_hat, t, rxy');\n"); #if 0 fprintf(fid,"z = abs( z );\n"); fprintf(fid,"[zmax i] = max(z);\n"); fprintf(fid,"plot(1:length(z),z,'-x');\n"); fprintf(fid,"axis([(i-8*k) (i+8*k) 0 zmax*1.2]);\n"); fprintf(fid,"grid on\n"); #endif fclose(fid); printf("results written to '%s'\n", OUTPUT_FILENAME); 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 = 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[]) { srand(time(NULL)); // options unsigned int k=2; // filter samples/symbol unsigned int m=5; // filter delay (symbols) float beta=0.3f; // bandwidth-time product float dt = 0.0f; // fractional sample timing offset unsigned int num_sync_symbols = 64; // number of synchronization symbols float SNRdB = 20.0f; // signal-to-noise ratio [dB] float dphi = 0.02f; // carrier frequency offset float phi = 2*M_PI*randf(); // carrier phase offset int dopt; while ((dopt = getopt(argc,argv,"uhk:m:n:b:t:F:t:S:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'n': num_sync_symbols = atoi(optarg); break; case 'b': beta = atof(optarg); break; case 'F': dphi = atof(optarg); break; case 't': dt = atof(optarg); break; case 'S': SNRdB = atof(optarg); break; default: exit(1); } } unsigned int i; // validate input if (beta <= 0.0f || beta >= 1.0f) { fprintf(stderr,"error: %s, bandwidth-time product must be in (0,1)\n", argv[0]); exit(1); } else if (dt < -0.5f || dt > 0.5f) { fprintf(stderr,"error: %s, fractional sample offset must be in [-0.5,0.5]\n", argv[0]); exit(1); } // derived values unsigned int num_symbols = num_sync_symbols + 2*m + 10; unsigned int num_samples = k*num_symbols; float nstd = powf(10.0f, -SNRdB/20.0f); // arrays float complex seq[num_sync_symbols]; // synchronization pattern (symbols) float complex s0[k*num_sync_symbols]; // synchronization pattern (samples) float complex x[num_samples]; // transmitted signal float complex y[num_samples]; // received signal float complex rxy[num_samples]; // pre-demod correlation output float dphi_hat[num_samples]; // carrier offset estimate // create transmit/receive interpolator/decimator firinterp_crcf interp = firinterp_crcf_create_prototype(LIQUID_FIRFILT_RRC,k,m,beta,dt); // generate synchronization pattern (BPSK) and interpolate for (i=0; i<num_sync_symbols + 2*m; i++) { float complex sym = 0.0f; if (i < num_sync_symbols) { sym = rand() % 2 ? -1.0f : 1.0f; seq[i] = sym; } if (i < 2*m) firinterp_crcf_execute(interp, sym, s0); else firinterp_crcf_execute(interp, sym, &s0[k*(i-2*m)]); } // reset interpolator firinterp_crcf_reset(interp); // interpolate input for (i=0; i<num_symbols; i++) { float complex sym = i < num_sync_symbols ? seq[i] : 0.0f; firinterp_crcf_execute(interp, sym, &x[k*i]); } // push through channel for (i=0; i<num_samples; i++) y[i] = x[i]*cexpf(_Complex_I*(dphi*i + phi)) + nstd*(randnf() + _Complex_I*randnf())*M_SQRT1_2; // create cross-correlator bpresync_cccf sync = bpresync_cccf_create(s0, k*num_sync_symbols, 0.05f, 11); bpresync_cccf_print(sync); // push signal through cross-correlator float rxy_max = 0.0f; // maximum cross-correlation float dphi_est = 0.0f; // carrier frequency offset estimate int delay_est = 0; // delay estimate for (i=0; i<num_samples; i++) { // correlate bpresync_cccf_push(sync, y[i]); bpresync_cccf_execute(sync, &rxy[i], &dphi_hat[i]); // detect... if (cabsf(rxy[i]) > 0.6f) { printf("****** preamble found, rxy = %12.8f (dphi-hat: %12.8f), i=%3u ******\n", cabsf(rxy[i]), dphi_hat[i], i); } // retain maximum if (cabsf(rxy[i]) > rxy_max) { rxy_max = cabsf(rxy[i]); dphi_est = dphi_hat[i]; delay_est = (int)i - (int)2*k*m + 1; } } // destroy objects firinterp_crcf_destroy(interp); bpresync_cccf_destroy(sync); // print results printf("\n"); printf("rxy (max) : %12.8f\n", rxy_max); printf("dphi est. : %12.8f ,error=%12.8f\n", dphi_est, dphi-dphi_est); printf("delay est.: %12d ,error=%3d sample(s)\n", delay_est, k*num_sync_symbols - delay_est); printf("\n"); // // 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,"num_samples = %u;\n", num_samples); fprintf(fid,"num_symbols = %u;\n", num_symbols); fprintf(fid,"k = %u;\n", k); fprintf(fid,"x = zeros(1,num_samples);\n"); fprintf(fid,"y = zeros(1,num_samples);\n"); fprintf(fid,"rxy = zeros(1,num_samples);\n"); for (i=0; i<num_samples; i++) { fprintf(fid,"x(%4u) = %12.8f + j*%12.8f;\n", i+1, crealf(x[i]), cimagf(x[i])); fprintf(fid,"y(%4u) = %12.8f + j*%12.8f;\n", i+1, crealf(y[i]), cimagf(y[i])); fprintf(fid,"rxy(%4u) = %12.8f + j*%12.8f;\n", i+1, crealf(rxy[i]), cimagf(rxy[i])); } fprintf(fid,"t=[0:(num_samples-1)]/k;\n"); fprintf(fid,"figure;\n"); fprintf(fid,"subplot(2,1,1);\n"); fprintf(fid," plot(t,real(y), t,imag(y));\n"); fprintf(fid," axis([0 num_symbols -2 2]);\n"); fprintf(fid," grid on;\n"); fprintf(fid," xlabel('time');\n"); fprintf(fid," ylabel('received signal');\n"); fprintf(fid,"subplot(2,1,2);\n"); fprintf(fid," plot(t,abs(rxy));\n"); fprintf(fid," axis([0 num_symbols 0 1.5]);\n"); fprintf(fid," xlabel('time');\n"); fprintf(fid," ylabel('correlator output');\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 k=2; // samples/symbol unsigned int m=2; // filter delay float beta = 0.5f; // filter excess bandwidth unsigned int num_data_symbols=8; // number of data symbols int dopt; while ((dopt = getopt(argc,argv,"uhk:m:b:n:")) != 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 'n': num_data_symbols = atoi(optarg); break; default: usage(); return 1; } } // validate options if (k < 2) { fprintf(stderr,"error: %s, interp factor must be greater than 1\n", argv[0]); return 1; } else if (m < 1) { fprintf(stderr,"error: %s, filter delay must be greater than 0\n", argv[0]); return 1; } else if (beta <= 0.0 || beta > 1.0f) { fprintf(stderr,"error: %s, beta (excess bandwidth factor) must be in (0,1]\n", argv[0]); return 1; } else if (num_data_symbols < 1) { fprintf(stderr,"error: %s, must have at least one data symbol\n", argv[0]); return 1; } // derived values unsigned int h_len = 2*k*m+1; unsigned int num_symbols = num_data_symbols + 2*m; unsigned int num_samples = k*num_symbols; // design filter and create interpolator and decimator objects float h[h_len]; // transmit filter float g[h_len]; // receive filter (reverse of h) liquid_firdes_rrcos(k,m,beta,0.3f,h); unsigned int i; for (i=0; i<h_len; i++) g[i] = h[h_len-i-1]; firinterp_crcf interp = firinterp_crcf_create(k,h,h_len); firdecim_crcf decim = firdecim_crcf_create(k,g,h_len); // allocate memory for buffers float complex x[num_symbols]; // input symbols float complex y[num_samples]; // interpolated sequence float complex z[num_symbols]; // decimated (received) symbols // generate input symbols, padded with zeros at the end for (i=0; i<num_data_symbols; i++) { x[i] = (rand() % 2 ? 1.0f : -1.0f) + (rand() % 2 ? 1.0f : -1.0f) * _Complex_I; } for ( ; i<num_symbols; i++) x[i] = 0.0f; // run interpolator for (i=0; i<num_symbols; i++) { firinterp_crcf_execute(interp, x[i], &y[k*i]); } // run decimator for (i=0; i<num_symbols; i++) { firdecim_crcf_execute(decim, &y[k*i], &z[i]); // normalize output by samples/symbol z[i] /= k; } // destroy objects firinterp_crcf_destroy(interp); firdecim_crcf_destroy(decim); // print results to screen printf("filter impulse response :\n"); for (i=0; i<h_len; i++) printf(" [%4u] : %8.4f\n", i, h[i]); printf("input symbols\n"); for (i=0; i<num_symbols; i++) { printf(" [%4u] : %8.4f + j*%8.4f", i, crealf(x[i]), cimagf(x[i])); // highlight actual data symbols if (i < num_data_symbols) printf(" *\n"); else printf("\n"); } printf("interpolator output samples:\n"); for (i=0; i<num_samples; i++) { printf(" [%4u] : %8.4f + j*%8.4f", i, crealf(y[i]), cimagf(y[i])); if ( (i >= k*m) && ((i%k)==0)) printf(" **\n"); else printf("\n"); } printf("output symbols:\n"); for (i=0; i<num_symbols; i++) { printf(" [%4u] : %8.4f + j*%8.4f", i, crealf(z[i]), cimagf(z[i])); // highlight symbols (compensate for filter delay) if ( i < 2*m ) printf("\n"); else printf(" *\n"); } // open output file FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s: auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n"); fprintf(fid,"k = %u;\n", k); fprintf(fid,"m = %u;\n", m); fprintf(fid,"h_len=%u;\n",h_len); fprintf(fid,"num_symbols = %u;\n", num_symbols); fprintf(fid,"num_samples = k*num_symbols;\n"); fprintf(fid,"h = zeros(1,h_len);\n"); fprintf(fid,"x = zeros(1,num_symbols);\n"); fprintf(fid,"y = zeros(1,num_samples);\n"); for (i=0; i<h_len; i++) fprintf(fid,"h(%4u) = %12.4e;\n", i+1, h[i]); for (i=0; i<num_symbols; i++) fprintf(fid,"x(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(x[i]), cimagf(x[i])); for (i=0; i<num_samples; i++) fprintf(fid,"y(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(y[i]), cimagf(y[i])); for (i=0; i<num_symbols; i++) fprintf(fid,"z(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(z[i]), cimagf(z[i])); fprintf(fid,"\n\n"); fprintf(fid,"tx = [0:(num_symbols-1)];\n"); fprintf(fid,"ty = [0:(num_samples-1)]/k - m;\n"); fprintf(fid,"tz = [0:(num_symbols-1)] - 2*m;\n"); fprintf(fid,"figure;\n"); fprintf(fid,"subplot(2,1,1);\n"); fprintf(fid," plot(ty,real(y),'-',tx,real(x),'s',tz,real(z),'x');\n"); fprintf(fid," xlabel('time');\n"); fprintf(fid," ylabel('real');\n"); fprintf(fid," grid on;\n"); fprintf(fid," legend('interp','data in','data out',0);\n"); fprintf(fid,"subplot(2,1,2);\n"); fprintf(fid," plot(ty,imag(y),'-',tx,imag(x),'s',tz,imag(z),'x');\n"); fprintf(fid," xlabel('time');\n"); fprintf(fid," ylabel('imag');\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[]) { // options float noise_floor= -40.0f; // noise floor [dB] float SNRdB = 20.0f; // signal-to-noise ratio [dB] float bt = 0.05f; // loop bandwidth unsigned int num_symbols= 100; // number of iterations unsigned int d = 5; // print every d iterations unsigned int k = 2; // interpolation factor (samples/symbol) unsigned int m = 3; // filter delay (symbols) float beta = 0.3f; // filter excess bandwidth factor float dt = 0.0f; // filter fractional sample delay // derived values unsigned int num_samples=num_symbols*k; float gamma = powf(10.0f, (SNRdB+noise_floor)/20.0f); // channel gain float nstd = powf(10.0f, noise_floor / 20.0f); // arrays float complex x[num_samples]; float complex y[num_samples]; float rssi[num_samples]; // create objects modem mod = modem_create(LIQUID_MODEM_QPSK); firinterp_crcf interp = firinterp_crcf_create_prototype(LIQUID_FIRFILT_RRC,k,m,beta,dt); agc_crcf p = agc_crcf_create(); agc_crcf_set_bandwidth(p, bt); unsigned int i; // print info printf("automatic gain control // loop bandwidth: %4.2e\n",bt); unsigned int sym; float complex s; for (i=0; i<num_symbols; i++) { // generate random symbol sym = modem_gen_rand_sym(mod); modem_modulate(mod, sym, &s); s *= gamma; firinterp_crcf_execute(interp, s, &x[i*k]); } // add noise for (i=0; i<num_samples; i++) x[i] += nstd*(randnf() + _Complex_I*randnf()) * M_SQRT1_2; // run agc for (i=0; i<num_samples; i++) { agc_crcf_execute(p, x[i], &y[i]); rssi[i] = agc_crcf_get_rssi(p); } // destroy objects modem_destroy(mod); agc_crcf_destroy(p); firinterp_crcf_destroy(interp); // print results to screen printf("received signal strength indication (rssi):\n"); for (i=0; i<num_samples; i+=d) { printf("%4u : %8.2f\n", i, rssi[i]); } // // export results // FILE* fid = fopen(OUTPUT_FILENAME,"w"); if (!fid) { fprintf(stderr,"error: %s, could not open '%s' for writing\n", argv[0], OUTPUT_FILENAME); exit(1); } fprintf(fid,"%% %s: auto-generated file\n\n",OUTPUT_FILENAME); fprintf(fid,"n = %u;\n", num_samples); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n\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,"rssi(%4u) = %12.4e;\n", i+1, rssi[i]); } fprintf(fid,"\n\n"); fprintf(fid,"n = length(x);\n"); fprintf(fid,"t = 0:(n-1);\n"); fprintf(fid,"figure('position',[100 100 800 600]);\n"); fprintf(fid,"subplot(2,1,1);\n"); fprintf(fid," plot(t,rssi,'-k','LineWidth',2);\n"); fprintf(fid," xlabel('sample index');\n"); fprintf(fid," ylabel('rssi [dB]');\n"); fprintf(fid," grid on;\n"); fprintf(fid,"subplot(2,1,2);\n"); fprintf(fid," plot(t,real(y),t,imag(y));\n"); fprintf(fid," xlabel('sample index');\n"); fprintf(fid," ylabel('agc output');\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 k = 2; // samples/symbol (input) unsigned int m = 3; // filter delay (symbols) float beta = 0.5f; // filter excess bandwidth factor unsigned int num_filters = 32; // number of filters in the bank float SNRdB = 30.0f; // signal-to-noise ratio float bt = 0.02f; // loop filter bandwidth unsigned int num_symbols = 400; // number of data symbols float tau = -0.20f; // fractional symbol offset // Nyquist filter type liquid_firfilt_type ftype = LIQUID_FIRFILT_KAISER; int dopt; while ((dopt = getopt(argc,argv,"uhk:m:b:B:s:w:n:t:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'k': k = 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; default: exit(1); } } unsigned int i; // 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); } // derived values unsigned int num_samples = k*num_symbols; float complex x[num_samples]; // interpolated samples float complex y[num_samples]; // received signal (with noise) float tau_hat[num_samples]; // instantaneous timing offset estimate float complex sym_out[num_symbols + 64];// synchronized symbols // create sequence of Nyquist-interpolated QPSK symbols firinterp_crcf interp = firinterp_crcf_create_nyquist(ftype,k,m,beta,tau); for (i=0; i<num_symbols; i++) { // generate random QPSK symbol float complex s = ( rand() % 2 ? M_SQRT1_2 : -M_SQRT1_2 ) + ( rand() % 2 ? M_SQRT1_2 : -M_SQRT1_2 ) * _Complex_I; // interpolate symbol firinterp_crcf_execute(interp, s, &x[i*k]); } firinterp_crcf_destroy(interp); // add noise float nstd = powf(10.0f, -SNRdB/20.0f); for (i=0; i<num_samples; i++) y[i] = x[i] + nstd*(randnf() + _Complex_I*randnf()); // create and run symbol synchronizer symsync_crcf decim = symsync_crcf_create_kaiser(k, m, beta, num_filters); symsync_crcf_set_lf_bw(decim,bt); // set loop filter bandwidth // NOTE: we could just synchronize entire block (see following line); // however we would like to save the instantaneous timing offset // estimate for plotting purposes //symsync_crcf_execute(d, y, num_samples, sym_out, &num_symbols_sync); unsigned int num_symbols_sync = 0; unsigned int num_written=0; for (i=0; i<num_samples; i++) { // save instantaneous timing offset estimate tau_hat[i] = symsync_crcf_get_tau(decim); // execute one sample at a time symsync_crcf_execute(decim, &y[i], 1, &sym_out[num_symbols_sync], &num_written); // increment number of symbols synchronized num_symbols_sync += num_written; } symsync_crcf_destroy(decim); // 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,"num_filters=%u;\n",num_filters); fprintf(fid,"num_symbols=%u;\n",num_symbols); 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; i++) fprintf(fid,"tau_hat(%3u) = %12.8f;\n", i+1, tau_hat[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])); fprintf(fid,"i0 = 1:round( 0.5*num_symbols );\n"); fprintf(fid,"i1 = round( 0.5*num_symbols ):num_symbols;\n"); fprintf(fid,"figure;\n"); fprintf(fid,"hold on;\n"); fprintf(fid,"plot(real(sym_out(i0)),imag(sym_out(i0)),'x','MarkerSize',4,'Color',[0.6 0.6 0.6]);\n"); fprintf(fid,"plot(real(sym_out(i1)),imag(sym_out(i1)),'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]*1.6);\n"); fprintf(fid,"xlabel('In-phase');\n"); fprintf(fid,"ylabel('Quadrature');\n"); fprintf(fid,"legend(['first 50%%'],['last 50%%'],1);\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[]) { 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); 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) / 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; }
// create flexframesync object // _callback : callback function invoked when frame is received // _userdata : user-defined data object passed to callback flexframesync flexframesync_create(framesync_callback _callback, void * _userdata) { flexframesync q = (flexframesync) malloc(sizeof(struct flexframesync_s)); q->callback = _callback; q->userdata = _userdata; unsigned int i; // generate p/n sequence msequence ms = msequence_create(6, 0x005b, 1); for (i=0; i<64; i++) q->preamble_pn[i] = (msequence_advance(ms)) ? 1.0f : -1.0f; msequence_destroy(ms); // interpolate p/n sequence with matched filter q->k = 2; // samples/symbol q->m = 7; // filter delay (symbols) q->beta = 0.25f; // excess bandwidth factor float complex seq[q->k*64]; firinterp_crcf interp = firinterp_crcf_create_rnyquist(LIQUID_FIRFILT_ARKAISER,q->k,q->m,q->beta,0); for (i=0; i<64+q->m; i++) { // compensate for filter delay if (i < q->m) firinterp_crcf_execute(interp, q->preamble_pn[i], &seq[0]); else firinterp_crcf_execute(interp, q->preamble_pn[i%64], &seq[q->k*(i-q->m)]); } firinterp_crcf_destroy(interp); // create frame detector float threshold = 0.4f; // detection threshold float dphi_max = 0.05f; // maximum carrier offset allowable q->frame_detector = detector_cccf_create(seq, q->k*64, threshold, dphi_max); q->buffer = windowcf_create(q->k*(64+q->m)); // create symbol timing recovery filters q->npfb = 32; // number of filters in the bank q->mf = firpfb_crcf_create_rnyquist(LIQUID_FIRFILT_ARKAISER, q->npfb,q->k,q->m,q->beta); q->dmf = firpfb_crcf_create_drnyquist(LIQUID_FIRFILT_ARKAISER,q->npfb,q->k,q->m,q->beta); // create down-coverters for carrier phase tracking q->nco_coarse = nco_crcf_create(LIQUID_NCO); q->nco_fine = nco_crcf_create(LIQUID_VCO); nco_crcf_pll_set_bandwidth(q->nco_fine, 0.05f); // create header objects q->demod_header = modem_create(LIQUID_MODEM_BPSK); q->p_header = packetizer_create(FLEXFRAME_H_DEC, FLEXFRAME_H_CRC, FLEXFRAME_H_FEC0, FLEXFRAME_H_FEC1); assert(packetizer_get_enc_msg_len(q->p_header)==FLEXFRAME_H_ENC); // frame properties (default values to be overwritten when frame // header is received and properly decoded) q->ms_payload = LIQUID_MODEM_QPSK; q->bps_payload = 2; q->payload_dec_len = 1; q->check = LIQUID_CRC_NONE; q->fec0 = LIQUID_FEC_NONE; q->fec1 = LIQUID_FEC_NONE; // create payload objects (overridden by received properties) q->demod_payload = modem_create(LIQUID_MODEM_QPSK); q->p_payload = packetizer_create(q->payload_dec_len, q->check, q->fec0, q->fec1); q->payload_enc_len = packetizer_get_enc_msg_len(q->p_payload); q->payload_mod_len = 4 * q->payload_enc_len; q->payload_mod = (unsigned char*) malloc(q->payload_mod_len*sizeof(unsigned char)); q->payload_enc = (unsigned char*) malloc(q->payload_enc_len*sizeof(unsigned char)); q->payload_dec = (unsigned char*) malloc(q->payload_dec_len*sizeof(unsigned char)); #if DEBUG_FLEXFRAMESYNC // set debugging flags, objects to NULL q->debug_enabled = 0; q->debug_objects_created = 0; q->debug_x = NULL; #endif // reset state flexframesync_reset(q); return q; }
int main(int argc, char*argv[]) { // options unsigned int k=4; // samples/symbol unsigned int m=3; // filter delay float As = 60.0f; // filter stop-band attenuation unsigned int num_data_symbols=16; // number of data symbols int dopt; while ((dopt = getopt(argc,argv,"uhk:m:s:n:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 's': As = atof(optarg); break; case 'n': num_data_symbols = atoi(optarg); break; default: exit(1); } } // validate options if (k < 2) { fprintf(stderr,"error: %s, interp factor must be greater than 1\n", argv[0]); exit(1); } else if (m < 1) { fprintf(stderr,"error: %s, filter delay must be greater than 0\n", argv[0]); exit(1); } else if (num_data_symbols < 1) { fprintf(stderr,"error: %s, must have at least one data symbol\n", argv[0]); usage(); return 1; } // derived values unsigned int num_symbols = num_data_symbols + 2*m; // compensate for filter delay unsigned int num_samples = k*num_symbols; // create interpolator from prototype firinterp_crcf q = firinterp_crcf_create_prototype(k,m,As); // generate input signal and interpolate float complex x[num_symbols]; // input symbols float complex y[num_samples]; // output samples unsigned int i; for (i=0; i<num_data_symbols; i++) { x[i] = (rand() % 2 ? 1.0f : -1.0f) + (rand() % 2 ? 1.0f : -1.0f) * _Complex_I; } // pad end of sequence with zeros for (i=num_data_symbols; i<num_symbols; i++) x[i] = 0.0f; // interpolate symbols for (i=0; i<num_symbols; i++) firinterp_crcf_execute(q, x[i], &y[k*i]); // destroy interpolator object firinterp_crcf_destroy(q); // print results to screen printf("x(t) :\n"); for (i=0; i<num_symbols; i++) printf(" x(%4u) = %8.4f + j*%8.4f;\n", i, crealf(x[i]), cimagf(x[i])); printf("y(t) :\n"); for (i=0; i<num_samples; i++) { printf(" y(%4u) = %8.4f + j*%8.4f;", i, crealf(y[i]), cimagf(y[i])); if ( (i >= k*m) && ((i%k)==0)) printf(" **\n"); else printf("\n"); } // // export output file // FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s: auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n"); fprintf(fid,"k = %u;\n", k); fprintf(fid,"m = %u;\n", m); fprintf(fid,"num_symbols = %u;\n", num_symbols); fprintf(fid,"num_samples = k*num_symbols;\n"); fprintf(fid,"x = zeros(1,num_symbols);\n"); fprintf(fid,"y = zeros(1,num_samples);\n"); for (i=0; i<num_symbols; i++) fprintf(fid,"x(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(x[i]), cimagf(x[i])); for (i=0; i<num_samples; i++) fprintf(fid,"y(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(y[i]), cimagf(y[i])); fprintf(fid,"\n\n"); fprintf(fid,"tx = [0:(num_symbols-1)];\n"); fprintf(fid,"ty = [0:(num_samples-1)]/k - m;\n"); fprintf(fid,"figure;\n"); fprintf(fid,"subplot(2,1,1);\n"); fprintf(fid," plot(ty,real(y),'-',tx,real(x),'s');\n"); fprintf(fid," xlabel('time');\n"); fprintf(fid," ylabel('real');\n"); fprintf(fid," grid on;\n"); fprintf(fid,"subplot(2,1,2);\n"); fprintf(fid," plot(ty,imag(y),'-',tx,imag(x),'s');\n"); fprintf(fid," xlabel('time');\n"); fprintf(fid," ylabel('imag');\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; }
void autotest_firinterp_crcf_generic() { // h = [0, 0.25, 0.5, 0.75, 1.0, 0.75, 0.5, 0.25, 0]; float h[9] = { -0.7393353832652201, 0.1909821993029451, -1.7013834621383086, -0.6157406339062349, 0.5806218191269317, 0.0576963976148674, -1.0958217797368455, -0.6379821629743743, 0.7019489165905530}; unsigned int M = 4; // firinterp factor firinterp_crcf q = firinterp_crcf_create(M,h,9); // x = [1+j*0.2, -0.2+j*1.3, 0.5+j*0.3, 1.1-j*0.2] float complex x[4] = { 1.0000e+00+ 2.0000e-01*_Complex_I, -2.0000e-01+ 1.3000e+00*_Complex_I, 5.0000e-01+ 3.0000e-01*_Complex_I, 1.1000e+00+ -2.0000e-01*_Complex_I }; float complex y[16]; // z = [x(1) 0 0 0 x(2) 0 0 0 x(3) 0 0 0 x(4) 0 0 0]; // test = filter(h,1,z) float complex test[16] = { -0.7393353832652201 - 0.1478670766530440*_Complex_I, 0.1909821993029451 + 0.0381964398605890*_Complex_I, -1.7013834621383086 - 0.3402766924276617*_Complex_I, -0.6157406339062349 - 0.1231481267812470*_Complex_I, 0.7284888957799757 - 0.8450116344193997*_Complex_I, 0.0194999577542784 + 0.2598161386168021*_Complex_I, -0.7555450873091838 - 2.4309628567271702*_Complex_I, -0.5148340361931273 - 0.9280592566729803*_Complex_I, 0.2161568611325566 + 0.6733975332035558*_Complex_I, 0.0839518201284991 + 0.1322999766902112*_Complex_I, -0.6315273751217851 - 1.9349833522993918*_Complex_I, -0.1802738843582426 - 1.0140990020385570*_Complex_I, -0.6633477953463869 + 1.2345872139588425*_Complex_I, 0.2389286180406733 - 0.0208875205761288*_Complex_I, -2.4194326982205623 + 0.0115301585066081*_Complex_I, -0.9963057787840456 - 0.0682465221110653*_Complex_I }; float tol = 1e-6; unsigned int i; for (i=0; i<4; i++) firinterp_crcf_execute(q, x[i], &y[i*M]); for (i=0; i<16; i++) { CONTEND_DELTA( crealf(y[i]), crealf(test[i]), tol); CONTEND_DELTA( cimagf(y[i]), cimagf(test[i]), tol); if (liquid_autotest_verbose) printf(" y(%u) = %8.4f + j%8.4f;\n", i+1, crealf(y[i]), cimagf(y[i])); } if (liquid_autotest_verbose) firinterp_crcf_print(q); // destroy interpolator object firinterp_crcf_destroy(q); }
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_firfilt_type ftype = LIQUID_FIRFILT_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_prototype(ftype,k,m,beta,dt,ht); firinterp_crcf q = firinterp_crcf_create(k, ht, ht_len); for (i=0; i<num_symbols; i++) firinterp_crcf_execute(q, s[i], &x[i*k]); firinterp_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 as low-pass filter float complex hp[hp_len]; eqlms_cccf eq = eqlms_cccf_create_lowpass(hp_len, 0.4f); 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 // compute composite response fprintf(fid,"hd = real(conv(ht/k,conv(hc,hp)));\n"); // 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,"Hd = 20*log10(abs(fftshift(fft(hd, nfft))));\n"); fprintf(fid,"figure;\n"); fprintf(fid,"plot(f,Ht, f,Hc, f,Hp, f,Hd,'-k','LineWidth',2);\n"); fprintf(fid,"axis([-0.5 0.5 -20 10]);\n"); fprintf(fid,"axis([-0.5 0.5 -6 6 ]);\n"); fprintf(fid,"grid on;\n"); fprintf(fid,"legend('transmit','channel','equalizer','composite','location','northeast');\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%%'],'location','northeast');\n"); fclose(fid); printf("results written to %s.\n", OUTPUT_FILENAME); // clean it up printf("done.\n"); return 0; }
int main() { // spectral periodogram options unsigned int nfft=512; // spectral periodogram FFT size unsigned int num_samples = 4000; // number of samples float beta = 10.0f; // Kaiser-Bessel window parameter float noise_floor = -60.0f; // noise floor [dB] unsigned int i; // derived values float nstd = powf(10.0f, noise_floor/20.0f); // allocate memory for data arrays float complex X[nfft]; // output spectrum float psd[nfft]; // power spectral density // initialize PSD estimate for (i=0; i<nfft; i++) psd[i] = 0.0f; // create spectral periodogram unsigned int window_size = nfft/2; // spgram window size unsigned int delay = nfft/8; // samples between transforms spgram q = spgram_create_kaiser(nfft, window_size, beta); // generate signal (interpolated symbols with noise) unsigned int k = 4; // interpolation rate unsigned int m = 7; // filter delay (symbols) firinterp_crcf interp = firinterp_crcf_create_rnyquist(LIQUID_RNYQUIST_RKAISER, k, m, 0.3f, 0.0f); int spgram_timer = nfft; unsigned int n=0; float complex x[k]; // interpolator output unsigned int num_transforms = 0; while (n < num_samples) { // generate random symbol float complex s = ( rand() % 2 ? 0.707f : -0.707f ) + ( rand() % 2 ? 0.707f : -0.707f ) * _Complex_I; // interpolate firinterp_crcf_execute(interp, s, x); // add noise for (i=0; i<k; i++) x[i] += nstd * ( randnf() + _Complex_I*randnf() ) * M_SQRT1_2; // push resulting samples through spgram spgram_push(q, x, k); // spgram_timer -= k; n += k; // if (spgram_timer <= 0) { // update timer, counter spgram_timer += delay; num_transforms++; // run spectral periodogram spgram_execute(q, X); // accumulate PSD and FFT shift for (i=0; i<nfft; i++) { float complex X0 = X[(i+nfft/2)%nfft]; psd[i] += crealf(X0*conjf(X0)); } } } // destroy objects firinterp_crcf_destroy(interp); spgram_destroy(q); // normalize result printf("computed %u transforms\n", num_transforms); // TODO: ensure at least one transform was taken for (i=0; i<nfft; i++) psd[i] = 10*log10f( psd[i] / (float)(num_transforms) ); // // export output file // FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n\n"); fprintf(fid,"nfft = %u;\n", nfft); fprintf(fid,"f = [0:(nfft-1)]/nfft - 0.5;\n"); fprintf(fid,"H = zeros(1,nfft);\n"); fprintf(fid,"noise_floor = %12.6f;\n", noise_floor); for (i=0; i<nfft; i++) fprintf(fid,"H(%6u) = %12.4e;\n", i+1, psd[i]); fprintf(fid,"figure;\n"); fprintf(fid,"plot(f, H, '-', 'LineWidth',1.5);\n"); fprintf(fid,"xlabel('Normalized Frequency [f/F_s]');\n"); fprintf(fid,"ylabel('Power Spectral Density [dB]');\n"); fprintf(fid,"grid on;\n"); fprintf(fid,"ymin = 10*floor([noise_floor-20]/10);\n"); fprintf(fid,"ymax = 10*floor([noise_floor+80]/10);\n"); fprintf(fid,"axis([-0.5 0.5 ymin ymax]);\n"); fclose(fid); printf("results written to %s.\n", OUTPUT_FILENAME); printf("done.\n"); return 0; }