// estimate long sequence gain // _q : ofdmframesync object // _x : input array (time), [size: M x 1] // _G : output gain (freq) void ofdmframesync_estimate_gain_S1(ofdmframesync _q, float complex * _x, float complex * _G) { // move input array into fft input buffer memmove(_q->x, _x, (_q->M)*sizeof(float complex)); // compute fft, storing result into _q->X FFT_EXECUTE(_q->fft); // compute gain, ignoring NULL subcarriers unsigned int i; float gain = sqrtf(_q->M_S1) / (float)(_q->M); for (i=0; i<_q->M; i++) { if (_q->p[i] != OFDMFRAME_SCTYPE_NULL) { // NOTE : if cabsf(_q->S1[i]) == 0 then we can multiply by conjugate // rather than compute division //_G[i] = _q->X[i] / _q->S1[i]; _G[i] = _q->X[i] * conjf(_q->S1[i]); } else { _G[i] = 0.0f; } // normalize gain _G[i] *= gain; } }
// write OFDM symbol // _q : framing generator object // _x : input symbols, [size: _M x 1] // _y : output samples, [size: _M x 1] void ofdmframegen_writesymbol(ofdmframegen _q, float complex * _x, float complex * _y) { // move frequency data to internal buffer unsigned int i; unsigned int k; int sctype; for (i=0; i<_q->M; i++) { // start at mid-point (effective fftshift) k = (i + _q->M/2) % _q->M; sctype = _q->p[k]; if (sctype==OFDMFRAME_SCTYPE_NULL) { // disabled subcarrier _q->X[k] = 0.0f; } else if (sctype==OFDMFRAME_SCTYPE_PILOT) { // pilot subcarrier _q->X[k] = (msequence_advance(_q->ms_pilot) ? 1.0f : -1.0f) * _q->g_data; } else { // data subcarrier _q->X[k] = _x[k] * _q->g_data; } //printf("X[%3u] = %12.8f + j*%12.8f;\n",i+1,crealf(_q->X[i]),cimagf(_q->X[i])); } // execute transform FFT_EXECUTE(_q->ifft); // copy result to output, adding cyclic prefix and tapering window ofdmframegen_gensymbol(_q, _y); }
// estimate long sequence gain // _q : wlanframesync object // _x : input array (time), [size: M x 1] // _G : output gain (freq) void wlanframesync_estimate_gain_S1(wlanframesync _q, float complex * _x, float complex * _G) { // move input array into fft input buffer memmove(_q->x, _x, 64*sizeof(float complex)); // compute fft, storing result into _q->X FFT_EXECUTE(_q->fft); // nominal gain (normalization factor) float gain = 0.11267f; // sqrt(52)/64 ; sqrtf(_q->M_S1) / (float)(_q->M); // compute gain, ignoring NULL subcarriers unsigned int i; for (i=0; i<64; i++) { if (i == 0 || (i>26 && i<38) ) { // NULL subcarrier _G[i] = 0.0f; } else { // DATA/PILOT subcarrier (S1 enabled) _G[i] = _q->X[i] * conjf(wlanframe_S1[i]) * gain; } } }
// demodulate symbol, assuming perfect symbol timing // _q : fskdem object // _y : input sample array [size: _k x 1] unsigned int fskdem_demodulate(fskdem _q, float complex * _y) { // copy input to internal time buffer memmove(_q->buf_time, _y, _q->k*sizeof(float complex)); // compute transform, storing result in 'buf_freq' FFT_EXECUTE(_q->fft); // find maximum by looking at particular bins float vmax = 0; unsigned int s = 0; // run search for (s=0; s<_q->M; s++) { float v = cabsf( _q->buf_freq[_q->demod_map[s]] ); if (s==0 || v > vmax) { // save optimal output symbol _q->s_demod = s; // save peak FFT bin value vmax = v; } } // save best result return _q->s_demod; }
// estimate short sequence gain // _q : wlanframesync object // _x : input array (time), [size: M x 1] // _G : output gain (freq) void wlanframesync_estimate_gain_S0(wlanframesync _q, float complex * _x, float complex * _G) { // move input array into fft input buffer memmove(_q->x, _x, 64*sizeof(float complex)); // compute fft, storing result into _q->X FFT_EXECUTE(_q->fft); // compute gain, ignoring NULL subcarriers unsigned int i; float gain = 0.054127f; // sqrt(12)/64 ; sqrtf(_q->M_S0) / (float)(_q->M); // clear input for (i=0; i<64; i++) _G[i] = 0.0f; // NOTE : if cabsf(_q->S0[i]) == 0 then we can multiply by conjugate // rather than compute division //_G[i] = _q->X[i] / _q->S0[i]; _G[40] = _q->X[40] * conjf(wlanframe_S0[40]) * gain; _G[44] = _q->X[44] * conjf(wlanframe_S0[44]) * gain; _G[48] = _q->X[48] * conjf(wlanframe_S0[48]) * gain; _G[52] = _q->X[52] * conjf(wlanframe_S0[52]) * gain; _G[56] = _q->X[56] * conjf(wlanframe_S0[56]) * gain; _G[60] = _q->X[60] * conjf(wlanframe_S0[60]) * gain; // _G[ 4] = _q->X[ 4] * conjf(wlanframe_S0[ 4]) * gain; _G[ 8] = _q->X[ 8] * conjf(wlanframe_S0[ 8]) * gain; _G[12] = _q->X[12] * conjf(wlanframe_S0[12]) * gain; _G[16] = _q->X[16] * conjf(wlanframe_S0[16]) * gain; _G[20] = _q->X[20] * conjf(wlanframe_S0[20]) * gain; _G[24] = _q->X[24] * conjf(wlanframe_S0[24]) * gain; }
// estimate complex equalizer gain from G0 and G1 // _q : ofdmframesync object // _ntaps : number of time-domain taps for smoothing void ofdmframesync_estimate_eqgain(ofdmframesync _q, unsigned int _ntaps) { #if DEBUG_OFDMFRAMESYNC if (_q->debug_enabled) { // copy pre-smoothed gain memmove(_q->G_hat, _q->G, _q->M*sizeof(float complex)); } #endif // validate input if (_ntaps == 0 || _ntaps > _q->M) { fprintf(stderr, "error: ofdmframesync_estimate_eqgain(), ntaps must be in [1,M]\n"); exit(1); } unsigned int i; // generate smoothing window (fft of temporal window) for (i=0; i<_q->M; i++) _q->x[i] = (i < _ntaps) ? 1.0f : 0.0f; FFT_EXECUTE(_q->fft); memmove(_q->G0, _q->G, _q->M*sizeof(float complex)); // smooth complex equalizer gains for (i=0; i<_q->M; i++) { // set gain to zero for null subcarriers if (_q->p[i] == OFDMFRAME_SCTYPE_NULL) { _q->G[i] = 0.0f; continue; } float complex w; float complex w0 = 0.0f; float complex G_hat = 0.0f; unsigned int j; for (j=0; j<_q->M; j++) { if (_q->p[j] == OFDMFRAME_SCTYPE_NULL) continue; // select window sample from array w = _q->X[(i + _q->M - j) % _q->M]; // accumulate gain //G_hat += w * 0.5f * (_q->G0[j] + _q->G1[j]); G_hat += w * _q->G0[j]; w0 += w; } // eliminate divide-by-zero issues if (cabsf(w0) < 1e-4f) { fprintf(stderr,"error: ofdmframesync_estimate_eqgain(), weighting factor is zero\n"); w0 = 1.0f; } _q->G[i] = G_hat / w0; } }
void firpfbch_analyzer_run(firpfbch _c, float complex * _y) { // NOTE: The analyzer is different from the synthesizer in // that the invocation of the commutator results in a // delay from the first input sample to the resulting // partitions. As a result, the inverse DFT is // invoked after the first filter is run, after which // the remaining filters are executed. // restore saved IDFT input state X from X_prime memmove(_c->X, _c->X_prime, (_c->num_channels)*sizeof(float complex)); unsigned int i, b; unsigned int k = _c->filter_index; // push first value and compute output float complex * r; WINDOW(_read)(_c->w[k], &r); DOTPROD(_execute)(_c->dp[0], r, &(_c->X[0])); // execute inverse fft, store in buffer _c->x FFT_EXECUTE(_c->fft); // copy results to output buffer memmove(_y, _c->x, (_c->num_channels)*sizeof(float complex)); // push remaining samples into filter bank and execute in // *reverse* order, putting result into the inverse DFT // input buffer _c->X //for (i=1; i<_c->num_channels; i++) { // NOTE : the filter window buffers have already been loaded // in the proper reverse order, so there is no need // to execute the dot products in any particular order, // so long as they are aligned with the proper input // buffer. for (i=1; i<_c->num_channels; i++) { b = (k+i) % _c->num_channels; WINDOW(_read)(_c->w[b], &r); DOTPROD(_execute)(_c->dp[i], r, &(_c->X[i])); } }
void FFTransformer::fillComplexSub() { auto plan = FFT_CREATE_PLAN(m_bufferSize, m_complexSub, m_complexSub, FFTW_FORWARD, FFTW_ESTIMATE); double speed = Options::getInstance()->getSignalSpeed(); double rxRate = Options::getInstance()->getBand(); for(size_t i = 0; i < m_bufferSize; i++) { double t = i / rxRate; t *= t; auto iter = *(m_complexSub + i); iter[0] = cos(M_PI * t * speed); iter[1] = sin(M_PI * t * speed); } FFT_EXECUTE(plan); for(size_t i = 0; i < m_bufferSize; i++) m_complexSub[i][1] *= -1; FFT_DESTROY_PLAN(plan); }
void firpfbch_synthesizer_execute(firpfbch _c, float complex * _x, float complex * _y) { unsigned int i; // copy samples into ifft input buffer _c->X memmove(_c->X, _x, (_c->num_channels)*sizeof(float complex)); // execute inverse fft, store in buffer _c->x FFT_EXECUTE(_c->fft); // push samples into filter bank and execute, putting // samples into output buffer _y float complex * r; for (i=0; i<_c->num_channels; i++) { WINDOW(_push)(_c->w[i], _c->x[i]); WINDOW(_read)(_c->w[i], &r); DOTPROD(_execute)(_c->dp[i], r, &(_y[i])); // invoke scaling factor _y[i] /= (float)(_c->num_channels); } }
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; } }
// receive data symbols void wlanframesync_execute_rxdata(wlanframesync _q) { _q->timer++; if (_q->timer < 80) return; //printf(" receiving symbol %u...\n", _q->num_symbols); // reset timer _q->timer = 0; // run fft float complex * rc; windowcf_read(_q->input_buffer, &rc); memmove(_q->x, &rc[16-2], 64*sizeof(float complex)); // compute fft, storing result into _q->X FFT_EXECUTE(_q->fft); // recover symbol, correcting for gain, pilot phase, etc. wlanframesync_rxsymbol(_q); // demodulate and pack unsigned int i; unsigned int n=0; unsigned int sym; for (i=0; i<64; i++) { unsigned int k = (i + 32) % 64; if ( k==0 || (k > 26 && k < 38) ) { // NULL subcarrier } else if (k==43 || k==57 || k==7 || k==21) { // PILOT subcarrier } else { // DATA subcarrier assert(n<48); sym = wlan_demodulate(_q->mod_scheme, _q->X[k]); _q->modem_syms[n] = sym; n++; #if DEBUG_WLANFRAMESYNC // TODO : move this outside loop if (_q->debug_enabled) windowcf_push(_q->debug_framesyms, _q->X[k]); #endif } } assert(n==48); // pack modem symbols //printf(" %3u = %3u * %3u\n", _q->enc_msg_len, _q->nsym, _q->bytes_per_symbol); unsigned int num_written; liquid_wlan_repack_bytes(_q->modem_syms, _q->nbpsc, 48, &_q->msg_enc[_q->num_symbols * _q->bytes_per_symbol], 8, _q->bytes_per_symbol, &num_written); assert(num_written == _q->bytes_per_symbol); // increment number of received symbols _q->num_symbols++; // check number of symbols if (_q->num_symbols == _q->nsym) { // decode message wlan_packet_decode(_q->rate, _q->seed, _q->length, _q->msg_enc, _q->msg_dec); // assemble RX vector struct wlan_rxvector_s rxvector; rxvector.LENGTH = _q->length; rxvector.RSSI = 200 + (unsigned int) (10*log10f(_q->g0)); rxvector.DATARATE = _q->rate; rxvector.SERVICE = 0; // invoke callback if (_q->callback != NULL) { //int retval = _q->callback(_q->msg_dec, rxvector, _q->userdata); } // reset and return wlanframesync_reset(_q); } }
// receive the 'SIGNAL' field void wlanframesync_execute_rxsignal(wlanframesync _q) { _q->timer++; if (_q->timer < 80) return; // reset timer _q->timer = 0; // run fft float complex * rc; windowcf_read(_q->input_buffer, &rc); memmove(_q->x, &rc[16-2], 64*sizeof(float complex)); // compute fft, storing result into _q->X FFT_EXECUTE(_q->fft); // recover symbol, correcting for gain, pilot phase, etc. wlanframesync_rxsymbol(_q); // demodulate, decode, ... memset(_q->signal_int, 0x00, 6*sizeof(unsigned char)); _q->signal_int[0] |= crealf(_q->X[38]) > 0.0f ? 0x80 : 0x00; _q->signal_int[0] |= crealf(_q->X[39]) > 0.0f ? 0x40 : 0x00; _q->signal_int[0] |= crealf(_q->X[40]) > 0.0f ? 0x20 : 0x00; _q->signal_int[0] |= crealf(_q->X[41]) > 0.0f ? 0x10 : 0x00; _q->signal_int[0] |= crealf(_q->X[42]) > 0.0f ? 0x08 : 0x00; // 43 : pilot _q->signal_int[0] |= crealf(_q->X[44]) > 0.0f ? 0x04 : 0x00; _q->signal_int[0] |= crealf(_q->X[45]) > 0.0f ? 0x02 : 0x00; _q->signal_int[0] |= crealf(_q->X[46]) > 0.0f ? 0x01 : 0x00; _q->signal_int[1] |= crealf(_q->X[47]) > 0.0f ? 0x80 : 0x00; _q->signal_int[1] |= crealf(_q->X[48]) > 0.0f ? 0x40 : 0x00; _q->signal_int[1] |= crealf(_q->X[49]) > 0.0f ? 0x20 : 0x00; _q->signal_int[1] |= crealf(_q->X[50]) > 0.0f ? 0x10 : 0x00; _q->signal_int[1] |= crealf(_q->X[51]) > 0.0f ? 0x08 : 0x00; _q->signal_int[1] |= crealf(_q->X[52]) > 0.0f ? 0x04 : 0x00; _q->signal_int[1] |= crealf(_q->X[53]) > 0.0f ? 0x02 : 0x00; _q->signal_int[1] |= crealf(_q->X[54]) > 0.0f ? 0x01 : 0x00; _q->signal_int[2] |= crealf(_q->X[55]) > 0.0f ? 0x80 : 0x00; _q->signal_int[2] |= crealf(_q->X[56]) > 0.0f ? 0x40 : 0x00; // 57 : pilot _q->signal_int[2] |= crealf(_q->X[58]) > 0.0f ? 0x20 : 0x00; _q->signal_int[2] |= crealf(_q->X[59]) > 0.0f ? 0x10 : 0x00; _q->signal_int[2] |= crealf(_q->X[60]) > 0.0f ? 0x08 : 0x00; _q->signal_int[2] |= crealf(_q->X[61]) > 0.0f ? 0x04 : 0x00; _q->signal_int[2] |= crealf(_q->X[62]) > 0.0f ? 0x02 : 0x00; _q->signal_int[2] |= crealf(_q->X[63]) > 0.0f ? 0x01 : 0x00; // 0 : NULL _q->signal_int[3] |= crealf(_q->X[ 1]) > 0.0f ? 0x80 : 0x00; _q->signal_int[3] |= crealf(_q->X[ 2]) > 0.0f ? 0x40 : 0x00; _q->signal_int[3] |= crealf(_q->X[ 3]) > 0.0f ? 0x20 : 0x00; _q->signal_int[3] |= crealf(_q->X[ 4]) > 0.0f ? 0x10 : 0x00; _q->signal_int[3] |= crealf(_q->X[ 5]) > 0.0f ? 0x08 : 0x00; _q->signal_int[3] |= crealf(_q->X[ 6]) > 0.0f ? 0x04 : 0x00; // 7 : pilot _q->signal_int[3] |= crealf(_q->X[ 8]) > 0.0f ? 0x02 : 0x00; _q->signal_int[3] |= crealf(_q->X[ 9]) > 0.0f ? 0x01 : 0x00; _q->signal_int[4] |= crealf(_q->X[10]) > 0.0f ? 0x80 : 0x00; _q->signal_int[4] |= crealf(_q->X[11]) > 0.0f ? 0x40 : 0x00; _q->signal_int[4] |= crealf(_q->X[12]) > 0.0f ? 0x20 : 0x00; _q->signal_int[4] |= crealf(_q->X[13]) > 0.0f ? 0x10 : 0x00; _q->signal_int[4] |= crealf(_q->X[14]) > 0.0f ? 0x08 : 0x00; _q->signal_int[4] |= crealf(_q->X[15]) > 0.0f ? 0x04 : 0x00; _q->signal_int[4] |= crealf(_q->X[16]) > 0.0f ? 0x02 : 0x00; _q->signal_int[4] |= crealf(_q->X[17]) > 0.0f ? 0x01 : 0x00; _q->signal_int[5] |= crealf(_q->X[18]) > 0.0f ? 0x80 : 0x00; _q->signal_int[5] |= crealf(_q->X[19]) > 0.0f ? 0x40 : 0x00; _q->signal_int[5] |= crealf(_q->X[20]) > 0.0f ? 0x20 : 0x00; // 21 : pilot _q->signal_int[5] |= crealf(_q->X[22]) > 0.0f ? 0x10 : 0x00; _q->signal_int[5] |= crealf(_q->X[23]) > 0.0f ? 0x08 : 0x00; _q->signal_int[5] |= crealf(_q->X[24]) > 0.0f ? 0x04 : 0x00; _q->signal_int[5] |= crealf(_q->X[25]) > 0.0f ? 0x02 : 0x00; _q->signal_int[5] |= crealf(_q->X[26]) > 0.0f ? 0x01 : 0x00; // decode SIGNAL field wlanframesync_decode_signal(_q); // validate proper decoding if (!_q->signal_valid) { // reset synchronizer and return wlanframesync_reset(_q); return; } // set state _q->state = WLANFRAMESYNC_STATE_RXDATA; }
// create FFT-based FIR filter using external coefficients // _h : filter coefficients [size: _h_len x 1] // _h_len : filter length, _h_len > 0 // _n : block size = nfft/2, at least _h_len-1 FFTFILT() FFTFILT(_create)(TC * _h, unsigned int _h_len, unsigned int _n) { // validate input if (_h_len == 0) { fprintf(stderr,"error: fftfilt_%s_create(), filter length must be greater than zero\n", EXTENSION_FULL); exit(1); } else if (_n < _h_len-1) { fprintf(stderr,"error: fftfilt_%s_create(), block length must be greater than _h_len-1 (%u)\n", EXTENSION_FULL, _h_len-1); exit(1); } // create filter object and initialize FFTFILT() q = (FFTFILT()) malloc(sizeof(struct FFTFILT(_s))); q->h_len = _h_len; q->n = _n; // copy filter coefficients q->h = (TC *) malloc((q->h_len)*sizeof(TC)); memmove(q->h, _h, _h_len*sizeof(TC)); // allocate internal memory arrays q->time_buf = (float complex *) malloc((2*q->n)* sizeof(float complex)); // time buffer q->freq_buf = (float complex *) malloc((2*q->n)* sizeof(float complex)); // frequency buffer q->H = (float complex *) malloc((2*q->n)* sizeof(float complex)); // FFT{ h } q->w = (float complex *) malloc(( q->n)* sizeof(float complex)); // delay buffer // create internal FFT objects #ifdef LIQUID_FFTOVERRIDE q->fft = fft_create_plan(2*q->n, q->time_buf, q->freq_buf, LIQUID_FFT_FORWARD, 0); q->ifft = fft_create_plan(2*q->n, q->freq_buf, q->time_buf, LIQUID_FFT_BACKWARD, 0); #else q->fft = FFT_CREATE_PLAN(2*q->n, q->time_buf, q->freq_buf, FFT_DIR_FORWARD, FFT_METHOD); q->ifft = FFT_CREATE_PLAN(2*q->n, q->freq_buf, q->time_buf, FFT_DIR_BACKWARD, FFT_METHOD); #endif // compute FFT of filter coefficients and copy to internal H array unsigned int i; for (i=0; i<2*q->n; i++) q->time_buf[i] = (i < q->h_len) ? q->h[i] : 0; // time_buf > {FFT} > freq_buf #ifdef LIQUID_FFTOVERRIDE fft_execute(q->fft); #else FFT_EXECUTE(q->fft); #endif memmove(q->H, q->freq_buf, 2*q->n*sizeof(float complex)); // set default scaling FFTFILT(_set_scale)(q, 1); // reset filter state (clear buffer) FFTFILT(_reset)(q); // return object return q; }