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[]) { srand(time(NULL)); // options unsigned int k=2; // filter samples/symbol unsigned int num_sync_symbols = 64; // number of synchronization symbols float SNRdB = 20.0f; // signal-to-noise ratio [dB] float dphi_max = 0.02f; // maximum carrier frequency offset unsigned int num_trials = 1000; // number of trials to run int verbosity = 1; // verbosity level int dopt; while ((dopt = getopt(argc,argv,"hvqk:n:F:S:t:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'v': verbosity++; break; case 'q': verbosity--; break; case 'k': k = atoi(optarg); break; case 'n': num_sync_symbols = atoi(optarg); break; case 'F': dphi_max = atof(optarg); break; case 'S': SNRdB = atof(optarg); break; case 't': num_trials = atoi(optarg); break; default: exit(1); } } unsigned int i; // arrays float complex seq[k*num_sync_symbols]; // synchronization pattern (samples) float rxy_max[num_trials]; float dphi_err[num_trials]; float delay_err[num_trials]; // generate synchronization pattern (BPSK) and interpolate unsigned int n=0; for (i=0; i<num_sync_symbols; i++) { float sym = rand() % 2 ? -1.0f : 1.0f; unsigned int j; for (j=0; j<k; j++) seq[n++] = sym; } // create cross-correlator bpresync_cccf sync = bpresync_cccf_create(seq, k*num_sync_symbols, 0.05f, 11); bpresync_cccf_print(sync); // run trials printf("running %u trials...\n", num_trials); bpresync_test(sync, seq, k*num_sync_symbols, SNRdB, dphi_max, rxy_max, dphi_err, delay_err, num_trials, verbosity); // destroy objects bpresync_cccf_destroy(sync); // print results float rxy_max_avg = 0.0f; float dphi_err_rmse = 0.0f; float delay_err_rmse = 0.0f; for (i=0; i<num_trials; i++) { rxy_max_avg += rxy_max[i]; dphi_err_rmse += dphi_err[i]*dphi_err[i]; delay_err_rmse += delay_err[i]*delay_err[i]; } rxy_max_avg = rxy_max_avg / (float)num_trials; dphi_err_rmse = sqrtf( dphi_err_rmse / (float)num_trials ); delay_err_rmse = sqrtf( delay_err_rmse / (float)num_trials ); printf("\n"); printf(" rxy_max (average) : %12.8f\n", rxy_max_avg); printf(" dphi estimate (RMSE) : %12.8f\n", dphi_err_rmse); printf(" delay estimate (RMSE) : %12.8f\n", delay_err_rmse); // // 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_trials = %u;\n", num_trials); fprintf(fid,"k = %u;\n", k); fprintf(fid,"rxy_max = zeros(1,num_trials);\n"); fprintf(fid,"dphi_err = zeros(1,num_trials);\n"); fprintf(fid,"delay_err = zeros(1,num_trials);\n"); for (i=0; i<num_trials; i++) { fprintf(fid,"rxy_max(%4u) = %12.4e;\n", i+1, rxy_max[i]); fprintf(fid,"dphi_err(%4u) = %12.4e;\n", i+1, dphi_err[i]); fprintf(fid,"delay_err(%4u) = %12.4e;\n", i+1, delay_err[i]); } fprintf(fid,"figure;\n"); fprintf(fid," hist(rxy_max, 25);\n"); fprintf(fid," xlabel('|r_{xy}|');\n"); fprintf(fid," ylabel('histogram');\n"); fclose(fid); printf("results written to '%s'\n", OUTPUT_FILENAME); return 0; }