// 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[]) { 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() { // 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; }