// frame detection void ofdmframesync_execute_S0a(ofdmframesync _q) { //printf("t : %u\n", _q->timer); _q->timer++; if (_q->timer < _q->M2) return; // reset timer _q->timer = 0; // float complex * rc; windowcf_read(_q->input_buffer, &rc); // TODO : re-estimate nominal gain // estimate S0 gain ofdmframesync_estimate_gain_S0(_q, &rc[_q->cp_len], _q->G0); float complex s_hat; ofdmframesync_S0_metrics(_q, _q->G0, &s_hat); s_hat *= _q->g0; _q->s_hat_0 = s_hat; #if DEBUG_OFDMFRAMESYNC_PRINT float tau_hat = cargf(s_hat) * (float)(_q->M2) / (2*M_PI); printf("********** S0[0] received ************\n"); printf(" s_hat : %12.8f <%12.8f>\n", cabsf(s_hat), cargf(s_hat)); printf(" tau_hat : %12.8f\n", tau_hat); #endif #if 0 // TODO : also check for phase of s_hat (should be small) if (cabsf(s_hat) < 0.3f) { // false alarm #if DEBUG_OFDMFRAMESYNC_PRINT printf("false alarm S0[0]\n"); #endif ofdmframesync_reset(_q); return; } #endif _q->state = OFDMFRAMESYNC_STATE_PLCPSHORT1; }
void ofdmflexframesync_reset(ofdmflexframesync _q) { // reset internal state _q->state = OFDMFLEXFRAMESYNC_STATE_HEADER; // reset internal counters _q->symbol_counter=0; _q->header_symbol_index=0; _q->payload_symbol_index=0; _q->payload_buffer_index=0; // reset error vector magnitude estimate _q->evm_hat = 1e-12f; // slight offset to ensure no log(0) // reset framestats object framesyncstats_init_default(&_q->framestats); // reset internal OFDM frame synchronizer object ofdmframesync_reset(_q->fs); }
void ofdmframesync_execute_rxsymbols(ofdmframesync _q) { // wait for timeout _q->timer--; if (_q->timer == 0) { // run fft float complex * rc; windowcf_read(_q->input_buffer, &rc); memmove(_q->x, &rc[_q->cp_len-_q->backoff], (_q->M)*sizeof(float complex)); FFT_EXECUTE(_q->fft); // recover symbol in internal _q->X buffer ofdmframesync_rxsymbol(_q); #if DEBUG_OFDMFRAMESYNC if (_q->debug_enabled) { unsigned int i; for (i=0; i<_q->M; i++) { if (_q->p[i] == OFDMFRAME_SCTYPE_DATA) windowcf_push(_q->debug_framesyms, _q->X[i]); } } #endif // invoke callback if (_q->callback != NULL) { int retval = _q->callback(_q->X, _q->p, _q->M, _q->userdata); if (retval != 0) ofdmframesync_reset(_q); } // reset timer _q->timer = _q->M + _q->cp_len; } }
void ofdmframesync_execute_S1(ofdmframesync _q) { _q->timer--; if (_q->timer > 0) return; // increment number of symbols observed _q->num_symbols++; // run fft float complex * rc; windowcf_read(_q->input_buffer, &rc); // estimate S1 gain // TODO : add backoff in gain estimation ofdmframesync_estimate_gain_S1(_q, &rc[_q->cp_len], _q->G); // compute detector output float complex g_hat = 0.0f; unsigned int i; for (i=0; i<_q->M; i++) { //g_hat += _q->G[(i+1+_q->M)%_q->M]*conjf(_q->G[(i+_q->M)%_q->M]); g_hat += _q->G[(i+1)%_q->M]*conjf(_q->G[i]); } g_hat /= _q->M_S1; // normalize output g_hat *= _q->g0; // rotate by complex phasor relative to timing backoff g_hat *= liquid_cexpjf((float)(_q->backoff)*2.0f*M_PI/(float)(_q->M)); #if DEBUG_OFDMFRAMESYNC_PRINT printf(" g_hat : %12.4f <%12.8f>\n", cabsf(g_hat), cargf(g_hat)); #endif // check conditions for g_hat: // 1. magnitude should be large (near unity) when aligned // 2. phase should be very near zero (time aligned) if (cabsf(g_hat) > _q->plcp_sync_thresh && fabsf(cargf(g_hat)) < 0.1f*M_PI ) { //printf(" acquisition\n"); _q->state = OFDMFRAMESYNC_STATE_RXSYMBOLS; // reset timer _q->timer = _q->M + _q->cp_len + _q->backoff; _q->num_symbols = 0; // normalize gain by subcarriers, apply timing backoff correction float g = (float)(_q->M) / sqrtf(_q->M_pilot + _q->M_data); for (i=0; i<_q->M; i++) { _q->G[i] *= g; // gain due to relative subcarrier allocation _q->G[i] *= _q->B[i]; // timing backoff correction } #if 0 // TODO : choose number of taps more appropriately //unsigned int ntaps = _q->M / 4; unsigned int ntaps = (_q->M < 8) ? 2 : 8; // FIXME : this is by far the most computationally complex part of synchronization ofdmframesync_estimate_eqgain(_q, ntaps); #else unsigned int poly_order = 4; if (poly_order >= _q->M_pilot + _q->M_data) poly_order = _q->M_pilot + _q->M_data - 1; ofdmframesync_estimate_eqgain_poly(_q, poly_order); #endif #if 1 // compute composite gain unsigned int i; for (i=0; i<_q->M; i++) _q->R[i] = _q->B[i] / _q->G[i]; #endif return; #if 0 printf("exiting prematurely\n"); ofdmframesync_destroy(_q); exit(1); #endif } // check if we are stuck searching for the S1 symbol if (_q->num_symbols == 16) { #if DEBUG_OFDMFRAMESYNC_PRINT printf("could not find S1 symbol. bailing...\n"); #endif ofdmframesync_reset(_q); } // 'reset' timer (wait another half symbol) _q->timer = _q->M2; }
// frame detection void ofdmframesync_execute_S0b(ofdmframesync _q) { //printf("t = %u\n", _q->timer); _q->timer++; if (_q->timer < _q->M2) return; // reset timer _q->timer = _q->M + _q->cp_len - _q->backoff; // float complex * rc; windowcf_read(_q->input_buffer, &rc); // estimate S0 gain ofdmframesync_estimate_gain_S0(_q, &rc[_q->cp_len], _q->G1); float complex s_hat; ofdmframesync_S0_metrics(_q, _q->G1, &s_hat); s_hat *= _q->g0; _q->s_hat_1 = s_hat; #if DEBUG_OFDMFRAMESYNC_PRINT float tau_hat = cargf(s_hat) * (float)(_q->M2) / (2*M_PI); printf("********** S0[1] received ************\n"); printf(" s_hat : %12.8f <%12.8f>\n", cabsf(s_hat), cargf(s_hat)); printf(" tau_hat : %12.8f\n", tau_hat); // new timing offset estimate tau_hat = cargf(_q->s_hat_0 + _q->s_hat_1) * (float)(_q->M2) / (2*M_PI); printf(" tau_hat * : %12.8f\n", tau_hat); printf("**********\n"); #endif // re-adjust timer accordingly float tau_prime = cargf(_q->s_hat_0 + _q->s_hat_1) * (float)(_q->M2) / (2*M_PI); _q->timer -= (int)roundf(tau_prime); #if 0 if (cabsf(s_hat) < 0.3f) { #if DEBUG_OFDMFRAMESYNC_PRINT printf("false alarm S0[1]\n"); #endif // false alarm ofdmframesync_reset(_q); return; } #endif float complex g_hat = 0.0f; unsigned int i; for (i=0; i<_q->M; i++) g_hat += _q->G1[i] * conjf(_q->G0[i]); #if 0 // compute carrier frequency offset estimate using freq. domain method float nu_hat = 2.0f * cargf(g_hat) / (float)(_q->M); #else // compute carrier frequency offset estimate using ML method float complex t0 = 0.0f; for (i=0; i<_q->M2; i++) { t0 += conjf(rc[i]) * _q->s0[i] * rc[i+_q->M2] * conjf(_q->s0[i+_q->M2]); } float nu_hat = cargf(t0) / (float)(_q->M2); #endif #if DEBUG_OFDMFRAMESYNC_PRINT printf(" nu_hat : %12.8f\n", nu_hat); #endif // set NCO frequency nco_crcf_set_frequency(_q->nco_rx, nu_hat); _q->state = OFDMFRAMESYNC_STATE_PLCPLONG; }
// create OFDM framing synchronizer object // _M : number of subcarriers, >10 typical // _cp_len : cyclic prefix length // _taper_len : taper length (OFDM symbol overlap) // _p : subcarrier allocation (null, pilot, data), [size: _M x 1] // _callback : user-defined callback function // _userdata : user-defined data pointer ofdmframesync ofdmframesync_create(unsigned int _M, unsigned int _cp_len, unsigned int _taper_len, unsigned char * _p, ofdmframesync_callback _callback, void * _userdata) { ofdmframesync q = (ofdmframesync) malloc(sizeof(struct ofdmframesync_s)); // validate input if (_M < 8) { fprintf(stderr,"warning: ofdmframesync_create(), less than 8 subcarriers\n"); } else if (_M % 2) { fprintf(stderr,"error: ofdmframesync_create(), number of subcarriers must be even\n"); exit(1); } else if (_cp_len > _M) { fprintf(stderr,"error: ofdmframesync_create(), cyclic prefix length cannot exceed number of subcarriers\n"); exit(1); } q->M = _M; q->cp_len = _cp_len; // derived values q->M2 = _M/2; // subcarrier allocation q->p = (unsigned char*) malloc((q->M)*sizeof(unsigned char)); if (_p == NULL) { ofdmframe_init_default_sctype(q->M, q->p); } else { memmove(q->p, _p, q->M*sizeof(unsigned char)); } // validate and count subcarrier allocation ofdmframe_validate_sctype(q->p, q->M, &q->M_null, &q->M_pilot, &q->M_data); if ( (q->M_pilot + q->M_data) == 0) { fprintf(stderr,"error: ofdmframesync_create(), must have at least one enabled subcarrier\n"); exit(1); } else if (q->M_data == 0) { fprintf(stderr,"error: ofdmframesync_create(), must have at least one data subcarriers\n"); exit(1); } else if (q->M_pilot < 2) { fprintf(stderr,"error: ofdmframesync_create(), must have at least two pilot subcarriers\n"); exit(1); } // create transform object q->X = (float complex*) malloc((q->M)*sizeof(float complex)); q->x = (float complex*) malloc((q->M)*sizeof(float complex)); q->fft = FFT_CREATE_PLAN(q->M, q->x, q->X, FFT_DIR_FORWARD, FFT_METHOD); // create input buffer the length of the transform q->input_buffer = windowcf_create(q->M + q->cp_len); // allocate memory for PLCP arrays q->S0 = (float complex*) malloc((q->M)*sizeof(float complex)); q->s0 = (float complex*) malloc((q->M)*sizeof(float complex)); q->S1 = (float complex*) malloc((q->M)*sizeof(float complex)); q->s1 = (float complex*) malloc((q->M)*sizeof(float complex)); ofdmframe_init_S0(q->p, q->M, q->S0, q->s0, &q->M_S0); ofdmframe_init_S1(q->p, q->M, q->S1, q->s1, &q->M_S1); // compute scaling factor q->g_data = sqrtf(q->M) / sqrtf(q->M_pilot + q->M_data); q->g_S0 = sqrtf(q->M) / sqrtf(q->M_S0); q->g_S1 = sqrtf(q->M) / sqrtf(q->M_S1); // gain q->g0 = 1.0f; q->G0 = (float complex*) malloc((q->M)*sizeof(float complex)); q->G1 = (float complex*) malloc((q->M)*sizeof(float complex)); q->G = (float complex*) malloc((q->M)*sizeof(float complex)); q->B = (float complex*) malloc((q->M)*sizeof(float complex)); q->R = (float complex*) malloc((q->M)*sizeof(float complex)); #if 1 memset(q->G0, 0x00, q->M*sizeof(float complex)); memset(q->G1, 0x00, q->M*sizeof(float complex)); memset(q->G , 0x00, q->M*sizeof(float complex)); memset(q->B, 0x00, q->M*sizeof(float complex)); #endif // timing backoff q->backoff = q->cp_len < 2 ? q->cp_len : 2; float phi = (float)(q->backoff)*2.0f*M_PI/(float)(q->M); unsigned int i; for (i=0; i<q->M; i++) q->B[i] = liquid_cexpjf(i*phi); // set callback data q->callback = _callback; q->userdata = _userdata; // // synchronizer objects // // numerically-controlled oscillator q->nco_rx = nco_crcf_create(LIQUID_NCO); // set pilot sequence q->ms_pilot = msequence_create_default(8); #if OFDMFRAMESYNC_ENABLE_SQUELCH // coarse detection q->squelch_threshold = -25.0f; q->squelch_enabled = 0; #endif // reset object ofdmframesync_reset(q); #if DEBUG_OFDMFRAMESYNC q->debug_enabled = 0; q->debug_objects_created = 0; q->debug_x = NULL; q->debug_rssi = NULL; q->debug_framesyms =NULL; q->G_hat = NULL; q->px = NULL; q->py = NULL; q->debug_pilot_0 = NULL; q->debug_pilot_1 = NULL; #endif // return object return q; }