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; }
void bpresync_test(bpresync_cccf _q, float complex * _x, unsigned int _n, float _SNRdB, float _dphi_max, float * _rxy_max, float * _dphi_err, float * _delay_err, unsigned int _num_trials, unsigned int _verbosity) { unsigned int max_delay = 64; float gamma = powf(10.0f, _SNRdB/20.0f); float nstd = 1.0f; // Farrow filter (for facilitating delay) unsigned int h_len = 49; unsigned int order = 4; float fc = 0.45f; float As = 60.0f; firfarrow_crcf fdelay = firfarrow_crcf_create(h_len, order, fc, As); unsigned int num_samples = _n + max_delay + (h_len-1)/2; float complex y[num_samples]; unsigned int t; for (t=0; t<_num_trials; t++) { unsigned int delay = rand() % max_delay; // sample delay float dt = randf() - 0.5f; // fractional sample delay float dphi = (2.0f*randf() - 1.0f) * _dphi_max; // carrier frequency offset float phi = 2*M_PI*randf(); // carrier phase offset // reset binary pre-demod synchronizer bpresync_cccf_reset(_q); // reset farrow filter firfarrow_crcf_clear(fdelay); firfarrow_crcf_set_delay(fdelay, dt); unsigned int i; unsigned int n=0; // generate signal: delay for (i=0; i<delay; i++) { firfarrow_crcf_push(fdelay, 0.0f); firfarrow_crcf_execute(fdelay, &y[n++]); } // generate signal: input sequence for (i=0; i<_n; i++) { firfarrow_crcf_push(fdelay, _x[i]); firfarrow_crcf_execute(fdelay, &y[n++]); } // generate signal: flush filter while (n < num_samples) { firfarrow_crcf_push(fdelay, 0.0f); firfarrow_crcf_execute(fdelay, &y[n++]); } // add channel gain, carrier offset, noise for (i=0; i<num_samples; i++) { y[i] *= gamma; y[i] *= cexpf(_Complex_I*(phi + i*dphi)); y[i] += nstd*( randnf() + randnf()*_Complex_I )*M_SQRT1_2; } // push through synchronizer _rxy_max[t] = 0.0f; _dphi_err[t] = 0.0f; _delay_err[t] = 0.0f; for (i=0; i<num_samples; i++) { // push through correlator float complex rxy; float dphi_est; bpresync_cccf_push(_q, y[i]); bpresync_cccf_correlate(_q, &rxy, &dphi_est); // retain maximum if ( cabsf(rxy) > _rxy_max[t] ) { _rxy_max[t] = cabsf(rxy); _dphi_err[t] = dphi_est - dphi; _delay_err[t] = (float)i - (float)(_n + delay + (h_len-1)/2) + 1.0f + dt; } } if (_verbosity == 0) { // do nothing } else if (_verbosity == 1) { // print progress bar if ( (t%100)==0 || t==_num_trials-1 ) { float percent = (float)(t+1) / (float)_num_trials; unsigned int bars = (unsigned int) (percent*60); printf("["); for (i=0; i<60; i++) printf("%c", i < bars ? '#' : ' '); printf("] %5.1f%%\r", percent*100); fflush(stdout); } } else { // print every trial printf(" %6u: rxy_max=%12.8f, dphi-err=%12.8f, delay-err=%12.8f\n", t, _rxy_max[t], _dphi_err[t], _delay_err[t]); } } // destroy Farrow filter firfarrow_crcf_destroy(fdelay); }