// Helper function to keep code base small void qdetector_cccf_bench(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations, unsigned int _n) { // adjust number of iterations *_num_iterations *= 4; *_num_iterations /= _n; // generate sequence (random) float complex h[_n]; unsigned long int i; for (i=0; i<_n; i++) { h[i] = (rand() % 2 ? 1.0f : -1.0f) + (rand() % 2 ? 1.0f : -1.0f)*_Complex_I; } // generate synchronizer int ftype = LIQUID_FIRFILT_ARKAISER; unsigned int k = 2; // samples/symbol unsigned int m = 7; // filter delay [symbols] float beta = 0.3f; // excess bandwidth factor float threshold = 0.5f; // threshold for detection float range = 0.05f; // carrier offset search range [radians/sample] qdetector_cccf q = qdetector_cccf_create_linear(h, _n, ftype, k, m, beta); qdetector_cccf_set_threshold(q,threshold); qdetector_cccf_set_range (q, range); // input sequence (random) float complex x[7]; for (i=0; i<7; i++) { x[i] = (rand() % 2 ? 1.0f : -1.0f) + (rand() % 2 ? 1.0f : -1.0f)*_Complex_I; } // start trials getrusage(RUSAGE_SELF, _start); int detected = 0; for (i=0; i<(*_num_iterations); i++) { // push input sequence through synchronizer detected ^= qdetector_cccf_execute(q, x[0]) != NULL; detected ^= qdetector_cccf_execute(q, x[1]) != NULL; detected ^= qdetector_cccf_execute(q, x[2]) != NULL; detected ^= qdetector_cccf_execute(q, x[3]) != NULL; detected ^= qdetector_cccf_execute(q, x[4]) != NULL; detected ^= qdetector_cccf_execute(q, x[5]) != NULL; detected ^= qdetector_cccf_execute(q, x[6]) != NULL; } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 7; // clean up allocated objects qdetector_cccf_destroy(q); }
int main(int argc, char*argv[]) { // options unsigned int sequence_len = 80; // number of sync symbols unsigned int k = 2; // samples/symbol unsigned int m = 7; // filter delay [symbols] float beta = 0.3f; // excess bandwidth factor int ftype = LIQUID_FIRFILT_ARKAISER; float gamma = 10.0f; // channel gain float tau = -0.3f; // fractional sample timing offset float dphi = -0.01f; // carrier frequency offset float phi = 0.5f; // carrier phase offset float SNRdB = 20.0f; // signal-to-noise ratio [dB] float threshold = 0.5f; // detection threshold int dopt; while ((dopt = getopt(argc,argv,"hn:k:m:b:F:T:S:t:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'n': sequence_len = atoi(optarg); break; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'b': beta = atof(optarg); break; case 'F': dphi = atof(optarg); break; case 'T': tau = atof(optarg); break; case 'S': SNRdB = atof(optarg); break; case 't': threshold = atof(optarg); break; default: exit(1); } } unsigned int i; // validate input if (tau < -0.5f || tau > 0.5f) { fprintf(stderr,"error: %s, fractional sample offset must be in [-0.5,0.5]\n", argv[0]); exit(1); } // generate synchronization sequence (QPSK symbols) float complex sequence[sequence_len]; for (i=0; i<sequence_len; i++) { sequence[i] = (rand() % 2 ? 1.0f : -1.0f) * M_SQRT1_2 + (rand() % 2 ? 1.0f : -1.0f) * M_SQRT1_2 * _Complex_I; } // float tau_hat = 0.0f; float gamma_hat = 0.0f; float dphi_hat = 0.0f; float phi_hat = 0.0f; int frame_detected = 0; // create detector qdetector_cccf q = qdetector_cccf_create_linear(sequence, sequence_len, ftype, k, m, beta); qdetector_cccf_set_threshold(q, threshold); qdetector_cccf_print(q); // unsigned int seq_len = qdetector_cccf_get_seq_len(q); unsigned int buf_len = qdetector_cccf_get_buf_len(q); unsigned int num_samples = 2*buf_len; // double buffer length to ensure detection unsigned int num_symbols = buf_len; // arrays float complex y[num_samples]; // received signal float complex syms_rx[num_symbols]; // recovered symbols // get pointer to sequence and generate full sequence float complex * v = (float complex*) qdetector_cccf_get_sequence(q); unsigned int filter_delay = 15; firfilt_crcf filter = firfilt_crcf_create_kaiser(2*filter_delay+1, 0.4f, 60.0f, -tau); float nstd = 0.1f; for (i=0; i<num_samples; i++) { // add delay firfilt_crcf_push(filter, i < seq_len ? v[i] : 0); firfilt_crcf_execute(filter, &y[i]); // channel gain y[i] *= gamma; // carrier offset y[i] *= cexpf(_Complex_I*(dphi*i + phi)); // noise y[i] += nstd*(randnf() + _Complex_I*randnf())*M_SQRT1_2; } firfilt_crcf_destroy(filter); // run detection on sequence for (i=0; i<num_samples; i++) { v = qdetector_cccf_execute(q,y[i]); if (v != NULL) { printf("\nframe detected!\n"); frame_detected = 1; // get statistics tau_hat = qdetector_cccf_get_tau(q); gamma_hat = qdetector_cccf_get_gamma(q); dphi_hat = qdetector_cccf_get_dphi(q); phi_hat = qdetector_cccf_get_phi(q); break; } } unsigned int num_syms_rx = 0; // output symbol counter unsigned int counter = 0; // decimation counter if (frame_detected) { // recover symbols firfilt_crcf mf = firfilt_crcf_create_rnyquist(ftype, k, m, beta, tau_hat); firfilt_crcf_set_scale(mf, 1.0f / (float)(k*gamma_hat)); nco_crcf nco = nco_crcf_create(LIQUID_VCO); nco_crcf_set_frequency(nco, dphi_hat); nco_crcf_set_phase (nco, phi_hat); for (i=0; i<buf_len; i++) { // float complex sample; nco_crcf_mix_down(nco, v[i], &sample); nco_crcf_step(nco); // apply decimator firfilt_crcf_push(mf, sample); counter++; if (counter == k-1) firfilt_crcf_execute(mf, &syms_rx[num_syms_rx++]); counter %= k; } nco_crcf_destroy(nco); firfilt_crcf_destroy(mf); } // destroy objects qdetector_cccf_destroy(q); // print results printf("\n"); printf("frame detected : %s\n", frame_detected ? "yes" : "no"); printf(" gamma hat : %8.3f, actual=%8.3f (error=%8.3f)\n", gamma_hat, gamma, gamma_hat - gamma); printf(" tau hat : %8.3f, actual=%8.3f (error=%8.3f) samples\n", tau_hat, tau, tau_hat - tau ); printf(" dphi hat : %8.5f, actual=%8.5f (error=%8.5f) rad/sample\n", dphi_hat, dphi, dphi_hat - dphi ); printf(" phi hat : %8.5f, actual=%8.5f (error=%8.5f) radians\n", phi_hat, phi, phi_hat - phi ); printf(" symbols rx : %u\n", num_syms_rx); 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,"sequence_len= %u;\n", sequence_len); fprintf(fid,"num_samples = %u;\n", num_samples); fprintf(fid,"y = zeros(1,num_samples);\n"); for (i=0; i<num_samples; i++) fprintf(fid,"y(%4u) = %12.8f + j*%12.8f;\n", i+1, crealf(y[i]), cimagf(y[i])); fprintf(fid,"num_syms_rx = %u;\n", num_syms_rx); fprintf(fid,"syms_rx = zeros(1,num_syms_rx);\n"); for (i=0; i<num_syms_rx; i++) fprintf(fid,"syms_rx(%4u) = %12.8f + j*%12.8f;\n", i+1, crealf(syms_rx[i]), cimagf(syms_rx[i])); fprintf(fid,"t=[0:(num_samples-1)];\n"); fprintf(fid,"figure;\n"); fprintf(fid,"subplot(4,1,1);\n"); fprintf(fid," plot(t,real(y), t,imag(y));\n"); fprintf(fid," grid on;\n"); fprintf(fid," xlabel('time');\n"); fprintf(fid," ylabel('received signal');\n"); fprintf(fid,"subplot(4,1,2:4);\n"); fprintf(fid," plot(real(syms_rx), imag(syms_rx), 'x');\n"); fprintf(fid," axis([-1 1 -1 1]*1.5);\n"); fprintf(fid," axis square;\n"); fprintf(fid," grid on;\n"); fprintf(fid," xlabel('real');\n"); fprintf(fid," ylabel('imag');\n"); fclose(fid); printf("results written to '%s'\n", OUTPUT_FILENAME); 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; q->m = 7; // filter delay (symbols) q->beta = 0.3f; // excess bandwidth factor unsigned int i; // generate p/n sequence q->preamble_pn = (float complex*) malloc(64*sizeof(float complex)); q->preamble_rx = (float complex*) malloc(64*sizeof(float complex)); msequence ms = msequence_create(7, 0x0089, 1); for (i=0; i<64; i++) { q->preamble_pn[i] = (msequence_advance(ms) ? M_SQRT1_2 : -M_SQRT1_2) + (msequence_advance(ms) ? M_SQRT1_2 : -M_SQRT1_2)*_Complex_I; } msequence_destroy(ms); // create frame detector unsigned int k = 2; // samples/symbol q->detector = qdetector_cccf_create_linear(q->preamble_pn, 64, LIQUID_FIRFILT_ARKAISER, k, q->m, q->beta); qdetector_cccf_set_threshold(q->detector, 0.5f); // 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,k,q->m,q->beta); #if FLEXFRAMESYNC_ENABLE_EQ // create equalizer unsigned int p = 3; q->equalizer = eqlms_cccf_create_lowpass(2*k*p+1, 0.4f); eqlms_cccf_set_bw(q->equalizer, 0.05f); #endif // create down-coverters for carrier phase tracking q->mixer = nco_crcf_create(LIQUID_NCO); q->pll = nco_crcf_create(LIQUID_NCO); nco_crcf_pll_set_bandwidth(q->pll, 1e-4f); // very low bandwidth // header demodulator/decoder q->header_dec = (unsigned char *) malloc(FLEXFRAME_H_DEC*sizeof(unsigned char)); q->header_decoder = qpacketmodem_create(); qpacketmodem_configure(q->header_decoder, FLEXFRAME_H_DEC, FLEXFRAME_H_CRC, FLEXFRAME_H_FEC0, FLEXFRAME_H_FEC1, LIQUID_MODEM_QPSK); q->header_mod_len = qpacketmodem_get_frame_len(q->header_decoder); q->header_mod = (float complex*) malloc(q->header_mod_len*sizeof(float complex)); // header pilot synchronizer q->header_pilotsync = qpilotsync_create(q->header_mod_len, 16); q->header_sym_len = qpilotsync_get_frame_len(q->header_pilotsync); q->header_sym = (float complex*) malloc(q->header_sym_len*sizeof(float complex)); // payload demodulator for phase recovery q->payload_demod = modem_create(LIQUID_MODEM_QPSK); // create payload demodulator/decoder object q->payload_dec_len = 64; int check = LIQUID_CRC_24; int fec0 = LIQUID_FEC_NONE; int fec1 = LIQUID_FEC_GOLAY2412; int mod_scheme = LIQUID_MODEM_QPSK; q->payload_decoder = qpacketmodem_create(); qpacketmodem_configure(q->payload_decoder, q->payload_dec_len, check, fec0, fec1, mod_scheme); //qpacketmodem_print(q->payload_decoder); //assert( qpacketmodem_get_frame_len(q->payload_decoder)==600 ); q->payload_sym_len = qpacketmodem_get_frame_len(q->payload_decoder); // allocate memory for payload symbols and recovered data bytes q->payload_sym = (float complex*) malloc(q->payload_sym_len*sizeof(float complex)); q->payload_dec = (unsigned char*) malloc(q->payload_dec_len*sizeof(unsigned char)); // reset global data counters flexframesync_reset_framedatastats(q); #if DEBUG_FLEXFRAMESYNC // set debugging flags, objects to NULL q->debug_enabled = 0; q->debug_objects_created = 0; q->debug_qdetector_flush = 0; q->debug_x = NULL; #endif // reset state and return flexframesync_reset(q); return q; }