// execute synchronizer, receiving header // _q : frame synchronizer object // _x : input sample // _sym : demodulated symbol void flexframesync_execute_rxheader(flexframesync _q, float complex _x) { // step synchronizer float complex mf_out = 0.0f; int sample_available = flexframesync_step(_q, _x, &mf_out); // compute output if timeout if (sample_available) { // save payload symbols (modem input/output) _q->header_sym[_q->symbol_counter] = mf_out; // increment counter _q->symbol_counter++; if (_q->symbol_counter == _q->header_sym_len) { // decode header flexframesync_decode_header(_q); if (_q->header_valid) { // continue on to decoding payload _q->symbol_counter = 0; _q->state = FLEXFRAMESYNC_STATE_RXPAYLOAD; return; } // update statistics _q->framedatastats.num_frames_detected++; // header invalid: invoke callback if (_q->callback != NULL) { // set framestats internals _q->framesyncstats.evm = 0.0f; //20*log10f(sqrtf(_q->framesyncstats.evm / 600)); _q->framesyncstats.rssi = 20*log10f(_q->gamma_hat); _q->framesyncstats.cfo = nco_crcf_get_frequency(_q->mixer); _q->framesyncstats.framesyms = NULL; _q->framesyncstats.num_framesyms = 0; _q->framesyncstats.mod_scheme = LIQUID_MODEM_UNKNOWN; _q->framesyncstats.mod_bps = 0; _q->framesyncstats.check = LIQUID_CRC_UNKNOWN; _q->framesyncstats.fec0 = LIQUID_FEC_UNKNOWN; _q->framesyncstats.fec1 = LIQUID_FEC_UNKNOWN; // invoke callback method _q->callback(_q->header_dec, _q->header_valid, NULL, // payload 0, // payload length 0, // payload valid, _q->framesyncstats, _q->userdata); } // reset frame synchronizer flexframesync_reset(_q); return; } } }
// execute synchronizer, receiving payload // _q : frame synchronizer object // _x : input sample // _sym : demodulated symbol void flexframesync_execute_rxpayload(flexframesync _q, float complex _x) { // mix signal down float complex y; nco_crcf_mix_down(_q->nco_coarse, _x*0.5f/_q->gamma_hat, &y); nco_crcf_step(_q->nco_coarse); // update symbol synchronizer float complex mf_out = 0.0f; int sample_available = flexframesync_update_symsync(_q, y, &mf_out); // compute output if timeout if (sample_available) { // push through fine-tuned nco nco_crcf_mix_down(_q->nco_fine, mf_out, &mf_out); // save payload symbols for callback (up to 256 values) if (_q->payload_counter < 256) _q->payload_sym[_q->payload_counter] = mf_out; // demodulate unsigned int sym_out = 0; modem_demodulate(_q->demod_payload, mf_out, &sym_out); _q->payload_mod[_q->payload_counter] = (unsigned char)sym_out; // update phase-locked loop and fine-tuned NCO float phase_error = modem_get_demodulator_phase_error(_q->demod_payload); nco_crcf_pll_step(_q->nco_fine, phase_error); nco_crcf_step(_q->nco_fine); // increment counter _q->payload_counter++; if (_q->payload_counter == _q->payload_mod_len) { // decode payload and invoke callback flexframesync_decode_payload(_q); // invoke callback if (_q->callback != NULL) { // set framestats internals _q->framestats.evm = 20*log10f(sqrtf(_q->framestats.evm / FLEXFRAME_H_SYM)); _q->framestats.rssi = 20*log10f(_q->gamma_hat); _q->framestats.cfo = nco_crcf_get_frequency(_q->nco_coarse) + nco_crcf_get_frequency(_q->nco_fine) / 2.0f; //(float)(_q->k); _q->framestats.framesyms = _q->payload_sym; _q->framestats.num_framesyms = _q->payload_mod_len > 256 ? 256 : _q->payload_mod_len; _q->framestats.mod_scheme = _q->ms_payload; _q->framestats.mod_bps = _q->bps_payload; _q->framestats.check = _q->check; _q->framestats.fec0 = _q->fec0; _q->framestats.fec1 = _q->fec1; // invoke callback method _q->callback(_q->header, _q->header_valid, _q->payload_dec, _q->payload_dec_len, _q->payload_valid, _q->framestats, _q->userdata); } // reset frame synchronizer flexframesync_reset(_q); return; } } }
// execute synchronizer, receiving header // _q : frame synchronizer object // _x : input sample void flexframesync_execute_rxheader(flexframesync _q, float complex _x) { // mix signal down float complex y; nco_crcf_mix_down(_q->nco_coarse, _x*0.5f/_q->gamma_hat, &y); nco_crcf_step(_q->nco_coarse); // update symbol synchronizer float complex mf_out = 0.0f; int sample_available = flexframesync_update_symsync(_q, y, &mf_out); // compute output if timeout if (sample_available) { // push through fine-tuned nco nco_crcf_mix_down(_q->nco_fine, mf_out, &mf_out); #if DEBUG_FLEXFRAMESYNC if (_q->debug_enabled) _q->header_sym[_q->header_counter] = mf_out; #endif // demodulate unsigned int sym_out = 0; #if DEMOD_HEADER_SOFT unsigned char bpsk_soft_bit = 0; modem_demodulate_soft(_q->demod_header, mf_out, &sym_out, &bpsk_soft_bit); _q->header_mod[_q->header_counter] = bpsk_soft_bit; #else modem_demodulate(_q->demod_header, mf_out, &sym_out); _q->header_mod[_q->header_counter] = (unsigned char)sym_out; #endif // update phase-locked loop and fine-tuned NCO float phase_error = modem_get_demodulator_phase_error(_q->demod_header); nco_crcf_pll_step(_q->nco_fine, phase_error); nco_crcf_step(_q->nco_fine); // update error vector magnitude float evm = modem_get_demodulator_evm(_q->demod_header); _q->framestats.evm += evm*evm; // increment counter _q->header_counter++; if (_q->header_counter == FLEXFRAME_H_SYM) { // decode header and invoke callback flexframesync_decode_header(_q); // invoke callback if header is invalid if (!_q->header_valid && _q->callback != NULL) { // set framestats internals _q->framestats.evm = 20*log10f(sqrtf(_q->framestats.evm / FLEXFRAME_H_SYM)); _q->framestats.rssi = 20*log10f(_q->gamma_hat); _q->framestats.cfo = nco_crcf_get_frequency(_q->nco_coarse) + nco_crcf_get_frequency(_q->nco_fine) / 2.0f; //(float)(_q->k); _q->framestats.framesyms = NULL; _q->framestats.num_framesyms = 0; _q->framestats.mod_scheme = LIQUID_MODEM_UNKNOWN; _q->framestats.mod_bps = 0; _q->framestats.check = LIQUID_CRC_UNKNOWN; _q->framestats.fec0 = LIQUID_FEC_UNKNOWN; _q->framestats.fec1 = LIQUID_FEC_UNKNOWN; // invoke callback method _q->callback(_q->header, _q->header_valid, NULL, 0, 0, _q->framestats, _q->userdata); } if (!_q->header_valid) { flexframesync_reset(_q); return; } // update state _q->state = STATE_RXPAYLOAD; } } }
// 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; }
// execute synchronizer, receiving payload // _q : frame synchronizer object // _x : input sample // _sym : demodulated symbol void flexframesync_execute_rxpayload(flexframesync _q, float complex _x) { // step synchronizer float complex mf_out = 0.0f; int sample_available = flexframesync_step(_q, _x, &mf_out); // compute output if timeout if (sample_available) { // TODO: clean this up // mix down with fine-tuned oscillator nco_crcf_mix_down(_q->pll, mf_out, &mf_out); // track phase, accumulate error-vector magnitude unsigned int sym; modem_demodulate(_q->payload_demod, mf_out, &sym); float phase_error = modem_get_demodulator_phase_error(_q->payload_demod); float evm = modem_get_demodulator_evm (_q->payload_demod); nco_crcf_pll_step(_q->pll, phase_error); nco_crcf_step(_q->pll); _q->framesyncstats.evm += evm*evm; // save payload symbols (modem input/output) _q->payload_sym[_q->symbol_counter] = mf_out; // increment counter _q->symbol_counter++; if (_q->symbol_counter == _q->payload_sym_len) { // decode payload _q->payload_valid = qpacketmodem_decode(_q->payload_decoder, _q->payload_sym, _q->payload_dec); // update statistics _q->framedatastats.num_frames_detected++; _q->framedatastats.num_headers_valid++; _q->framedatastats.num_payloads_valid += _q->payload_valid; _q->framedatastats.num_bytes_received += _q->payload_dec_len; // invoke callback if (_q->callback != NULL) { // set framestats internals int ms = qpacketmodem_get_modscheme(_q->payload_decoder); _q->framesyncstats.evm = 10*log10f(_q->framesyncstats.evm / (float)_q->payload_sym_len); _q->framesyncstats.rssi = 20*log10f(_q->gamma_hat); _q->framesyncstats.cfo = nco_crcf_get_frequency(_q->mixer); _q->framesyncstats.framesyms = _q->payload_sym; _q->framesyncstats.num_framesyms = _q->payload_sym_len; _q->framesyncstats.mod_scheme = ms; _q->framesyncstats.mod_bps = modulation_types[ms].bps; _q->framesyncstats.check = qpacketmodem_get_crc(_q->payload_decoder); _q->framesyncstats.fec0 = qpacketmodem_get_fec0(_q->payload_decoder); _q->framesyncstats.fec1 = qpacketmodem_get_fec1(_q->payload_decoder); // invoke callback method _q->callback(_q->header_dec, _q->header_valid, _q->payload_dec, _q->payload_dec_len, _q->payload_valid, _q->framesyncstats, _q->userdata); } // reset frame synchronizer flexframesync_reset(_q); return; } } }
// 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; }