// push buffered p/n sequence through synchronizer void flexframesync_pushpn(flexframesync _q) { unsigned int i; // reset filterbanks firpfb_crcf_reset(_q->mf); firpfb_crcf_reset(_q->dmf); // read buffer float complex * rc; windowcf_read(_q->buffer, &rc); // compute delay and filterbank index // tau_hat < 0 : delay = 2*k*m-1, index = round( tau_hat *npfb), flag = 0 // tau_hat > 0 : delay = 2*k*m-2, index = round((1-tau_hat)*npfb), flag = 0 assert(_q->tau_hat < 0.5f && _q->tau_hat > -0.5f); unsigned int delay = 2*_q->k*_q->m - 1; // samples to buffer before computing output _q->pfb_soft = -_q->tau_hat*_q->npfb; _q->pfb_index = (int) roundf(_q->pfb_soft); while (_q->pfb_index < 0) { delay -= 1; _q->pfb_index += _q->npfb; _q->pfb_soft += _q->npfb; } _q->pfb_timer = 0; // set coarse carrier frequency offset nco_crcf_set_frequency(_q->nco_coarse, _q->dphi_hat); unsigned int buffer_len = (64+_q->m)*_q->k; for (i=0; i<buffer_len; i++) { if (i < delay) { float complex y; nco_crcf_mix_down(_q->nco_coarse, rc[i]*0.5f/_q->gamma_hat, &y); nco_crcf_step(_q->nco_coarse); // push initial samples into filterbanks firpfb_crcf_push(_q->mf, y); firpfb_crcf_push(_q->dmf, y); } else { // run remaining samples through p/n sequence recovery flexframesync_execute_rxpn(_q, rc[i]); } } // set state (still need a few more samples before entire p/n // sequence has been received) _q->state = STATE_RXPN; }
// step receiver mixer, matched filter, decimator // _q : frame synchronizer // _x : input sample // _y : output symbol int flexframesync_step(flexframesync _q, float complex _x, float complex * _y) { // mix sample down float complex v; nco_crcf_mix_down(_q->mixer, _x, &v); nco_crcf_step (_q->mixer); // push sample into filterbank firpfb_crcf_push (_q->mf, v); firpfb_crcf_execute(_q->mf, _q->pfb_index, &v); #if FLEXFRAMESYNC_ENABLE_EQ // push sample through equalizer eqlms_cccf_push(_q->equalizer, v); #endif // increment counter to determine if sample is available _q->mf_counter++; int sample_available = (_q->mf_counter >= 1) ? 1 : 0; // set output sample if available if (sample_available) { #if FLEXFRAMESYNC_ENABLE_EQ // compute equalizer output eqlms_cccf_execute(_q->equalizer, &v); #endif // set output *_y = v; // decrement counter by k=2 samples/symbol _q->mf_counter -= 2; } // return flag return sample_available; }
// update symbol synchronizer internal state (filtered error, index, etc.) // _q : frame synchronizer // _x : input sample // _y : output symbol int flexframesync_update_symsync(flexframesync _q, float complex _x, float complex * _y) { // push sample into filterbanks firpfb_crcf_push(_q->mf, _x); firpfb_crcf_push(_q->dmf, _x); // float complex mf_out = 0.0f; // matched-filter output float complex dmf_out = 0.0f; // derivatived matched-filter output int sample_available = 0; // compute output if timeout if (_q->pfb_timer <= 0) { sample_available = 1; // reset timer _q->pfb_timer = 2; // k samples/symbol firpfb_crcf_execute(_q->mf, _q->pfb_index, &mf_out); firpfb_crcf_execute(_q->dmf, _q->pfb_index, &dmf_out); // update filtered timing error // hi bandwidth parameters: {0.92, 1.20}, about 100 symbols settling time // med bandwidth parameters: {0.98, 0.20}, about 200 symbols settling time // lo bandwidth parameters: {0.99, 0.05}, about 500 symbols settling time _q->pfb_q = 0.99f*_q->pfb_q + 0.05f*crealf( conjf(mf_out)*dmf_out ); // accumulate error into soft filterbank value _q->pfb_soft += _q->pfb_q; // compute actual filterbank index _q->pfb_index = roundf(_q->pfb_soft); // contrain index to be in [0, npfb-1] while (_q->pfb_index < 0) { _q->pfb_index += _q->npfb; _q->pfb_soft += _q->npfb; // adjust pfb output timer _q->pfb_timer--; } while (_q->pfb_index > _q->npfb-1) { _q->pfb_index -= _q->npfb; _q->pfb_soft -= _q->npfb; // adjust pfb output timer _q->pfb_timer++; } } // decrement symbol timer _q->pfb_timer--; // set output and return *_y = mf_out; return sample_available; }