// Helper function to keep code base small void window_push_bench(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations, unsigned int _n) { // normalize number of iterations *_num_iterations *= 8; if (*_num_iterations < 1) *_num_iterations = 1; // initialize port windowcf w = windowcf_create(_n); unsigned long int i; // start trials: // write to port, read from port getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { windowcf_push(w, 1.0f); windowcf_push(w, 1.0f); windowcf_push(w, 1.0f); windowcf_push(w, 1.0f); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; windowcf_destroy(w); }
// 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++) }
int main (int argc, char ** argv) { w=windowcf_create(SPECTRUM_FFT_LENGTH); wchA = windowcf_create(TRACK_LENGTH); wchB = windowcf_create(TRACK_LENGTH); wchC = windowcf_create(TRACK_LENGTH); wchA_filtered = windowcf_create(TRACK_LENGTH); wchB_filtered = windowcf_create(TRACK_LENGTH); wchC_filtered = windowcf_create(TRACK_LENGTH); wmag_buffer = windowf_create(TRACK_LENGTH); nco = nco_crcf_create(LIQUID_NCO); std::cout << "hydromath daemon is beginning..." << std::endl; std::cout << "NOTE: if this is symhydromath you must pass in a matfile" << std::endl; std::cout << argv[1] << std::endl; shm_init(); shm_getg(hydrophones_results_track, shm_results_track); shm_getg(hydrophones_results_spectrum, shm_results_spectrum); //shm_results_track.tracked_ping_count=0; shm_results_track.tracked_ping_time=0; if (argc > 1) { udp_init(argv[1]); } else { udp_init(""); } //std::thread track_thread(direction_loop); // //std::thread spectrum_thread(spectrum_loop); track_sample_idx = 0; while (loop(&spt) == 0) { shm_getg(hydrophones_settings, shm_settings); for (int i = 0; i < 3*CHANNEL_DEPTH; i+=3) { windowcf_push(w, std::complex<float>(spt.data[i+1],0)); //This uses channel B windowcf_push(wchA, std::complex<float>(spt.data[i],0)); windowcf_push(wchB, std::complex<float>(spt.data[i+1],0)); windowcf_push(wchC, std::complex<float>(spt.data[i+2],0)); } current_sample_count+=CHANNEL_DEPTH; do_spectrum(); do_track(); } printf("loop done %li =ci\n",current_sample_count/CHANNEL_DEPTH); return 0; }
// execute frame synchronizer // _q : frame synchronizer object // _x : input sample array [size: _n x 1] // _n : number of input samples void flexframesync_execute(flexframesync _q, float complex * _x, unsigned int _n) { unsigned int i; for (i=0; i<_n; i++) { #if DEBUG_FLEXFRAMESYNC // write samples to debug buffer // NOTE: the debug_qdetector_flush prevents samples from being written twice if (_q->debug_enabled && !_q->debug_qdetector_flush) windowcf_push(_q->debug_x, _x[i]); #endif switch (_q->state) { case FLEXFRAMESYNC_STATE_DETECTFRAME: // detect frame (look for p/n sequence) flexframesync_execute_seekpn(_q, _x[i]); break; case FLEXFRAMESYNC_STATE_RXPREAMBLE: // receive p/n sequence symbols flexframesync_execute_rxpreamble(_q, _x[i]); break; case FLEXFRAMESYNC_STATE_RXHEADER: // receive header symbols flexframesync_execute_rxheader(_q, _x[i]); break; case FLEXFRAMESYNC_STATE_RXPAYLOAD: // receive payload symbols flexframesync_execute_rxpayload(_q, _x[i]); break; default: fprintf(stderr,"error: flexframesync_exeucte(), unknown/unsupported state\n"); exit(1); } } }
// execute frame synchronizer // _q : frame synchronizer object // _x : input sample array [size: _n x 1] // _n : number of input samples void flexframesync_execute(flexframesync _q, float complex * _x, unsigned int _n) { unsigned int i; for (i=0; i<_n; i++) { #if DEBUG_FLEXFRAMESYNC if (_q->debug_enabled) windowcf_push(_q->debug_x, _x[i]); #endif switch (_q->state) { case STATE_DETECTFRAME: // detect frame (look for p/n sequence) flexframesync_execute_seekpn(_q, _x[i]); break; case STATE_RXPN: // receive p/n sequence symbols flexframesync_execute_rxpn(_q, _x[i]); break; case STATE_RXHEADER: // receive header sequence symbols flexframesync_execute_rxheader(_q, _x[i]); break; case STATE_RXPAYLOAD: // receive payload symbols flexframesync_execute_rxpayload(_q, _x[i]); break; default: fprintf(stderr,"error: flexframesync_exeucte(), unknown/unsupported state\n"); exit(1); } } }
void ofdmoqamframe64sync_execute(ofdmoqamframe64sync _q, float complex * _x, unsigned int _n) { unsigned int i; float complex x; for (i=0; i<_n; i++) { x = _x[i]; #if DEBUG_OFDMOQAMFRAME64SYNC windowcf_push(_q->debug_x,x); #endif _q->num_samples++; // coarse gain correction //x *= _q->g; // compensate for CFO nco_crcf_mix_down(_q->nco_rx, x, &x); // push sample into analysis filter banks float complex x_delay0; float complex x_delay1; windowcf_index(_q->input_buffer,0, &x_delay0); // full symbol delay windowcf_index(_q->input_buffer,32,&x_delay1); // half symbol delay windowcf_push(_q->input_buffer,x); firpfbch_analyzer_push(_q->ca0, x_delay0); // push input sample firpfbch_analyzer_push(_q->ca1, x_delay1); // push delayed sample switch (_q->state) { case OFDMOQAMFRAME64SYNC_STATE_PLCPSHORT: ofdmoqamframe64sync_execute_plcpshort(_q,x); break; case OFDMOQAMFRAME64SYNC_STATE_PLCPLONG0: ofdmoqamframe64sync_execute_plcplong0(_q,x); break; case OFDMOQAMFRAME64SYNC_STATE_PLCPLONG1: ofdmoqamframe64sync_execute_plcplong1(_q,x); break; case OFDMOQAMFRAME64SYNC_STATE_RXSYMBOLS: ofdmoqamframe64sync_execute_rxsymbols(_q,x); break; default:; } } // for (i=0; i<_n; i++) } // ofdmoqamframe64sync_execute()
void ofdmoqamframe64sync_execute_plcplong1(ofdmoqamframe64sync _q, float complex _x) { // cross-correlator float complex rxy; firfilt_cccf_push(_q->crosscorr, _x); firfilt_cccf_execute(_q->crosscorr, &rxy); rxy *= _q->g; #if DEBUG_OFDMOQAMFRAME64SYNC windowcf_push(_q->debug_rxy, rxy); #endif _q->timer++; if (_q->timer < _q->num_subcarriers-8) { return; } else if (_q->timer > _q->num_subcarriers+8) { #if DEBUG_OFDMOQAMFRAME64SYNC_PRINT printf("warning: ofdmoqamframe64sync could not find second PLCP long sequence; resetting synchronizer\n"); #endif ofdmoqamframe64sync_reset(_q); return; } if (cabsf(rxy) > 0.7f*(_q->rxy_thresh)*(_q->num_subcarriers)) { #if DEBUG_OFDMOQAMFRAME64SYNC_PRINT printf("rxy[1] : %12.8f at input[%3u]\n", cabsf(rxy), _q->num_samples); #endif // float complex * rc; windowcf_read(_q->input_buffer, &rc); memmove(_q->S1b, rc, 64*sizeof(float complex)); // estimate frequency offset float complex rxy_hat=0.0f; unsigned int j; for (j=0; j<64; j++) { rxy_hat += _q->S1a[j] * conjf(_q->S1b[j]) * hamming(j,64); } float nu_hat1 = -cargf(rxy_hat); if (nu_hat1 > M_PI) nu_hat1 -= 2.0f*M_PI; if (nu_hat1 < -M_PI) nu_hat1 += 2.0f*M_PI; nu_hat1 /= 64.0f; #if DEBUG_OFDMOQAMFRAME64SYNC_PRINT printf("nu_hat[0] = %12.8f\n", _q->nu_hat); printf("nu_hat[1] = %12.8f\n", nu_hat1); #endif nco_crcf_adjust_frequency(_q->nco_rx, nu_hat1); /* printf("exiting prematurely\n"); ofdmoqamframe64sync_destroy(_q); exit(1); */ _q->state = OFDMOQAMFRAME64SYNC_STATE_RXSYMBOLS; } }
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()
void ofdmoqamframe64sync_execute_plcpshort(ofdmoqamframe64sync _q, float complex _x) { // run AGC, clip output float complex y; agc_crcf_execute(_q->sigdet, _x, &y); //if (agc_crcf_get_signal_level(_q->sigdet) < -15.0f) // return; if (cabsf(y) > 2.0f) y = 2.0f*liquid_cexpjf(cargf(y)); // auto-correlators //autocorr_cccf_push(_q->autocorr, _x); autocorr_cccf_push(_q->autocorr, y); autocorr_cccf_execute(_q->autocorr, &_q->rxx); #if DEBUG_OFDMOQAMFRAME64SYNC windowcf_push(_q->debug_rxx, _q->rxx); windowf_push(_q->debug_rssi, agc_crcf_get_signal_level(_q->sigdet)); #endif float rxx_mag = cabsf(_q->rxx); float threshold = (_q->rxx_thresh)*(_q->autocorr_length); if (rxx_mag > threshold) { // wait for auto-correlation to peak before changing state if (rxx_mag > _q->rxx_mag_max) { _q->rxx_mag_max = rxx_mag; return; } // estimate CFO _q->nu_hat = cargf(_q->rxx); if (_q->nu_hat > M_PI/2.0f) _q->nu_hat -= M_PI; if (_q->nu_hat < -M_PI/2.0f) _q->nu_hat += M_PI; _q->nu_hat *= 4.0f / (float)(_q->num_subcarriers); #if DEBUG_OFDMOQAMFRAME64SYNC_PRINT printf("rxx = |%12.8f| arg{%12.8f}\n", cabsf(_q->rxx),cargf(_q->rxx)); printf("nu_hat = %12.8f\n", _q->nu_hat); #endif nco_crcf_set_frequency(_q->nco_rx, _q->nu_hat); _q->state = OFDMOQAMFRAME64SYNC_STATE_PLCPLONG0; _q->g = agc_crcf_get_gain(_q->sigdet); #if DEBUG_OFDMOQAMFRAME64SYNC_PRINT printf("gain : %f\n", _q->g); #endif _q->timer=0; } }
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 ofdmoqamframe64sync_execute_plcplong0(ofdmoqamframe64sync _q, float complex _x) { // cross-correlator float complex rxy; firfilt_cccf_push(_q->crosscorr, _x); firfilt_cccf_execute(_q->crosscorr, &rxy); rxy *= _q->g; #if DEBUG_OFDMOQAMFRAME64SYNC windowcf_push(_q->debug_rxy, rxy); #endif _q->timer++; if (_q->timer > 10*(_q->num_subcarriers)) { #if DEBUG_OFDMOQAMFRAME64SYNC_PRINT printf("warning: ofdmoqamframe64sync could not find first PLCP long sequence; resetting synchronizer\n"); #endif ofdmoqamframe64sync_reset(_q); return; } if (cabsf(rxy) > (_q->rxy_thresh)*(_q->num_subcarriers)) { #if DEBUG_OFDMOQAMFRAME64SYNC_PRINT printf("rxy[0] : %12.8f at input[%3u]\n", cabsf(rxy), _q->num_samples); #endif // run analyzers //firpfbch_analyzer_run(_q->ca0, _q->S1a); //firpfbch_analyzer_run(_q->ca1, _q->S1b); _q->sample_phase = (_q->num_samples + (_q->num_subcarriers)/2) % _q->num_subcarriers; //_q->sample_phase = (_q->num_samples) % _q->num_subcarriers; #if DEBUG_OFDMOQAMFRAME64SYNC_PRINT printf("sample phase : %u\n",_q->sample_phase); #endif // float complex * rc; windowcf_read(_q->input_buffer, &rc); memmove(_q->S1a, rc, 64*sizeof(float complex)); _q->state = OFDMOQAMFRAME64SYNC_STATE_PLCPLONG1; _q->timer = 0; } }
// execute frame synchronizer // _q : frame synchronizer object // _x : input sample array [size: _n x 1] // _n : number of input samples void gmskframesync_execute(gmskframesync _q, float complex * _x, unsigned int _n) { // push through synchronizer unsigned int i; for (i=0; i<_n; i++) { float complex xf; // input sample #if GMSKFRAMESYNC_PREFILTER iirfilt_crcf_execute(_q->prefilter, _x[i], &xf); #else xf = _x[i]; #endif #if DEBUG_GMSKFRAMESYNC if (_q->debug_enabled) windowcf_push(_q->debug_x, xf); #endif switch (_q->state) { case STATE_DETECTFRAME: // look for p/n sequence gmskframesync_execute_detectframe(_q, xf); break; case STATE_RXPREAMBLE: // receive p/n sequence symbols gmskframesync_execute_rxpreamble(_q, xf); break; case STATE_RXHEADER: // receive header gmskframesync_execute_rxheader(_q, xf); break; case STATE_RXPAYLOAD: // receive payload gmskframesync_execute_rxpayload(_q, xf); break; } } }
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 gmskframesync_execute_detectframe(gmskframesync _q, float complex _x) { // push sample into pre-demod p/n sequence buffer windowcf_push(_q->buffer, _x); // push through pre-demod synchronizer int detected = detector_cccf_correlate(_q->frame_detector, _x, &_q->tau_hat, &_q->dphi_hat, &_q->gamma_hat); // check if frame has been detected if (detected) { //printf("***** frame detected! tau-hat:%8.4f, dphi-hat:%8.4f, gamma:%8.2f dB\n", // _q->tau_hat, _q->dphi_hat, 20*log10f(_q->gamma_hat)); // push buffered samples through synchronizer // NOTE: state will be updated to STATE_RXPREAMBLE internally gmskframesync_pushpn(_q); } }
// execute synchronizer, seeking p/n sequence // _q : frame synchronizer object // _x : input sample // _sym : demodulated symbol void flexframesync_execute_seekpn(flexframesync _q, float complex _x) { // push sample into pre-demod p/n sequence buffer windowcf_push(_q->buffer, _x); // push through pre-demod synchronizer int detected = detector_cccf_correlate(_q->frame_detector, _x, &_q->tau_hat, &_q->dphi_hat, &_q->gamma_hat); // check if frame has been detected if (detected) { //printf("***** frame detected! tau-hat:%8.4f, dphi-hat:%8.4f, gamma:%8.2f dB\n", // _q->tau_hat, _q->dphi_hat, 20*log10f(_q->gamma_hat)); // push buffered samples through synchronizer // NOTE: this will set internal state appropriately // to STATE_DETECTFRAME flexframesync_pushpn(_q); } }
int main(int argc, char*argv[]) { // options unsigned int num_channels=6; // number of channels (must be even) unsigned int m=4; // filter delay unsigned int num_symbols=4*m; // number of symbols // validate input if (num_channels%2) { fprintf(stderr,"error: %s, number of channels must be even\n", argv[0]); exit(1); } // derived values unsigned int num_samples = num_channels * num_symbols; unsigned int i; unsigned int j; // generate filter // NOTE : these coefficients can be random; the purpose of this // exercise is to demonstrate mathematical equivalence #if 0 unsigned int h_len = 2*m*num_channels; float h[h_len]; for (i=0; i<h_len; i++) h[i] = randnf(); #else unsigned int h_len = 2*m*num_channels+1; float h[h_len]; // NOTE: 81.29528 dB > beta = 8.00000 (6 channels, m=4) liquid_firdes_kaiser(h_len, 1.0f/(float)num_channels, 81.29528f, 0.0f, h); #endif // normalize float hsum = 0.0f; for (i=0; i<h_len; i++) hsum += h[i]; for (i=0; i<h_len; i++) h[i] = h[i] * num_channels / hsum; // sub-sampled filters for M=6 channels, m=4, beta=8.0 // -3.2069e-19 -6.7542e-04 -1.3201e-03 2.2878e-18 3.7613e-03 5.8033e-03 // -7.2899e-18 -1.2305e-02 -1.7147e-02 1.6510e-17 3.1187e-02 4.0974e-02 // -3.0032e-17 -6.8026e-02 -8.6399e-02 4.6273e-17 1.3732e-01 1.7307e-01 // -6.2097e-17 -2.8265e-01 -3.7403e-01 7.3699e-17 8.0663e-01 1.6438e+00 // 2.0001e+00 1.6438e+00 8.0663e-01 7.3699e-17 -3.7403e-01 -2.8265e-01 // -6.2097e-17 1.7307e-01 1.3732e-01 4.6273e-17 -8.6399e-02 -6.8026e-02 // -3.0032e-17 4.0974e-02 3.1187e-02 1.6510e-17 -1.7147e-02 -1.2305e-02 // -7.2899e-18 5.8033e-03 3.7613e-03 2.2878e-18 -1.3201e-03 -6.7542e-04 // create filterbank manually dotprod_crcf dp[num_channels]; // vector dot products windowcf w[num_channels]; // window buffers #if DEBUG // print coefficients printf("h_prototype:\n"); for (i=0; i<h_len; i++) printf(" h[%3u] = %12.8f\n", i, h[i]); #endif // create objects unsigned int h_sub_len = 2*m; float h_sub[h_sub_len]; for (i=0; i<num_channels; i++) { // sub-sample prototype filter #if 0 for (j=0; j<h_sub_len; j++) h_sub[j] = h[j*num_channels+i]; #else // load coefficients in reverse order for (j=0; j<h_sub_len; j++) h_sub[h_sub_len-j-1] = h[j*num_channels+i]; #endif // create window buffer and dotprod objects dp[i] = dotprod_crcf_create(h_sub, h_sub_len); w[i] = windowcf_create(h_sub_len); #if DEBUG printf("h_sub[%u] : \n", i); for (j=0; j<h_sub_len; j++) printf(" h[%3u] = %12.8f\n", j, h_sub[j]); #endif } // generate DFT object float complex x[num_channels]; // time-domain buffer float complex X[num_channels]; // freq-domain buffer #if 1 fftplan fft = fft_create_plan(num_channels, X, x, LIQUID_FFT_BACKWARD, 0); #else fftplan fft = fft_create_plan(num_channels, X, x, LIQUID_FFT_FORWARD, 0); #endif float complex y[num_samples]; // time-domain input float complex Y0[2*num_symbols][num_channels]; // channelizer output float complex Y1[2*num_symbols][num_channels]; // conventional output // generate input sequence for (i=0; i<num_samples; i++) { //y[i] = randnf() * cexpf(_Complex_I*randf()*2*M_PI); y[i] = (i==0) ? 1.0f : 0.0f; y[i] = cexpf(_Complex_I*sqrtf(2.0f)*i*i); printf("y[%3u] = %12.8f + %12.8fj\n", i, crealf(y[i]), cimagf(y[i])); } // // run analysis filter bank // #if 0 unsigned int filter_index = 0; #else unsigned int filter_index = num_channels/2-1; #endif float complex y_hat; // input sample float complex * r; // buffer read pointer int toggle = 0; // flag indicating buffer/filter alignment // for (i=0; i<2*num_symbols; i++) { // load buffers in blocks of num_channels/2 for (j=0; j<num_channels/2; j++) { // grab sample y_hat = y[i*num_channels/2 + j]; // push sample into buffer at filter index windowcf_push(w[filter_index], y_hat); // decrement filter index filter_index = (filter_index + num_channels - 1) % num_channels; //filter_index = (filter_index + 1) % num_channels; } // execute filter outputs // reversing order of output (not sure why this is necessary) unsigned int offset = toggle ? num_channels/2 : 0; toggle = 1-toggle; for (j=0; j<num_channels; j++) { unsigned int buffer_index = (offset+j)%num_channels; unsigned int dotprod_index = j; windowcf_read(w[buffer_index], &r); //dotprod_crcf_execute(dp[dotprod_index], r, &X[num_channels-j-1]); dotprod_crcf_execute(dp[dotprod_index], r, &X[buffer_index]); } printf("***** i = %u\n", i); for (j=0; j<num_channels; j++) printf(" v2[%4u] = %12.8f + %12.8fj\n", j, crealf(X[j]), cimagf(X[j])); // execute DFT, store result in buffer 'x' fft_execute(fft); // scale fft output for (j=0; j<num_channels; j++) x[j] *= 1.0f / (num_channels); // move to output array for (j=0; j<num_channels; j++) Y0[i][j] = x[j]; } // destroy objects for (i=0; i<num_channels; i++) { dotprod_crcf_destroy(dp[i]); windowcf_destroy(w[i]); } fft_destroy_plan(fft); // // run traditional down-converter (inefficient) // // generate filter object firfilt_crcf f = firfilt_crcf_create(h, h_len); float dphi; // carrier frequency unsigned int n=0; for (i=0; i<num_channels; i++) { // reset filter firfilt_crcf_clear(f); // set center frequency dphi = 2.0f * M_PI * (float)i / (float)num_channels; // reset symbol counter n=0; for (j=0; j<num_samples; j++) { // push down-converted sample into filter firfilt_crcf_push(f, y[j]*cexpf(-_Complex_I*j*dphi)); // compute output at the appropriate sample time assert(n<2*num_symbols); if ( ((j+1)%(num_channels/2))==0 ) { firfilt_crcf_execute(f, &Y1[n][i]); n++; } } assert(n==2*num_symbols); } firfilt_crcf_destroy(f); // print filterbank channelizer printf("\n"); printf("filterbank channelizer:\n"); for (i=0; i<2*num_symbols; i++) { printf("%2u:", i); for (j=0; j<num_channels; j++) { printf("%6.3f+%6.3fj, ", crealf(Y0[i][j]), cimagf(Y0[i][j])); } printf("\n"); } #if 0 // print traditional channelizer printf("\n"); printf("traditional channelizer:\n"); for (i=0; i<2*num_symbols; i++) { printf("%2u:", i); for (j=0; j<num_channels; j++) { printf("%6.3f+%6.3fj, ", crealf(Y1[i][j]), cimagf(Y1[i][j])); } printf("\n"); } // // compare results // float mse[num_channels]; float complex d; for (i=0; i<num_channels; i++) { mse[i] = 0.0f; for (j=0; j<2*num_symbols; j++) { d = Y0[j][i] - Y1[j][i]; mse[i] += crealf(d*conjf(d)); } mse[i] /= num_symbols; } printf("\n"); printf(" e:"); for (i=0; i<num_channels; i++) printf("%12.4e ", sqrt(mse[i])); printf("\n"); #endif printf("done.\n"); 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 } } }
// 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); } }
void do_track(){ if (local_track_freq != shm_settings.track_frequency_target) { if (ff.sosMap.count(shm_settings.track_frequency_target)) { //frequency key exists if (track_filterA != NULL) iirfilt_crcf_destroy(track_filterA); if (track_filterB != NULL) iirfilt_crcf_destroy(track_filterB); if (track_filterC != NULL) iirfilt_crcf_destroy(track_filterC); float *b = &((ff.sosMap[shm_settings.track_frequency_target]->b)[0]); float *a = &((ff.sosMap[shm_settings.track_frequency_target]->a)[0]); track_filterA = iirfilt_crcf_create_sos(b,a,NUMBER_OF_SECTIONS); track_filterB = iirfilt_crcf_create_sos(b,a,NUMBER_OF_SECTIONS); track_filterC = iirfilt_crcf_create_sos(b,a,NUMBER_OF_SECTIONS); shm_results_track.track_state = 0; local_track_freq = shm_settings.track_frequency_target; float normalized_frequency = (float) shm_settings.track_frequency_target / (float) SAMPLING_FREQUENCY; nco_crcf_set_frequency(nco,2*M_PI*normalized_frequency); } else { //frequency key does not exist. Trigger error state shm_results_track.track_state = -1; std::cerr << shm_settings.track_frequency_target << " WARN TRACK FREQ NOT IN SOS TABLE" << std::endl; } shm_setg(hydrophones_results_track, shm_results_track); } std::complex<float> *chA_ptr, *chA_filtered_ptr; std::complex<float> *chB_ptr, *chB_filtered_ptr; std::complex<float> *chC_ptr, *chC_filtered_ptr; float *mag_ptr; windowcf_read(wchA,&chA_ptr); windowcf_read(wchB,&chB_ptr); windowcf_read(wchC,&chC_ptr); std::complex<float> filtOutA, filtOutB, filtOutC; for (int i = 0; i < SAMPLING_DEPTH; i++) { iirfilt_crcf_execute(track_filterA,chA_ptr[i],&filtOutA); iirfilt_crcf_execute(track_filterB,chB_ptr[i],&filtOutB); iirfilt_crcf_execute(track_filterC,chC_ptr[i],&filtOutC); windowcf_read(wchA_filtered,&chA_filtered_ptr); windowcf_read(wchB_filtered,&chB_filtered_ptr); windowcf_read(wchC_filtered,&chC_filtered_ptr); windowcf_push(wchA_filtered,filtOutA); windowcf_push(wchB_filtered,filtOutB); windowcf_push(wchC_filtered,filtOutC); float b_sqrd = std::pow(std::real(filtOutB),2); pwr_sum += b_sqrd; windowf_read(wmag_buffer,&mag_ptr); pwr_sum -= mag_ptr[0]; windowf_push(wmag_buffer,b_sqrd); double normalized_pwr = pwr_sum / (double)TRACK_LENGTH; if (normalized_pwr > shm_settings.track_magnitude_threshold && (track_sample_idx - shm_results_track.tracked_ping_time) >= shm_settings.track_cooldown_samples) { std::complex<float> dtft_coeff_A = goertzelNonInteger(chA_filtered_ptr,TRACK_LENGTH,shm_settings.track_frequency_target,SAMPLING_FREQUENCY); std::complex<float> dtft_coeff_B = goertzelNonInteger(chB_filtered_ptr,TRACK_LENGTH,shm_settings.track_frequency_target,SAMPLING_FREQUENCY); std::complex<float> dtft_coeff_C = goertzelNonInteger(chC_filtered_ptr,TRACK_LENGTH,shm_settings.track_frequency_target,SAMPLING_FREQUENCY); float phaseA = std::arg(dtft_coeff_A); float phaseB = std::arg(dtft_coeff_B); float phaseC = std::arg(dtft_coeff_C); shm_results_track.diff_phase_y = phase_difference(phaseC,phaseB); shm_results_track.diff_phase_x = phase_difference(phaseA,phaseB); float kx = SOUND_SPEED * shm_results_track.diff_phase_x / (NIPPLE_DISTANCE * 2 * M_PI * shm_settings.track_frequency_target); float ky = SOUND_SPEED * shm_results_track.diff_phase_y / (NIPPLE_DISTANCE * 2 * M_PI * shm_settings.track_frequency_target); float kz_2 = 1 - kx * kx - ky * ky; if (kz_2 < 0) { std::cerr << "WARNING: z mag is negative! " << kz_2 << std::endl; kz_2 = 0; } shm_results_track.tracked_ping_heading_radians = std::atan2(ky, kx); shm_results_track.tracked_ping_elevation_radians = std::acos(std::sqrt(kz_2)); shm_results_track.tracked_ping_count++; shm_results_track.tracked_ping_frequency = shm_results_spectrum.most_recent_ping_frequency; shm_results_track.tracked_ping_time = track_sample_idx; std::cout << "PING DETECTED @ n=" << track_sample_idx << " w/ pwr="<< normalized_pwr<< std::endl; std::cout << "@ HEADING=" << shm_results_track.tracked_ping_heading_radians*(180.0f/M_PI) << std::endl; shm_setg(hydrophones_results_track, shm_results_track); } track_sample_idx++; } }
int main() { // options unsigned int num_channels=4; // number of channels unsigned int m=5; // filter delay unsigned int num_symbols=12; // number of symbols // derived values unsigned int num_samples = num_channels * num_symbols; unsigned int i; unsigned int j; // generate filter // NOTE : these coefficients can be random; the purpose of this // exercise is to demonstrate mathematical equivalence unsigned int h_len = 2*m*num_channels; float h[h_len]; for (i=0; i<h_len; i++) h[i] = randnf(); //for (i=0; i<h_len; i++) h[i] = 0.1f*i; //for (i=0; i<h_len; i++) h[i] = (i<=m) ? 1.0f : 0.0f; //for (i=0; i<h_len; i++) h[i] = 1.0f; // create filterbank manually dotprod_crcf dp[num_channels]; // vector dot products windowcf w[num_channels]; // window buffers #if DEBUG // print coefficients printf("h_prototype:\n"); for (i=0; i<h_len; i++) printf(" h[%3u] = %12.8f\n", i, h[i]); #endif // create objects unsigned int h_sub_len = 2*m; float h_sub[h_sub_len]; for (i=0; i<num_channels; i++) { // sub-sample prototype filter, loading coefficients in // reverse order #if 0 for (j=0; j<h_sub_len; j++) h_sub[j] = h[j*num_channels+i]; #else for (j=0; j<h_sub_len; j++) h_sub[h_sub_len-j-1] = h[j*num_channels+i]; #endif // create window buffer and dotprod objects dp[i] = dotprod_crcf_create(h_sub, h_sub_len); w[i] = windowcf_create(h_sub_len); #if DEBUG printf("h_sub[%u] : \n", i); for (j=0; j<h_sub_len; j++) printf(" h[%3u] = %12.8f\n", j, h_sub[j]); #endif } // generate DFT object float complex x[num_channels]; // time-domain buffer float complex X[num_channels]; // freq-domain buffer #if 0 fftplan fft = fft_create_plan(num_channels, X, x, LIQUID_FFT_BACKWARD, 0); #else fftplan fft = fft_create_plan(num_channels, X, x, LIQUID_FFT_FORWARD, 0); #endif // generate filter object firfilt_crcf f = firfilt_crcf_create(h, h_len); float complex y[num_samples]; // time-domain input float complex Y0[num_symbols][num_channels]; // channelized output float complex Y1[num_symbols][num_channels]; // channelized output // generate input sequence (complex noise) for (i=0; i<num_samples; i++) y[i] = randnf() * cexpf(_Complex_I*randf()*2*M_PI); // // run analysis filter bank // #if 0 unsigned int filter_index = 0; #else unsigned int filter_index = num_channels-1; #endif float complex y_hat; // input sample float complex * r; // read pointer for (i=0; i<num_symbols; i++) { // load buffers for (j=0; j<num_channels; j++) { // grab sample y_hat = y[i*num_channels + j]; // push sample into buffer at filter index windowcf_push(w[filter_index], y_hat); // decrement filter index filter_index = (filter_index + num_channels - 1) % num_channels; //filter_index = (filter_index + 1) % num_channels; } // execute filter outputs, reversing order of output (not // sure why this is necessary) for (j=0; j<num_channels; j++) { windowcf_read(w[j], &r); dotprod_crcf_execute(dp[j], r, &X[num_channels-j-1]); } // execute DFT, store result in buffer 'x' fft_execute(fft); // move to output array for (j=0; j<num_channels; j++) Y0[i][j] = x[j]; } // // run traditional down-converter (inefficient) // float dphi; // carrier frequency unsigned int n=0; for (i=0; i<num_channels; i++) { // reset filter firfilt_crcf_reset(f); // set center frequency dphi = 2.0f * M_PI * (float)i / (float)num_channels; // reset symbol counter n=0; for (j=0; j<num_samples; j++) { // push down-converted sample into filter firfilt_crcf_push(f, y[j]*cexpf(-_Complex_I*j*dphi)); // compute output at the appropriate sample time assert(n<num_symbols); if ( ((j+1)%num_channels)==0 ) { firfilt_crcf_execute(f, &Y1[n][i]); n++; } } assert(n==num_symbols); } // destroy objects for (i=0; i<num_channels; i++) { dotprod_crcf_destroy(dp[i]); windowcf_destroy(w[i]); } fft_destroy_plan(fft); firfilt_crcf_destroy(f); // print filterbank channelizer printf("\n"); printf("filterbank channelizer:\n"); for (i=0; i<num_symbols; i++) { printf("%3u: ", i); for (j=0; j<num_channels; j++) { printf(" %8.5f+j%8.5f, ", crealf(Y0[i][j]), cimagf(Y0[i][j])); } printf("\n"); } // print traditional channelizer printf("\n"); printf("traditional channelizer:\n"); for (i=0; i<num_symbols; i++) { printf("%3u: ", i); for (j=0; j<num_channels; j++) { printf(" %8.5f+j%8.5f, ", crealf(Y1[i][j]), cimagf(Y1[i][j])); } printf("\n"); } // // compare results // float mse[num_channels]; float complex d; for (i=0; i<num_channels; i++) { mse[i] = 0.0f; for (j=0; j<num_symbols; j++) { d = Y0[j][i] - Y1[j][i]; mse[i] += crealf(d*conjf(d)); } mse[i] /= num_symbols; } printf("\n"); printf("rmse: "); for (i=0; i<num_channels; i++) printf("%12.4e ", sqrt(mse[i])); printf("\n"); printf("done.\n"); return 0; }
int main() { // options unsigned int num_channels=64; // must be even number unsigned int num_symbols=16; // number of symbols unsigned int m=3; // filter delay (symbols) float beta = 0.9f; // filter excess bandwidth factor float phi = 0.0f; // carrier phase offset; float dphi = 0.04f; // carrier frequency offset // number of frames (compensate for filter delay) unsigned int num_frames = num_symbols + 2*m; unsigned int num_samples = num_channels * num_frames; unsigned int i; unsigned int j; // create filter prototype unsigned int h_len = 2*num_channels*m + 1; float h[h_len]; float complex hc[h_len]; float complex gc[h_len]; liquid_firdes_rkaiser(num_channels, m, beta, 0.0f, h); unsigned int g_len = 2*num_channels*m; for (i=0; i<g_len; i++) { hc[i] = h[i]; gc[i] = h[g_len-i-1] * cexpf(_Complex_I*dphi*i); } // data arrays float complex s[num_channels]; // input symbols float complex y[num_samples]; // time-domain samples float complex Y0[num_frames][num_channels]; // channelized output float complex Y1[num_frames][num_channels]; // channelized output // create ofdm/oqam generator object and generate data ofdmoqam qs = ofdmoqam_create(num_channels, m, beta, 0.0f, LIQUID_SYNTHESIZER, 0); for (i=0; i<num_frames; i++) { for (j=0; j<num_channels; j++) { if (i<num_symbols) { #if 0 // QPSK on all subcarriers s[j] = (rand() % 2 ? 1.0f : -1.0f) + (rand() % 2 ? 1.0f : -1.0f) * _Complex_I; s[j] *= 1.0f / sqrtf(2.0f); #else // BPSK on even subcarriers s[j] = rand() % 2 ? 1.0f : -1.0f; s[j] *= (j%2)==0 ? 1.0f : 0.0f; #endif } else { s[j] = 0.0f; } } // run synthesizer ofdmoqam_execute(qs, s, &y[i*num_channels]); } ofdmoqam_destroy(qs); // channel for (i=0; i<num_samples; i++) y[i] *= cexpf(_Complex_I*(phi + dphi*i)); // // analysis filterbank (receiver) // // create filterbank manually dotprod_cccf dp[num_channels]; // vector dot products windowcf w[num_channels]; // window buffers #if DEBUG // print coefficients printf("h_prototype:\n"); for (i=0; i<h_len; i++) printf(" h[%3u] = %12.8f\n", i, h[i]); #endif // create objects unsigned int gc_sub_len = 2*m; float complex gc_sub[gc_sub_len]; for (i=0; i<num_channels; i++) { // sub-sample prototype filter, loading coefficients in // reverse order #if 0 for (j=0; j<gc_sub_len; j++) gc_sub[j] = h[j*num_channels+i]; #else for (j=0; j<gc_sub_len; j++) gc_sub[gc_sub_len-j-1] = gc[j*num_channels+i]; #endif // create window buffer and dotprod objects dp[i] = dotprod_cccf_create(gc_sub, gc_sub_len); w[i] = windowcf_create(gc_sub_len); #if DEBUG printf("gc_sub[%u] : \n", i); for (j=0; j<gc_sub_len; j++) printf(" g[%3u] = %12.8f + %12.8f\n", j, crealf(gc_sub[j]), cimagf(gc_sub[j])); #endif } // generate DFT object float complex x[num_channels]; // time-domain buffer float complex X[num_channels]; // freq-domain buffer #if 0 fftplan fft = fft_create_plan(num_channels, X, x, FFT_REVERSE, 0); #else fftplan fft = fft_create_plan(num_channels, X, x, FFT_FORWARD, 0); #endif // // run analysis filter bank // #if 0 unsigned int filter_index = 0; #else unsigned int filter_index = num_channels-1; #endif float complex y_hat; // input sample float complex * r; // read pointer for (i=0; i<num_frames; i++) { // load buffers for (j=0; j<num_channels; j++) { // grab sample y_hat = y[i*num_channels + j]; // push sample into buffer at filter index windowcf_push(w[filter_index], y_hat); // decrement filter index filter_index = (filter_index + num_channels - 1) % num_channels; //filter_index = (filter_index + 1) % num_channels; } // execute filter outputs, reversing order of output (not // sure why this is necessary) for (j=0; j<num_channels; j++) { windowcf_read(w[j], &r); dotprod_cccf_execute(dp[j], r, &X[num_channels-j-1]); } #if 1 // compensate for carrier frequency offset (before transform) for (j=0; j<num_channels; j++) { X[j] *= cexpf(-_Complex_I*(dphi*i*num_channels)); } #endif // execute DFT, store result in buffer 'x' fft_execute(fft); #if 0 // compensate for carrier frequency offset (after transform) for (j=0; j<num_channels; j++) { x[j] *= cexpf(-_Complex_I*(dphi*i*num_channels)); } #endif // move to output array for (j=0; j<num_channels; j++) Y0[i][j] = x[j]; } // destroy objects for (i=0; i<num_channels; i++) { dotprod_cccf_destroy(dp[i]); windowcf_destroy(w[i]); } fft_destroy_plan(fft); #if 0 // print filterbank channelizer printf("\n"); printf("filterbank channelizer:\n"); for (i=0; i<num_symbols; i++) { printf("%3u: ", i); for (j=0; j<num_channels; j++) { printf(" %8.5f+j%8.5f, ", crealf(Y0[i][j]), cimagf(Y0[i][j])); } printf("\n"); } #endif // // export data // 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_symbols=%u;\n", num_symbols); fprintf(fid,"num_frames = %u;\n", num_frames); fprintf(fid,"num_samples = num_frames*num_channels;\n"); fprintf(fid,"y = zeros(1,%u);\n", num_samples); fprintf(fid,"Y0 = zeros(%u,%u);\n", num_frames, num_channels); fprintf(fid,"Y1 = zeros(%u,%u);\n", num_frames, num_channels); for (i=0; i<num_frames; i++) { for (j=0; j<num_channels; j++) { fprintf(fid,"Y0(%4u,%4u) = %12.4e + j*%12.4e;\n", i+1, j+1, crealf(Y0[i][j]), cimagf(Y0[i][j])); fprintf(fid,"Y1(%4u,%4u) = %12.4e + j*%12.4e;\n", i+1, j+1, crealf(Y1[i][j]), cimagf(Y1[i][j])); } } // plot BPSK results fprintf(fid,"figure;\n"); fprintf(fid,"plot(Y0(:,1:2:end),'x');\n"); fprintf(fid,"axis([-1 1 -1 1]*1.2*sqrt(num_channels));\n"); fprintf(fid,"axis square;\n"); fprintf(fid,"grid on;\n"); fclose(fid); printf("results written to '%s'\n", OUTPUT_FILENAME); printf("done.\n"); return 0; }
// compute ISI for entire system // _gt : transmit filter [size: _gt_len x 1] // _hc : channel filter [size: _hc_len x 1] // _gr : receive filter [size: _gr_len x 1] float eqlms_cccf_isi(unsigned int _k, float complex * _gt, unsigned int _gt_len, float complex * _hc, unsigned int _hc_len, float complex * _gr, unsigned int _gr_len) { // generate composite by convolving all filters together unsigned int i; #if 0 printf("\n"); for (i=0; i<_gt_len; i++) printf(" gt(%3u) = %16.12f + j*%16.12f;\n", i+1, crealf(_gt[i]), cimagf(_gt[i])); printf("\n"); for (i=0; i<_hc_len; i++) printf(" hc(%3u) = %16.12f + j*%16.12f;\n", i+1, crealf(_hc[i]), cimagf(_hc[i])); printf("\n"); for (i=0; i<_gr_len; i++) printf(" gr(%3u) = %16.12f + j*%16.12f;\n", i+1, crealf(_gr[i]), cimagf(_gr[i])); printf("\n"); #endif windowcf w; float complex * rc; // start by convolving transmit and channel filters unsigned int gthc_len = _gt_len + _hc_len - 1; float complex gthc[gthc_len]; w = windowcf_create(_gt_len); for (i=0; i<gthc_len; i++) { if (i < _hc_len) windowcf_push(w, conjf(_hc[_hc_len-i-1])); else windowcf_push(w, 0.0f); windowcf_read(w, &rc); dotprod_cccf_run(_gt, rc, _gt_len, >hc[i]); } windowcf_destroy(w); #if 0 printf("composite filter:\n"); for (i=0; i<gthc_len; i++) printf(" gthc(%3u) = %16.12f + j*%16.12f;\n", i+1, crealf(gthc[i]), cimagf(gthc[i])); #endif // convolve result with equalizer unsigned int h_len = gthc_len + _gr_len - 1; float complex h[h_len]; w = windowcf_create(gthc_len); for (i=0; i<h_len; i++) { if (i < _gr_len) windowcf_push(w, conjf(_gr[i])); else windowcf_push(w, 0.0f); windowcf_read(w, &rc); dotprod_cccf_run(gthc, rc, gthc_len, &h[i]); } windowcf_destroy(w); #if 0 printf("composite filter:\n"); for (i=0; i<h_len; i++) printf(" h(%3u) = %16.12f + j*%16.12f;\n", i+1, crealf(h[i]), cimagf(h[i])); #endif // compute resulting ISI unsigned int n0 = (_gt_len + _gr_len + (_gt_len + _gr_len)%2)/2 - 1; float isi = 0.0f; unsigned int n=0; for (i=0; i<h_len; i++) { if (i == n0) continue; else if ( (i%_k)==0 ) { isi += crealf( h[i]*conjf(h[i]) ); n++; } } isi /= crealf( h[n0]*conjf(h[n0]) ); isi = sqrtf(isi / (float)n); return isi; }