// // test phase-locked loop // _type : NCO type (e.g. LIQUID_NCO) // _phase_offset : initial phase offset // _freq_offset : initial frequency offset // _pll_bandwidth : bandwidth of phase-locked loop // _num_iterations : number of iterations to run // _tol : error tolerance void nco_crcf_pll_test(int _type, float _phase_offset, float _freq_offset, float _pll_bandwidth, unsigned int _num_iterations, float _tol) { // objects nco_crcf nco_tx = nco_crcf_create(_type); nco_crcf nco_rx = nco_crcf_create(_type); // initialize objects nco_crcf_set_phase(nco_tx, _phase_offset); nco_crcf_set_frequency(nco_tx, _freq_offset); nco_crcf_pll_set_bandwidth(nco_rx, _pll_bandwidth); // run loop unsigned int i; float phase_error; float complex r, v; for (i=0; i<_num_iterations; i++) { // received complex signal nco_crcf_cexpf(nco_tx,&r); nco_crcf_cexpf(nco_rx,&v); // error estimation phase_error = cargf(r*conjf(v)); // update pll nco_crcf_pll_step(nco_rx, phase_error); // update nco objects nco_crcf_step(nco_tx); nco_crcf_step(nco_rx); } // ensure phase of oscillators is locked float nco_tx_phase = nco_crcf_get_phase(nco_tx); float nco_rx_phase = nco_crcf_get_phase(nco_rx); CONTEND_DELTA(nco_tx_phase, nco_rx_phase, _tol); // ensure frequency of oscillators is locked float nco_tx_freq = nco_crcf_get_frequency(nco_tx); float nco_rx_freq = nco_crcf_get_frequency(nco_rx); CONTEND_DELTA(nco_tx_freq, nco_rx_freq, _tol); // clean it up nco_crcf_destroy(nco_tx); nco_crcf_destroy(nco_rx); }
size_t demodulator_recv(demodulator *d, const sample_t *samples, size_t sample_len, float complex *symbols) { if (!d) { return 0; } if (sample_len % d->opt.samples_per_symbol != 0) { printf("must receive multiple of samples_per_symbol samples"); return 0; } float complex post_mixer[d->opt.samples_per_symbol]; size_t written = 0; for (size_t i = 0; i < sample_len; i += d->opt.samples_per_symbol) { for (size_t j = 0; j < d->opt.samples_per_symbol; j++) { nco_crcf_mix_down(d->nco, samples[i + j], &post_mixer[j]); nco_crcf_step(d->nco); } if (d->decim) { firdecim_crcf_execute(d->decim, &post_mixer[0], &symbols[(i / d->opt.samples_per_symbol)]); symbols[(i / d->opt.samples_per_symbol)] /= d->opt.samples_per_symbol; } else { symbols[i] = post_mixer[0]; } written++; } return written; }
void gmskframesync_execute_rxpreamble(gmskframesync _q, float complex _x) { // validate input if (_q->preamble_counter == _q->preamble_len) { fprintf(stderr,"warning: gmskframesync_execute_rxpn(), p/n buffer already full!\n"); return; } // mix signal down float complex y; nco_crcf_mix_down(_q->nco_coarse, _x, &y); nco_crcf_step(_q->nco_coarse); // update instantanenous frequency estimate gmskframesync_update_fi(_q, y); // update symbol synchronizer float mf_out = 0.0f; int sample_available = gmskframesync_update_symsync(_q, _q->fi_hat, &mf_out); // compute output if timeout if (sample_available) { // save output in p/n symbols buffer _q->preamble_rx[ _q->preamble_counter ] = mf_out / (float)(_q->k); // update counter _q->preamble_counter++; if (_q->preamble_counter == _q->preamble_len) { gmskframesync_syncpn(_q); _q->state = STATE_RXHEADER; } } }
void ampmodem_modulate(ampmodem _q, float _x, float complex *_y) { float complex x_hat = 0.0f; float complex y_hat; if (_q->type == LIQUID_AMPMODEM_DSB) { x_hat = _x; } else { // push through Hilbert transform // LIQUID_AMPMODEM_USB: // LIQUID_AMPMODEM_LSB: conjugate Hilbert transform output firhilbf_r2c_execute(_q->hilbert, _x, &x_hat); if (_q->type == LIQUID_AMPMODEM_LSB) x_hat = conjf(x_hat); } if (_q->suppressed_carrier) y_hat = x_hat; else y_hat = 0.5f*(x_hat + 1.0f); // mix up nco_crcf_mix_up(_q->oscillator, y_hat, _y); nco_crcf_step(_q->oscillator); }
// modulate sample // _q : frequency modulator object // _s : input symbol // _y : output sample array [size: _k x 1] void fskmod_modulate(fskmod _q, unsigned int _s, float complex * _y) { // validate input if (_s >= _q->M) { fprintf(stderr,"warning: fskmod_modulate(), input symbol (%u) exceeds maximum (%u)\n", _s, _q->M); _s = 0; } // compute appropriate frequency float dphi = ((float)_s - _q->M2) * 2 * M_PI * _q->bandwidth / _q->M2; // set frequency appropriately nco_crcf_set_frequency(_q->oscillator, dphi); // generate output tone unsigned int i; for (i=0; i<_q->k; i++) { // compute complex output nco_crcf_cexpf(_q->oscillator, &_y[i]); // step oscillator nco_crcf_step(_q->oscillator); } }
// execute synchronizer, receiving p/n sequence // _q : frame synchronizer object // _x : input sample // _sym : demodulated symbol void flexframesync_execute_rxpn(flexframesync _q, float complex _x) { // validate input if (_q->pn_counter == 64) { fprintf(stderr,"warning: flexframesync_execute_rxpn(), p/n buffer already full!\n"); return; } // 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) { // save output in p/n symbols buffer _q->preamble_rx[ _q->pn_counter ] = mf_out; // update p/n counter _q->pn_counter++; if (_q->pn_counter == 64) { flexframesync_syncpn(_q); _q->state = STATE_RXHEADER; } } }
// // test floating point precision nco // void autotest_nco_basic() { nco_crcf p = nco_crcf_create(LIQUID_NCO); unsigned int i; // loop index float s, c; // sine/cosine result float tol=1e-4f; // error tolerance float f=0.0f; // frequency to test nco_crcf_set_phase( p, 0.0f); CONTEND_DELTA( nco_crcf_cos(p), 1.0f, tol ); CONTEND_DELTA( nco_crcf_sin(p), 0.0f, tol ); nco_crcf_sincos(p, &s, &c); CONTEND_DELTA( s, 0.0f, tol ); CONTEND_DELTA( c, 1.0f, tol ); nco_crcf_set_phase(p, M_PI/2); CONTEND_DELTA( nco_crcf_cos(p), 0.0f, tol ); CONTEND_DELTA( nco_crcf_sin(p), 1.0f, tol ); nco_crcf_sincos(p, &s, &c); CONTEND_DELTA( s, 1.0f, tol ); CONTEND_DELTA( c, 0.0f, tol ); // cycle through one full period in 64 steps nco_crcf_set_phase(p, 0.0f); f = 2.0f * M_PI / 64.0f; nco_crcf_set_frequency(p, f); for (i=0; i<128; i++) { nco_crcf_sincos(p, &s, &c); CONTEND_DELTA( s, sinf(i*f), tol ); CONTEND_DELTA( c, cosf(i*f), tol ); nco_crcf_step(p); } // double frequency: cycle through one full period in 32 steps nco_crcf_set_phase(p, 0.0f); f = 2.0f * M_PI / 32.0f; nco_crcf_set_frequency(p, f); for (i=0; i<128; i++) { nco_crcf_sincos(p, &s, &c); CONTEND_DELTA( s, sinf(i*f), tol ); CONTEND_DELTA( c, cosf(i*f), tol ); nco_crcf_step(p); } // destroy NCO object nco_crcf_destroy(p); }
// execute framing synchronizer on input buffer // _q : framing synchronizer object // _buffer : input buffer [size: _n x 1] // _n : input buffer size void wlanframesync_execute(wlanframesync _q, liquid_float_complex * _buffer, unsigned int _n) { unsigned int i; float complex x; for (i=0; i<_n; i++) { x = _buffer[i]; // correct for carrier frequency offset (only if not in // initial 'seek PLCP' state) if (_q->state != WLANFRAMESYNC_STATE_SEEKPLCP) { nco_crcf_mix_down(_q->nco_rx, x, &x); nco_crcf_step(_q->nco_rx); } // save input sample to buffer windowcf_push(_q->input_buffer,x); #if DEBUG_WLANFRAMESYNC if (_q->debug_enabled) { // apply agc (estimate initial signal gain) float complex y; agc_crcf_execute(_q->agc_rx, x, &y); windowcf_push(_q->debug_x, x); windowf_push(_q->debug_rssi, agc_crcf_get_rssi(_q->agc_rx)); } #endif switch (_q->state) { case WLANFRAMESYNC_STATE_SEEKPLCP: wlanframesync_execute_seekplcp(_q); break; case WLANFRAMESYNC_STATE_RXSHORT0: wlanframesync_execute_rxshort0(_q); break; case WLANFRAMESYNC_STATE_RXSHORT1: wlanframesync_execute_rxshort1(_q); break; case WLANFRAMESYNC_STATE_RXLONG0: wlanframesync_execute_rxlong0(_q); break; case WLANFRAMESYNC_STATE_RXLONG1: wlanframesync_execute_rxlong1(_q); break; case WLANFRAMESYNC_STATE_RXSIGNAL: wlanframesync_execute_rxsignal(_q); break; case WLANFRAMESYNC_STATE_RXDATA: wlanframesync_execute_rxdata(_q); break; default:; // should never get to this point fprintf(stderr,"error: wlanframesync_execute(), invalid state\n"); exit(1); } } // for (i=0; i<_n; i++) }
void PfbSynthesizerComponent::process() { //Get input DataSets std::size_t curSize = 0; vector< DataSet< complex<float> >* > inSets(nChans_x); for(int i=0;i<nChans_x;i++) { stringstream ss; ss << "input"; ss << i; getInputDataSet(ss.str(), inSets[i]); std::size_t s = inSets[i]->data.size(); if(s != curSize && curSize > 0) LOG(LWARNING) << "Input channel sizes do not match."; curSize = s; } //Get output DataSet DataSet< complex<float> >* writeDataSet = NULL; getOutputDataSet("output1", writeDataSet, curSize*nChans_x); writeDataSet->sampleRate = inSets[0]->sampleRate*nChans_x; writeDataSet->timeStamp = inSets[0]->timeStamp; // Execute the synthesizer for(int i=0;i<curSize;i++) { for (int j=0; j<nChans_x; j++) buf[j] = inSets[j]->data[i]; firpfbch_crcf_synthesizer_execute(channelizer, &buf[0], &outBuf[0]); copy(outBuf.begin(), outBuf.end(), writeDataSet->data.begin()+i*nChans_x); } // mix signal down for(int i=0;i<writeDataSet->data.size();i++) { complex<float>* x = &writeDataSet->data[i]; nco_crcf_mix_down(nco, *x, x); nco_crcf_step(nco); } //Release the DataSets for(int i=0;i<nChans_x;i++) { stringstream ss; ss << "input"; ss << i; releaseInputDataSet(ss.str(), inSets[i]); } releaseOutputDataSet("output1", writeDataSet); }
// push buffered p/n sequence through synchronizer void gmskframesync_pushpn(gmskframesync _q) { unsigned int i; // reset filterbanks firpfb_rrrf_reset(_q->mf); firpfb_rrrf_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 = (_q->preamble_len + _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], &y); nco_crcf_step(_q->nco_coarse); // update instantanenous frequency estimate gmskframesync_update_fi(_q, y); // push initial samples into filterbanks firpfb_rrrf_push(_q->mf, _q->fi_hat); firpfb_rrrf_push(_q->dmf, _q->fi_hat); } else { // run remaining samples through p/n sequence recovery gmskframesync_execute_rxpreamble(_q, rc[i]); } } // set state (still need a few more samples before entire p/n // sequence has been received) _q->state = STATE_RXPREAMBLE; }
void ampmodem_demodulate(ampmodem _q, float complex _y, float *_x) { #if DEBUG_AMPMODEM windowcf_push(_q->debug_x, _y); #endif if (_q->suppressed_carrier) { // single side-band suppressed carrier if (_q->type != LIQUID_AMPMODEM_DSB) { *_x = crealf(_y); return; } // coherent demodulation // mix signal down float complex y_hat; nco_crcf_mix_down(_q->oscillator, _y, &y_hat); // compute phase error float phase_error = tanhf( crealf(y_hat) * cimagf(y_hat) ); #if DEBUG_AMPMODEM // compute frequency error float nco_freq = nco_crcf_get_frequency(_q->oscillator); float freq_error = nco_freq/(2*M_PI) - _q->fc/(2*M_PI); // retain phase and frequency errors windowf_push(_q->debug_phase_error, phase_error); windowf_push(_q->debug_freq_error, freq_error); #endif // adjust nco, pll objects nco_crcf_pll_step(_q->oscillator, phase_error); // step NCO nco_crcf_step(_q->oscillator); // set output *_x = crealf(y_hat); } else { // non-coherent demodulation (peak detector) float t = cabsf(_y); // remove DC bias _q->ssb_q_hat = ( _q->ssb_alpha)*t + (1 - _q->ssb_alpha)*_q->ssb_q_hat; *_x = 2.0f*(t - _q->ssb_q_hat); } }
void ofdmframesync_execute(ofdmframesync _q, float complex * _x, unsigned int _n) { unsigned int i; float complex x; for (i=0; i<_n; i++) { x = _x[i]; // correct for carrier frequency offset if (_q->state != OFDMFRAMESYNC_STATE_SEEKPLCP) { nco_crcf_mix_down(_q->nco_rx, x, &x); nco_crcf_step(_q->nco_rx); } // save input sample to buffer windowcf_push(_q->input_buffer,x); #if DEBUG_OFDMFRAMESYNC if (_q->debug_enabled) { windowcf_push(_q->debug_x, x); windowf_push(_q->debug_rssi, crealf(x)*crealf(x) + cimagf(x)*cimagf(x)); } #endif switch (_q->state) { case OFDMFRAMESYNC_STATE_SEEKPLCP: ofdmframesync_execute_seekplcp(_q); break; case OFDMFRAMESYNC_STATE_PLCPSHORT0: ofdmframesync_execute_S0a(_q); break; case OFDMFRAMESYNC_STATE_PLCPSHORT1: ofdmframesync_execute_S0b(_q); break; case OFDMFRAMESYNC_STATE_PLCPLONG: ofdmframesync_execute_S1(_q); break; case OFDMFRAMESYNC_STATE_RXSYMBOLS: ofdmframesync_execute_rxsymbols(_q); break; default:; } } // for (i=0; i<_n; i++) } // ofdmframesync_execute()
// once p/n symbols are buffered, estimate residual carrier // frequency and phase offsets, push through fine-tuned NCO void flexframesync_syncpn(flexframesync _q) { unsigned int i; // estimate residual carrier frequency offset from p/n symbols float complex dphi_metric = 0.0f; float complex r0 = 0.0f; float complex r1 = 0.0f; for (i=0; i<64; i++) { r0 = r1; r1 = _q->preamble_rx[i]*_q->preamble_pn[i]; dphi_metric += r1 * conjf(r0); } float dphi_hat = cargf(dphi_metric); // estimate carrier phase offset from p/n symbols float complex theta_metric = 0.0f; for (i=0; i<64; i++) theta_metric += _q->preamble_rx[i]*liquid_cexpjf(-dphi_hat*i)*_q->preamble_pn[i]; float theta_hat = cargf(theta_metric); // TODO: compute gain correction factor // initialize fine-tuned nco nco_crcf_set_frequency(_q->nco_fine, dphi_hat); nco_crcf_set_phase( _q->nco_fine, theta_hat); // correct for carrier offset, pushing through phase-locked loop for (i=0; i<64; i++) { // mix signal down nco_crcf_mix_down(_q->nco_fine, _q->preamble_rx[i], &_q->preamble_rx[i]); // push through phase-locked loop float phase_error = cimagf(_q->preamble_rx[i]*_q->preamble_pn[i]); nco_crcf_pll_step(_q->nco_fine, phase_error); #if DEBUG_FLEXFRAMESYNC //_q->debug_nco_phase[i] = nco_crcf_get_phase(_q->nco_fine); #endif // update nco phase nco_crcf_step(_q->nco_fine); } }
int main() { // create the NCO object nco_crcf p = nco_crcf_create(LIQUID_NCO); nco_crcf_set_phase(p, 0.0f); nco_crcf_set_frequency(p, M_PI/10); unsigned int i; float s, c; for (i=0; i<11; i++) { nco_crcf_sincos(p, &s, &c); printf(" %3u : %8.5f + j %8.5f\n", i, c, s); nco_crcf_step(p); } // clean up allocated memory nco_crcf_destroy(p); printf("done.\n"); return 0; }
// 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; }
// // test nco mixing // void autotest_nco_mixing() { // frequency, phase float f = 0.1f; float phi = M_PI; // error tolerance (high for NCO) float tol = 0.05f; // initialize nco object nco_crcf p = nco_crcf_create(LIQUID_NCO); nco_crcf_set_frequency(p, f); nco_crcf_set_phase(p, phi); unsigned int i; float nco_i, nco_q; for (i=0; i<64; i++) { // generate sin/cos nco_crcf_sincos(p, &nco_q, &nco_i); // mix back to zero phase complex float nco_cplx_in = nco_i + _Complex_I*nco_q; complex float nco_cplx_out; nco_crcf_mix_down(p, nco_cplx_in, &nco_cplx_out); // assert mixer output is correct CONTEND_DELTA(crealf(nco_cplx_out), 1.0f, tol); CONTEND_DELTA(cimagf(nco_cplx_out), 0.0f, tol); //printf("%3u : %12.8f + j*%12.8f\n", i, crealf(nco_cplx_out), cimagf(nco_cplx_out)); // step nco nco_crcf_step(p); } // destroy NCO object nco_crcf_destroy(p); }
// 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; } } }
int main() { // spectral periodogram options unsigned int nfft=256; // spectral periodogram FFT size unsigned int num_samples = 2001; // number of samples float beta = 10.0f; // Kaiser-Bessel window parameter // allocate memory for data arrays float complex x[num_samples]; // input signal float complex X[nfft]; // output spectrum float psd[nfft]; // power spectral density unsigned int ramp = num_samples/20 < 10 ? 10 : num_samples/20; // 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); unsigned int i; // generate signal nco_crcf nco = nco_crcf_create(LIQUID_VCO); for (i=0; i<num_samples; i++) { nco_crcf_set_frequency(nco, 0.1f*(1.2f+sinf(0.007f*i)) ); nco_crcf_cexpf(nco, &x[i]); nco_crcf_step(nco); } nco_crcf_destroy(nco); // add soft ramping functions for (i=0; i<ramp; i++) { x[i] *= 0.5f - 0.5f*cosf(M_PI*(float)i / (float)ramp); x[num_samples-ramp+i-1] *= 0.5f - 0.5f*cosf(M_PI*(float)(ramp-i-1) / (float)ramp); } // // export output file(s) // FILE * fid; // // export time-doman data // fid = fopen(OUTPUT_FILENAME_TIME,"w"); fprintf(fid,"# %s : auto-generated file\n", OUTPUT_FILENAME_TIME); for (i=0; i<num_samples; i++) fprintf(fid,"%12u %12.8f %12.8f\n", i, crealf(x[i]), cimagf(x[i])); fclose(fid); printf("results written to %s.\n", OUTPUT_FILENAME_TIME); // // export freq-doman data // fid = fopen(OUTPUT_FILENAME_FREQ,"w"); fprintf(fid,"# %s : auto-generated file\n", OUTPUT_FILENAME_FREQ); unsigned int t=0; for (i=0; i<num_samples; i++) { // push sample into periodogram spgram_push(q, &x[i], 1); if ( ((i+1)%delay)==0 ) { // compute spectral periodogram output spgram_execute(q, X); unsigned int k; // compute PSD and FFT shift for (k=0; k<nfft; k++) psd[k] = 20*log10f( cabsf(X[(k+nfft/2)%nfft]) ); #if 1 for (k=0; k<nfft; k++) fprintf(fid,"%12u %12.8f %12.8f\n", t, (float)k/(float)nfft - 0.5f, psd[k]); #else for (k=0; k<nfft; k++) fprintf(fid,"%12.8f ", psd[k]); #endif fprintf(fid,"\n"); t++; } } // destroy spectral periodogram object spgram_destroy(q); fclose(fid); printf("results written to %s.\n", OUTPUT_FILENAME_FREQ); printf("done.\n"); return 0; }
void gmskframesync_execute_rxpayload(gmskframesync _q, float complex _x) { // mix signal down float complex y; nco_crcf_mix_down(_q->nco_coarse, _x, &y); nco_crcf_step(_q->nco_coarse); // update instantanenous frequency estimate gmskframesync_update_fi(_q, y); // update symbol synchronizer float mf_out = 0.0f; int sample_available = gmskframesync_update_symsync(_q, _q->fi_hat, &mf_out); // compute output if timeout if (sample_available) { // demodulate unsigned char s = mf_out > 0.0f ? 1 : 0; // TODO: update evm // save payload _q->payload_byte <<= 1; _q->payload_byte |= s ? 0x01 : 0x00; _q->payload_enc[_q->payload_counter/8] = _q->payload_byte; // increment counter _q->payload_counter++; if (_q->payload_counter == 8*_q->payload_enc_len) { // decode payload _q->payload_valid = packetizer_decode(_q->p_payload, _q->payload_enc, _q->payload_dec); // invoke callback if (_q->callback != NULL) { // set framestats internals _q->framestats.rssi = 20*log10f(_q->gamma_hat); _q->framestats.evm = 0.0f; _q->framestats.framesyms = NULL; _q->framestats.num_framesyms = 0; _q->framestats.mod_scheme = LIQUID_MODEM_UNKNOWN; _q->framestats.mod_bps = 1; _q->framestats.check = _q->check; _q->framestats.fec0 = _q->fec0; _q->framestats.fec1 = _q->fec1; // invoke callback method _q->callback(_q->header_dec, _q->header_valid, _q->payload_dec, _q->payload_dec_len, _q->payload_valid, _q->framestats, _q->userdata); } // reset frame synchronizer gmskframesync_reset(_q); } } }
void gmskframesync_execute_rxheader(gmskframesync _q, float complex _x) { // mix signal down float complex y; nco_crcf_mix_down(_q->nco_coarse, _x, &y); nco_crcf_step(_q->nco_coarse); // update instantanenous frequency estimate gmskframesync_update_fi(_q, y); // update symbol synchronizer float mf_out = 0.0f; int sample_available = gmskframesync_update_symsync(_q, _q->fi_hat, &mf_out); // compute output if timeout if (sample_available) { // demodulate unsigned char s = mf_out > 0.0f ? 1 : 0; // TODO: update evm // save bit in buffer _q->header_mod[_q->header_counter] = s; // increment header counter _q->header_counter++; if (_q->header_counter == GMSKFRAME_H_SYM) { // decode header gmskframesync_decode_header(_q); // invoke callback if header is invalid if (!_q->header_valid && _q->callback != NULL) { // set framestats internals _q->framestats.rssi = 20*log10f(_q->gamma_hat); _q->framestats.evm = 0.0f; _q->framestats.framesyms = NULL; _q->framestats.num_framesyms = 0; _q->framestats.mod_scheme = LIQUID_MODEM_UNKNOWN; _q->framestats.mod_bps = 1; _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_dec, _q->header_valid, NULL, 0, 0, _q->framestats, _q->userdata); gmskframesync_reset(_q); } // reset if invalid if (!_q->header_valid) { gmskframesync_reset(_q); return; } // update state _q->state = STATE_RXPAYLOAD; } } }
int main(int argc, char*argv[]) { srand(time(NULL)); // options unsigned int M = 64; // number of subcarriers unsigned int cp_len = 16; // cyclic prefix length unsigned int taper_len = 4; // taper length unsigned int payload_len = 120; // length of payload (bytes) modulation_scheme ms = LIQUID_MODEM_QPSK; fec_scheme fec0 = LIQUID_FEC_NONE; fec_scheme fec1 = LIQUID_FEC_HAMMING128; crc_scheme check = LIQUID_CRC_32; float noise_floor = -30.0f; // noise floor [dB] float SNRdB = 20.0f; // signal-to-noise ratio [dB] float dphi = 0.02f; // carrier frequency offset int debug_enabled = 0; // enable debugging? // get options int dopt; while((dopt = getopt(argc,argv,"uhds:F:M:C:n:m:v:c:k:")) != EOF){ switch (dopt) { case 'u': case 'h': usage(); return 0; case 'd': debug_enabled = 1; break; case 's': SNRdB = atof(optarg); break; case 'F': dphi = atof(optarg); break; case 'M': M = atoi(optarg); break; case 'C': cp_len = atoi(optarg); break; case 'n': payload_len = atol(optarg); break; case 'm': ms = liquid_getopt_str2mod(optarg); if (ms == LIQUID_MODEM_UNKNOWN) { fprintf(stderr,"error: %s, unknown/unsupported mod. scheme: %s\n", argv[0], optarg); exit(-1); } break; case 'v': // data integrity check check = liquid_getopt_str2crc(optarg); if (check == LIQUID_CRC_UNKNOWN) { fprintf(stderr,"error: unknown/unsupported CRC scheme \"%s\"\n\n",optarg); exit(1); } break; case 'c': // inner FEC scheme fec0 = liquid_getopt_str2fec(optarg); if (fec0 == LIQUID_FEC_UNKNOWN) { fprintf(stderr,"error: unknown/unsupported inner FEC scheme \"%s\"\n\n",optarg); exit(1); } break; case 'k': // outer FEC scheme fec1 = liquid_getopt_str2fec(optarg); if (fec1 == LIQUID_FEC_UNKNOWN) { fprintf(stderr,"error: unknown/unsupported outer FEC scheme \"%s\"\n\n",optarg); exit(1); } break; default: exit(-1); } } unsigned int i; // TODO : validate options // derived values unsigned int frame_len = M + cp_len; float complex buffer[frame_len]; // time-domain buffer float nstd = powf(10.0f, noise_floor/20.0f); float gamma = powf(10.0f, (SNRdB + noise_floor)/20.0f); // allocate memory for header, payload unsigned char header[8]; unsigned char payload[payload_len]; // initialize subcarrier allocation unsigned char p[M]; ofdmframe_init_default_sctype(M, p); // create frame generator ofdmflexframegenprops_s fgprops; ofdmflexframegenprops_init_default(&fgprops); fgprops.check = check; fgprops.fec0 = fec0; fgprops.fec1 = fec1; fgprops.mod_scheme = ms; ofdmflexframegen fg = ofdmflexframegen_create(M, cp_len, taper_len, p, &fgprops); // create frame synchronizer ofdmflexframesync fs = ofdmflexframesync_create(M, cp_len, taper_len, p, callback, (void*)payload); if (debug_enabled) ofdmflexframesync_debug_enable(fs); // initialize header/payload and assemble frame for (i=0; i<8; i++) header[i] = i & 0xff; for (i=0; i<payload_len; i++) payload[i] = rand() & 0xff; ofdmflexframegen_assemble(fg, header, payload, payload_len); ofdmflexframegen_print(fg); ofdmflexframesync_print(fs); // initialize frame synchronizer with noise for (i=0; i<1000; i++) { float complex noise = nstd*( randnf() + _Complex_I*randnf())*M_SQRT1_2; ofdmflexframesync_execute(fs, &noise, 1); } // generate frame, push through channel int last_symbol=0; nco_crcf nco = nco_crcf_create(LIQUID_VCO); nco_crcf_set_frequency(nco, dphi); while (!last_symbol) { // generate symbol last_symbol = ofdmflexframegen_writesymbol(fg, buffer); // apply channel for (i=0; i<frame_len; i++) { float complex noise = nstd*( randnf() + _Complex_I*randnf())*M_SQRT1_2; buffer[i] *= gamma; buffer[i] += noise; nco_crcf_mix_up(nco, buffer[i], &buffer[i]); nco_crcf_step(nco); } // receive symbol ofdmflexframesync_execute(fs, buffer, frame_len); } nco_crcf_destroy(nco); // export debugging file if (debug_enabled) ofdmflexframesync_debug_print(fs, "ofdmflexframesync_debug.m"); // destroy objects ofdmflexframegen_destroy(fg); ofdmflexframesync_destroy(fs); printf("done.\n"); return 0; }
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; }
void ofdmoqamframe64sync_rxpayload(ofdmoqamframe64sync _q, float complex * _Y0, float complex * _Y1) { unsigned int j=0; unsigned int t=0; int sctype; unsigned int pilot_phase = msequence_advance(_q->ms_pilot); // gain correction (equalizer) unsigned int i; for (i=0; i<_q->num_subcarriers; i++) { _Y0[i] *= _q->G[i];// * _q->zeta; _Y1[i] *= _q->G[i];// * _q->zeta; } // TODO : extract pilots for (i=0; i<_q->num_subcarriers; i++) { sctype = ofdmoqamframe64_getsctype(i); if (sctype==OFDMOQAMFRAME64_SCTYPE_PILOT) { // pilot subcarrier : use p/n sequence for pilot phase float complex y0 = ((i%2)==0 ? _Y0[i] : _Y1[i]) / _q->zeta; float complex y1 = ((i%2)==0 ? _Y1[i] : _Y0[i]) / _q->zeta; float complex p = (pilot_phase ? 1.0f : -1.0f); float phi_hat = ofdmoqamframe64sync_estimate_pilot_phase(y0,y1,p); _q->y_phase[t] = phi_hat; t++; #if DEBUG_OFDMOQAMFRAME64SYNC_PRINT printf("i = %u\n", i); printf("y0 = %12.8f + j*%12.8f;\n", crealf(y0),cimagf(y0)); printf("y1 = %12.8f + j*%12.8f;\n", crealf(y1),cimagf(y1)); printf("phi_hat = %12.8f\n", phi_hat); #endif /* printf("exiting prematurely\n"); ofdmoqamframe64sync_destroy(_q); exit(1); */ } } assert(t==4); // pilot phase correction /* _q->y_phase[0] = cargf(_q->X[11]); // -21 _q->y_phase[1] = cargf(_q->X[25]); // -7 _q->y_phase[2] = cargf(_q->X[39]); // 7 _q->y_phase[3] = cargf(_q->X[53]); // 21 */ // try to unwrap phase for (i=1; i<4; i++) { while ((_q->y_phase[i] - _q->y_phase[i-1]) > M_PI) _q->y_phase[i] -= 2*M_PI; while ((_q->y_phase[i] - _q->y_phase[i-1]) < -M_PI) _q->y_phase[i] += 2*M_PI; } // fit phase to 1st-order polynomial (2 coefficients) polyf_fit(_q->x_phase, _q->y_phase, 4, _q->p_phase, 2); //nco_crcf_step(_q->nco_pilot); float theta_hat = nco_crcf_get_phase(_q->nco_pilot); float phase_error = _q->p_phase[0] - theta_hat; while (phase_error > M_PI) phase_error -= 2.0f*M_PI; while (phase_error < -M_PI) phase_error += 2.0f*M_PI; pll_step(_q->pll_pilot, _q->nco_pilot, 0.1f*phase_error); #if DEBUG_OFDMOQAMFRAME64SYNC_PRINT // print phase results for (i=0; i<4; i++) { printf("x(%3u) = %12.8f; y(%3u) = %12.8f;\n", i+1, _q->x_phase[i], i+1, _q->y_phase[i]); } printf("p(1) = %12.8f\n", _q->p_phase[0]); printf("p(2) = %12.8f\n", _q->p_phase[1]); #endif #if DEBUG_OFDMOQAMFRAME64SYNC windowf_push(_q->debug_pilotphase, _q->p_phase[0]); windowf_push(_q->debug_pilotphase_hat, theta_hat); #endif // compensate for phase shift due to timing offset float theta; _q->p_phase[0] = theta_hat; _q->p_phase[1] = 0.0f; for (i=0; i<_q->num_subcarriers; i++) { // TODO : compute phase for delayed symbol (different from non-delayed symbol) theta = polyf_val(_q->p_phase, 2, (float)(i)-32.0f); _Y0[i] *= liquid_cexpjf(-theta); _Y1[i] *= liquid_cexpjf(-theta); } nco_crcf_step(_q->nco_pilot); // strip data subcarriers for (i=0; i<_q->num_subcarriers; i++) { sctype = ofdmoqamframe64_getsctype(i); if (sctype==OFDMOQAMFRAME64_SCTYPE_NULL) { // disabled subcarrier } else if (sctype==OFDMOQAMFRAME64_SCTYPE_PILOT) { // pilot subcarrier } else { // data subcarrier if ((i%2)==0) { // even subcarrier _q->data[j] = crealf(_Y0[i]) + cimagf(_Y1[i]) * _Complex_I; } else { // odd subcarrier _q->data[j] = cimagf(_Y0[i]) * _Complex_I + crealf(_Y1[i]); } // scaling factor _q->data[j] /= _q->zeta; j++; } } assert(j==48); #if DEBUG_OFDMOQAMFRAME64SYNC for (i=0; i<48; i++) windowcf_push(_q->debug_framesyms,_q->data[i]); #endif if (_q->callback != NULL) { int retval = _q->callback(_q->data, _q->userdata); if (retval == -1) { printf("exiting prematurely\n"); ofdmoqamframe64sync_destroy(_q); exit(0); } else if (retval == 1) { #if DEBUG_OFDMOQAMFRAME64SYNC_PRINT printf("resetting synchronizer\n"); #endif ofdmoqamframe64sync_reset(_q); } else { // do nothing } } }
void quiet_beacon_encoder_emit(quiet_beacon_encoder *e, quiet_beacon_sample_t *buf, size_t buflen) { for (size_t i = 0; i < buflen; i++) { buf[i] = nco_crcf_cos(e->nco) * e->gain; nco_crcf_step(e->nco); } }
int main(int argc, char*argv[]) { srand( time(NULL) ); // parameters float phase_offset = M_PI/10; float frequency_offset = 0.001f; float SNRdB = 30.0f; float pll_bandwidth = 0.02f; modulation_scheme ms = LIQUID_MODEM_QPSK; unsigned int n=256; // number of iterations int dopt; while ((dopt = getopt(argc,argv,"uhs:b:n:P:F:m:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 's': SNRdB = atof(optarg); break; case 'b': pll_bandwidth = atof(optarg); break; case 'n': n = atoi(optarg); break; case 'P': phase_offset = atof(optarg); break; case 'F': frequency_offset= atof(optarg); break; case 'm': ms = liquid_getopt_str2mod(optarg); if (ms == LIQUID_MODEM_UNKNOWN) { fprintf(stderr,"error: %s, unknown/unsupported modulation scheme \"%s\"\n", argv[0], optarg); return 1; } break; default: exit(1); } } unsigned int d=n/32; // print every "d" lines FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid, "%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid, "clear all;\n"); fprintf(fid, "phi=zeros(1,%u);\n",n); fprintf(fid, "r=zeros(1,%u);\n",n); // objects nco_crcf nco_tx = nco_crcf_create(LIQUID_VCO); nco_crcf nco_rx = nco_crcf_create(LIQUID_VCO); modem mod = modem_create(ms); modem demod = modem_create(ms); unsigned int bps = modem_get_bps(mod); // initialize objects nco_crcf_set_phase(nco_tx, phase_offset); nco_crcf_set_frequency(nco_tx, frequency_offset); nco_crcf_pll_set_bandwidth(nco_rx, pll_bandwidth); float noise_power = powf(10.0f, -SNRdB/20.0f); // print parameters printf("PLL example :\n"); printf("modem : %u-%s\n", 1<<bps, modulation_types[ms].name); printf("frequency offset: %6.3f, phase offset: %6.3f, SNR: %6.2fdB, pll b/w: %6.3f\n", frequency_offset, phase_offset, SNRdB, pll_bandwidth); // run loop unsigned int i, M=1<<bps, sym_in, sym_out, num_errors=0; float phase_error; float complex x, r, v, noise; for (i=0; i<n; i++) { // generate random symbol sym_in = rand() % M; // modulate modem_modulate(mod, sym_in, &x); // channel //r = nco_crcf_cexpf(nco_tx); nco_crcf_mix_up(nco_tx, x, &r); // add complex white noise crandnf(&noise); r += noise * noise_power; // //v = nco_crcf_cexpf(nco_rx); nco_crcf_mix_down(nco_rx, r, &v); // demodulate modem_demodulate(demod, v, &sym_out); num_errors += count_bit_errors(sym_in, sym_out); // error estimation //phase_error = cargf(r*conjf(v)); phase_error = modem_get_demodulator_phase_error(demod); // perfect error estimation //phase_error = nco_tx->theta - nco_rx->theta; // print every line in a format that octave can read fprintf(fid, "phi(%u) = %10.6E;\n", i+1, phase_error); fprintf(fid, "r(%u) = %10.6E + j*%10.6E;\n", i+1, crealf(v), cimagf(v)); if ((i+1)%d == 0 || i==n-1) { printf(" %4u: e_hat : %6.3f, phase error : %6.3f, freq error : %6.3f\n", i+1, // iteration phase_error, // estimated phase error nco_crcf_get_phase(nco_tx) - nco_crcf_get_phase(nco_rx),// true phase error nco_crcf_get_frequency(nco_tx) - nco_crcf_get_frequency(nco_rx)// true frequency error ); } // update tx nco object nco_crcf_step(nco_tx); // update pll nco_crcf_pll_step(nco_rx, phase_error); // update rx nco object nco_crcf_step(nco_rx); } fprintf(fid, "figure;\n"); fprintf(fid, "plot(1:length(phi),phi,'LineWidth',2,'Color',[0 0.25 0.5]);\n"); fprintf(fid, "xlabel('Symbol Index');\n"); fprintf(fid, "ylabel('Phase Error [radians]');\n"); fprintf(fid, "grid on;\n"); fprintf(fid, "t0 = round(0.25*length(r));\n"); fprintf(fid, "figure;\n"); fprintf(fid, "plot(r(1:t0),'x','Color',[0.6 0.6 0.6],r(t0:end),'x','Color',[0 0.25 0.5]);\n"); fprintf(fid, "grid on;\n"); fprintf(fid, "axis([-1.5 1.5 -1.5 1.5]);\n"); fprintf(fid, "axis('square');\n"); fprintf(fid, "xlabel('In-Phase');\n"); fprintf(fid, "ylabel('Quadrature');\n"); fprintf(fid, "legend(['first 25%%'],['last 75%%'],1);\n"); fclose(fid); printf("results written to %s.\n",OUTPUT_FILENAME); nco_crcf_destroy(nco_tx); nco_crcf_destroy(nco_rx); modem_destroy(mod); modem_destroy(demod); printf("bit errors: %u / %u\n", num_errors, bps*n); printf("done.\n"); return 0; }
int main() { // spectral periodogram options unsigned int nfft = 1200; // spectral periodogram FFT size unsigned int num_samples = 64000; // number of samples float fc = 0.20f; // carrier (relative to sampling rate) // create objects iirfilt_crcf filter_tx = iirfilt_crcf_create_lowpass(15, 0.05); nco_crcf mixer_tx = nco_crcf_create(LIQUID_VCO); nco_crcf mixer_rx = nco_crcf_create(LIQUID_VCO); iirfilt_crcf filter_rx = iirfilt_crcf_create_lowpass(7, 0.2); // set carrier frequencies nco_crcf_set_frequency(mixer_tx, fc * 2*M_PI); nco_crcf_set_frequency(mixer_rx, fc * 2*M_PI); // create objects for measuring power spectral density spgramcf spgram_tx = spgramcf_create_default(nfft); spgramf spgram_dac = spgramf_create_default(nfft); spgramcf spgram_rx = spgramcf_create_default(nfft); // run through loop one step at a time unsigned int i; for (i=0; i<num_samples; i++) { // STEP 1: generate input signal (filtered noise with offset tone) float complex v1 = (randnf() + randnf()*_Complex_I) + 3.0f*cexpf(-_Complex_I*0.2f*i); iirfilt_crcf_execute(filter_tx, v1, &v1); // save spectrum spgramcf_push(spgram_tx, v1); // STEP 2: mix signal up and save real part (DAC output) nco_crcf_mix_up(mixer_tx, v1, &v1); float v2 = crealf(v1); nco_crcf_step(mixer_tx); // save spectrum spgramf_push(spgram_dac, v2); // STEP 3: mix signal down and filter off image float complex v3; nco_crcf_mix_down(mixer_rx, v2, &v3); iirfilt_crcf_execute(filter_rx, v3, &v3); nco_crcf_step(mixer_rx); // save spectrum spgramcf_push(spgram_rx, v3); } // compute power spectral density output float psd_tx [nfft]; float psd_dac [nfft]; float psd_rx [nfft]; spgramcf_get_psd(spgram_tx, psd_tx); spgramf_get_psd( spgram_dac, psd_dac); spgramcf_get_psd(spgram_rx, psd_rx); // destroy objects spgramcf_destroy(spgram_tx); spgramf_destroy(spgram_dac); spgramcf_destroy(spgram_rx); iirfilt_crcf_destroy(filter_tx); nco_crcf_destroy(mixer_tx); nco_crcf_destroy(mixer_rx); iirfilt_crcf_destroy(filter_rx); // // 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,"psd_tx = zeros(1,nfft);\n"); fprintf(fid,"psd_dac= zeros(1,nfft);\n"); fprintf(fid,"psd_rx = zeros(1,nfft);\n"); for (i=0; i<nfft; i++) { fprintf(fid,"psd_tx (%6u) = %12.4e;\n", i+1, psd_tx [i]); fprintf(fid,"psd_dac(%6u) = %12.4e;\n", i+1, psd_dac[i]); fprintf(fid,"psd_rx (%6u) = %12.4e;\n", i+1, psd_rx [i]); } fprintf(fid,"figure;\n"); fprintf(fid,"hold on;\n"); fprintf(fid," plot(f, psd_tx, '-', 'LineWidth',1.5,'Color',[0.7 0.7 0.7]);\n"); fprintf(fid," plot(f, psd_dac, '-', 'LineWidth',1.5,'Color',[0.0 0.5 0.3]);\n"); fprintf(fid," plot(f, psd_rx, '-', 'LineWidth',1.5,'Color',[0.0 0.3 0.5]);\n"); fprintf(fid,"hold off;\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,"axis([-0.5 0.5 -100 60]);\n"); fprintf(fid,"legend('transmit (complex)','DAC output (real)','receive (complex)','location','northeast');\n"); fclose(fid); printf("results written to %s.\n", OUTPUT_FILENAME); printf("done.\n"); return 0; }
void ModemFMStereo::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) { ModemKitFMStereo *fmkit = (ModemKitFMStereo *)kit; size_t bufSize = input->data.size(); liquid_float_complex u, v, w, x, y; double audio_resample_ratio = fmkit->audioResampleRatio; if (demodOutputData.size() != bufSize) { if (demodOutputData.capacity() < bufSize) { demodOutputData.reserve(bufSize); } demodOutputData.resize(bufSize); } size_t audio_out_size = (size_t)ceil((double) (bufSize) * audio_resample_ratio) + 512; freqdem_demodulate_block(demodFM, &input->data[0], bufSize, &demodOutputData[0]); if (resampledOutputData.size() != audio_out_size) { if (resampledOutputData.capacity() < audio_out_size) { resampledOutputData.reserve(audio_out_size); } resampledOutputData.resize(audio_out_size); } unsigned int numAudioWritten; msresamp_rrrf_execute(fmkit->audioResampler, &demodOutputData[0], bufSize, &resampledOutputData[0], &numAudioWritten); if (demodStereoData.size() != bufSize) { if (demodStereoData.capacity() < bufSize) { demodStereoData.reserve(bufSize); } demodStereoData.resize(bufSize); } float phase_error = 0; for (size_t i = 0; i < bufSize; i++) { // real -> complex firhilbf_r2c_execute(fmkit->firStereoR2C, demodOutputData[i], &x); // 19khz pilot band-pass iirfilt_crcf_execute(fmkit->iirStereoPilot, x, &v); nco_crcf_cexpf(fmkit->stereoPilot, &w); w.imag = -w.imag; // conjf(w) // multiply u = v * conjf(w) u.real = v.real * w.real - v.imag * w.imag; u.imag = v.real * w.imag + v.imag * w.real; // cargf(u) phase_error = atan2f(u.imag,u.real); // step pll nco_crcf_pll_step(fmkit->stereoPilot, phase_error); nco_crcf_step(fmkit->stereoPilot); // 38khz down-mix nco_crcf_mix_down(fmkit->stereoPilot, x, &y); nco_crcf_mix_down(fmkit->stereoPilot, y, &x); // complex -> real firhilbf_c2r_execute(fmkit->firStereoC2R, x, &demodStereoData[i]); } // std::cout << "[PLL] phase error: " << phase_error; // std::cout << " freq:" << (((nco_crcf_get_frequency(stereoPilot) / (2.0 * M_PI)) * inp->sampleRate)) << std::endl; if (audio_out_size != resampledStereoData.size()) { if (resampledStereoData.capacity() < audio_out_size) { resampledStereoData.reserve(audio_out_size); } resampledStereoData.resize(audio_out_size); } msresamp_rrrf_execute(fmkit->stereoResampler, &demodStereoData[0], bufSize, &resampledStereoData[0], &numAudioWritten); audioOut->channels = 2; if (audioOut->data.capacity() < (numAudioWritten * 2)) { audioOut->data.reserve(numAudioWritten * 2); } audioOut->data.resize(numAudioWritten * 2); for (size_t i = 0; i < numAudioWritten; i++) { float l, r; float ld, rd; if (fmkit->demph) { iirfilt_rrrf_execute(fmkit->iirDemphL, 0.568f * (resampledOutputData[i] - (resampledStereoData[i])), &ld); iirfilt_rrrf_execute(fmkit->iirDemphR, 0.568f * (resampledOutputData[i] + (resampledStereoData[i])), &rd); firfilt_rrrf_push(fmkit->firStereoLeft, ld); firfilt_rrrf_execute(fmkit->firStereoLeft, &l); firfilt_rrrf_push(fmkit->firStereoRight, rd); firfilt_rrrf_execute(fmkit->firStereoRight, &r); } else { firfilt_rrrf_push(fmkit->firStereoLeft, 0.568f * (resampledOutputData[i] - (resampledStereoData[i]))); firfilt_rrrf_execute(fmkit->firStereoLeft, &l); firfilt_rrrf_push(fmkit->firStereoRight, 0.568f * (resampledOutputData[i] + (resampledStereoData[i]))); firfilt_rrrf_execute(fmkit->firStereoRight, &r); } audioOut->data[i * 2] = l; audioOut->data[i * 2 + 1] = r; } }
// 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; } } }
int main() { // options unsigned int num_channels=8; // number of channels unsigned int m=2; // filter delay float As=-60; // stop-band attenuation unsigned int num_frames=25; // number of frames // create objects firpfbch_crcf c = firpfbch_crcf_create_kaiser(LIQUID_ANALYZER, num_channels, m, As); //firpfbch_crcf_print(c); FILE*fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s: auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\nclose all;\n\n"); fprintf(fid,"num_channels=%u;\n", num_channels); fprintf(fid,"num_frames=%u;\n", num_frames); fprintf(fid,"x = zeros(1,%u);\n", num_channels * num_frames); fprintf(fid,"y = zeros(%u,%u);\n", num_channels, num_frames); unsigned int i, j, n=0; float complex x[num_channels]; // time-domain input float complex y[num_channels]; // channelized output // create nco: sweeps entire range of frequencies over the evaluation interval nco_crcf nco_tx = nco_crcf_create(LIQUID_VCO); nco_crcf_set_frequency(nco_tx, 0.0f); float df = 2*M_PI/(num_channels*num_frames); printf("fr/ch:"); for (j=0; j<num_channels; j++) printf("%3u",j); printf("\n"); for (i=0; i<num_frames; i++) { // generate frame of data for (j=0; j<num_channels; j++) { nco_crcf_cexpf(nco_tx, &x[j]); nco_crcf_adjust_frequency(nco_tx, df); nco_crcf_step(nco_tx); } // execute analysis filter bank firpfbch_crcf_analyzer_execute(c, x, y); printf("%4u : ", i); for (j=0; j<num_channels; j++) { if (cabsf(y[j]) > num_channels / 4) printf(" x "); else printf(" . "); } printf("\n"); // write output to file for (j=0; j<num_channels; j++) { // frequency data fprintf(fid,"y(%4u,%4u) = %12.4e + j*%12.4e;\n", j+1, i+1, crealf(y[j]), cimagf(y[j])); // time data fprintf(fid,"x(%4u) = %12.4e + j*%12.4e;\n", n+1, crealf(x[j]), cimag(x[j])); n++; } } // destroy objects nco_crcf_destroy(nco_tx); firpfbch_crcf_destroy(c); // plot results fprintf(fid,"\n\n"); fprintf(fid,"figure;\n"); fprintf(fid,"subplot(2,1,1);\n"); fprintf(fid," plot(1:length(x),real(x),1:length(x),imag(x));\n"); fprintf(fid," xlabel('time');\n"); fprintf(fid," ylabel('signal');\n"); fprintf(fid,"subplot(2,1,2);\n"); fprintf(fid," plot(20*log10(abs(y.')/num_channels));\n"); fprintf(fid," xlabel('time (decimated)');\n"); fprintf(fid," ylabel('channelized energy [dB]');\n"); fprintf(fid,"n=min(num_channels,8);\n"); fprintf(fid,"figure;\n"); fprintf(fid,"for i=1:n\n"); fprintf(fid," subplot(n,1,i);\n"); fprintf(fid," plot(1:num_frames,real(y(i,:)),1:num_frames,imag(y(i,:)));\n"); fprintf(fid," axis off;\n"); fprintf(fid," ylabel(num2str(i));\n"); fprintf(fid,"end;\n"); fclose(fid); printf("results written to %s\n", OUTPUT_FILENAME); printf("done.\n"); return 0; }
// 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; } } }