// Helper function to keep code base small void window_read_bench(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations, unsigned int _n) { // normalize number of iterations if (*_num_iterations < 1) *_num_iterations = 1; // initialize port windowcf w = windowcf_create(_n); unsigned long int i; float complex * r; // start trials: // write to buffer, read from buffer getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { windowcf_push(w,1.0f); windowcf_read(w, &r); windowcf_push(w,1.0f); windowcf_read(w, &r); windowcf_push(w,1.0f); windowcf_read(w, &r); windowcf_push(w,1.0f); windowcf_read(w, &r); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; windowcf_destroy(w); }
// frame detection void wlanframesync_execute_rxshort0(wlanframesync _q) { _q->timer++; if (_q->timer < 16) return; // reset timer _q->timer = 0; // read contents of input buffer float complex * rc; windowcf_read(_q->input_buffer, &rc); // re-estimate S0 gain wlanframesync_estimate_gain_S0(_q, &rc[16], _q->G0a); float complex s_hat; wlanframesync_S0_metrics(_q, _q->G0a, &s_hat); //float g = agc_crcf_get_gain(_q->agc_rx); s_hat *= _q->g0; // save first 'short' symbol statistic _q->s0a_hat = s_hat; #if DEBUG_WLANFRAMESYNC_PRINT float tau_hat = cargf(s_hat) * 16.0f / (2*M_PI); printf("********** S0[a] received ************\n"); printf(" s_hat : %12.8f <%12.8f>\n", cabsf(s_hat), cargf(s_hat)); printf(" tau_hat : %12.8f\n", tau_hat); #endif _q->state = WLANFRAMESYNC_STATE_RXSHORT1; }
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; } }
// frame detection void wlanframesync_execute_rxshort1(wlanframesync _q) { _q->timer++; if (_q->timer < 16) return; // reset timer _q->timer = 0; // read contents of input buffer float complex * rc; windowcf_read(_q->input_buffer, &rc); // estimate S0 gain wlanframesync_estimate_gain_S0(_q, &rc[16], _q->G0b); float complex s_hat; wlanframesync_S0_metrics(_q, _q->G0b, &s_hat); //float g = agc_crcf_get_gain(_q->agc_rx); s_hat *= _q->g0; // save second 'short' symbol statistic _q->s0b_hat = s_hat; #if DEBUG_WLANFRAMESYNC_PRINT float tau_hat = cargf(s_hat) * 16.0f / (2*M_PI); printf("********** S0[b] received ************\n"); printf(" s_hat : %12.8f <%12.8f>\n", cabsf(s_hat), cargf(s_hat)); printf(" tau_hat : %12.8f\n", tau_hat); // new timing offset estimate tau_hat = cargf(_q->s0a_hat + _q->s0b_hat) * 16.0f / (2*M_PI); printf(" tau_hat * : %12.8f\n", tau_hat); #endif #if 0 // compute carrier frequency offset estimate using ML method float complex t0 = 0.0f; for (i=0; i<48; i++) { t0 += conjf(rc[i]) * wlanframe_s0[i] * rc[i+16] * conjf(wlanframe_s0[i+16]); } float nu_hat = cargf(t0) / (float)(_q->M2); #else // compute carrier frequency offset estimate using freq. domain method float nu_hat = wlanframesync_estimate_cfo_S0(_q->G0a, _q->G0b); #endif // set NCO frequency nco_crcf_set_frequency(_q->nco_rx, nu_hat); #if DEBUG_WLANFRAMESYNC_PRINT printf(" nu_hat[0]: %12.8f\n", nu_hat); #endif // set state _q->state = WLANFRAMESYNC_STATE_RXLONG0; }
void wlanframesync_execute_rxlong0(wlanframesync _q) { // set timer to 16, wait for phase to be relatively small _q->timer++; if (_q->timer < 16) return; // reset timer _q->timer = 0; // run fft float complex * rc; windowcf_read(_q->input_buffer, &rc); // estimate S1 gain, adding backoff in gain estimation wlanframesync_estimate_gain_S1(_q, &rc[16-2], _q->G1a); // compute S1 metrics float complex s_hat; wlanframesync_S1_metrics(_q, _q->G1a, &s_hat); s_hat *= _q->g0; // scale output by raw gain estimate // rotate by complex phasor relative to timing backoff //s_hat *= cexpf(_Complex_I * 2.0f * 2.0f * M_PI / 64.0f); s_hat *= cexpf(_Complex_I * 0.19635f); // save first 'long' symbol statistic _q->s1a_hat = s_hat; #if DEBUG_WLANFRAMESYNC_PRINT printf(" s_hat : %12.8f <%12.8f>\n", cabsf(s_hat), cargf(s_hat)); #endif float s_hat_abs = cabsf(s_hat); float s_hat_arg = cargf(s_hat); if (s_hat_arg > M_PI) s_hat_arg -= 2.0f*M_PI; if (s_hat_arg < -M_PI) s_hat_arg += 2.0f*M_PI; // check conditions for s_hat: // 1. magnitude should be large (near unity) when aligned // 2. phase should be very near zero (time aligned) if (s_hat_abs > WLANFRAMESYNC_S1A_ABS_THRESH && fabsf(s_hat_arg) < WLANFRAMESYNC_S1A_ARG_THRESH) { #if DEBUG_WLANFRAMESYNC_PRINT printf(" acquisition S1[a]\n"); #endif // set state _q->state = WLANFRAMESYNC_STATE_RXLONG1; // reset timer _q->timer = 0; } }
// export debugging file void ampmodem_debug_print(ampmodem _q, const char * _filename) { FILE * fid = fopen(_filename,"w"); if (!fid) { fprintf(stderr,"error: ofdmframe_debug_print(), could not open '%s' for writing\n", _filename); return; } fprintf(fid,"%% %s : auto-generated file\n", DEBUG_AMPMODEM_FILENAME); #if DEBUG_AMPMODEM fprintf(fid,"close all;\n"); fprintf(fid,"clear all;\n"); fprintf(fid,"n = %u;\n", DEBUG_AMPMODEM_BUFFER_LEN); unsigned int i; float complex * rc; float * r; // plot received signal fprintf(fid,"x = zeros(1,n);\n"); windowcf_read(_q->debug_x, &rc); for (i=0; i<DEBUG_AMPMODEM_BUFFER_LEN; i++) fprintf(fid,"x(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(rc[i]), cimagf(rc[i])); fprintf(fid,"figure;\n"); fprintf(fid,"plot(0:(n-1),real(x),0:(n-1),imag(x));\n"); fprintf(fid,"xlabel('sample index');\n"); fprintf(fid,"ylabel('received signal, x');\n"); // plot phase/freq error fprintf(fid,"phase_error = zeros(1,n);\n"); windowf_read(_q->debug_phase_error, &r); for (i=0; i<DEBUG_AMPMODEM_BUFFER_LEN; i++) fprintf(fid,"phase_error(%4u) = %12.4e;\n", i+1, r[i]); fprintf(fid,"freq_error = zeros(1,n);\n"); windowf_read(_q->debug_freq_error, &r); for (i=0; i<DEBUG_AMPMODEM_BUFFER_LEN; i++) fprintf(fid,"freq_error(%4u) = %12.4e;\n", i+1, r[i]); fprintf(fid,"figure;\n"); fprintf(fid,"subplot(2,1,1),\n"); fprintf(fid," plot(0:(n-1),phase_error);\n"); fprintf(fid," xlabel('sample index');\n"); fprintf(fid," ylabel('phase error');\n"); fprintf(fid,"subplot(2,1,2),\n"); fprintf(fid," plot(0:(n-1),freq_error);\n"); fprintf(fid," xlabel('sample index');\n"); fprintf(fid," ylabel('freq error');\n"); #else fprintf(fid,"disp('no debugging info available');\n"); #endif fclose(fid); printf("ampmodem/debug: results written to '%s'\n", _filename); }
// 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; }
// frame detection void ofdmframesync_execute_S0a(ofdmframesync _q) { //printf("t : %u\n", _q->timer); _q->timer++; if (_q->timer < _q->M2) return; // reset timer _q->timer = 0; // float complex * rc; windowcf_read(_q->input_buffer, &rc); // TODO : re-estimate nominal gain // estimate S0 gain ofdmframesync_estimate_gain_S0(_q, &rc[_q->cp_len], _q->G0); float complex s_hat; ofdmframesync_S0_metrics(_q, _q->G0, &s_hat); s_hat *= _q->g0; _q->s_hat_0 = s_hat; #if DEBUG_OFDMFRAMESYNC_PRINT float tau_hat = cargf(s_hat) * (float)(_q->M2) / (2*M_PI); printf("********** S0[0] received ************\n"); printf(" s_hat : %12.8f <%12.8f>\n", cabsf(s_hat), cargf(s_hat)); printf(" tau_hat : %12.8f\n", tau_hat); #endif #if 0 // TODO : also check for phase of s_hat (should be small) if (cabsf(s_hat) < 0.3f) { // false alarm #if DEBUG_OFDMFRAMESYNC_PRINT printf("false alarm S0[0]\n"); #endif ofdmframesync_reset(_q); return; } #endif _q->state = OFDMFRAMESYNC_STATE_PLCPSHORT1; }
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; } }
void do_spectrum() { std::complex<float> *data_in; windowcf_read(w, &data_in); fftplan q = fft_create_plan(SPECTRUM_FFT_LENGTH,data_in,spectrum_fft_output,LIQUID_FFT_FORWARD,0); fft_execute(q); fft_destroy_plan(q); spectrum_fft_magnitude[0] = 0.0; //Do not consider DC comp int maxIdx = 0; float maxVal = 0; double total_power = 0; double psd = 0; for (int i = 1; i < SPECTRUM_FFT_LENGTH/2; i++) { spectrum_fft_magnitude[i] = std::norm(spectrum_fft_output[i]); total_power += spectrum_fft_magnitude[i]; if (spectrum_fft_magnitude[i] > maxVal) { maxIdx = i; maxVal = spectrum_fft_magnitude[i]; } } // TODO normalize so window size does not affect this threshold. psd = maxVal / total_power; if (shm_settings.auto_magnitude_thresholding == 0) { if (psd > shm_settings.spectrum_magnitude_threshold && (current_sample_count - old_spectrum_sample_count > shm_settings.spectrum_cooldown_samples)) { shm_results_spectrum.most_recent_ping_magnitude = maxVal; shm_results_spectrum.most_recent_ping_frequency = (double) SAMPLING_FREQUENCY / (double) SPECTRUM_FFT_LENGTH * (double) maxIdx; shm_results_spectrum.most_recent_ping_count++; old_spectrum_sample_count = current_sample_count; shm_setg(hydrophones_results_spectrum, shm_results_spectrum); } prev_psd = psd; } else { //IMPLEMENTE AUTO THRESHOLDING AND ASSOCIATED PING STUFF } }
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 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++; } }
// 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; }
int main(int argc, char*argv[]) { // options int ftype = LIQUID_FIRFILT_ARKAISER; int ms = LIQUID_MODEM_QPSK; unsigned int k = 2; // samples per symbol unsigned int m = 7; // filter delay (symbols) float beta = 0.20f; // filter excess bandwidth factor unsigned int num_symbols = 4000; // number of data symbols unsigned int hc_len = 4; // channel filter length float noise_floor = -60.0f; // noise floor [dB] float SNRdB = 30.0f; // signal-to-noise ratio [dB] float bandwidth = 0.02f; // loop filter bandwidth float tau = -0.2f; // fractional symbol offset float rate = 1.001f; // sample rate offset float dphi = 0.01f; // carrier frequency offset [radians/sample] float phi = 2.1f; // carrier phase offset [radians] unsigned int nfft = 2400; // spectral periodogram FFT size unsigned int num_samples = 200000; // number of samples int dopt; while ((dopt = getopt(argc,argv,"hk:m:b:s:w:n:t:r:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'b': beta = atof(optarg); break; case 's': SNRdB = atof(optarg); break; case 'w': bandwidth = atof(optarg); break; case 'n': num_symbols = atoi(optarg); break; case 't': tau = atof(optarg); break; case 'r': rate = atof(optarg); break; default: exit(1); } } // validate input if (k < 2) { fprintf(stderr,"error: k (samples/symbol) must be greater than 1\n"); exit(1); } else if (m < 1) { fprintf(stderr,"error: m (filter delay) must be greater than 0\n"); exit(1); } else if (beta <= 0.0f || beta > 1.0f) { fprintf(stderr,"error: beta (excess bandwidth factor) must be in (0,1]\n"); exit(1); } else if (bandwidth <= 0.0f) { fprintf(stderr,"error: timing PLL bandwidth must be greater than 0\n"); exit(1); } else if (num_symbols == 0) { fprintf(stderr,"error: number of symbols must be greater than 0\n"); exit(1); } else if (tau < -1.0f || tau > 1.0f) { fprintf(stderr,"error: timing phase offset must be in [-1,1]\n"); exit(1); } else if (rate > 1.02f || rate < 0.98f) { fprintf(stderr,"error: timing rate offset must be in [1.02,0.98]\n"); exit(1); } unsigned int i; // buffers unsigned int buf_len = 400; // buffer size float complex x [buf_len]; // original signal float complex y [buf_len*2]; // channel output (larger to accommodate resampler) float complex syms[buf_len]; // recovered symbols // window for saving last few symbols windowcf sym_buf = windowcf_create(buf_len); // create stream generator symstreamcf gen = symstreamcf_create_linear(ftype,k,m,beta,ms); // create channel emulator and add impairments channel_cccf channel = channel_cccf_create(); channel_cccf_add_awgn (channel, noise_floor, SNRdB); channel_cccf_add_carrier_offset(channel, dphi, phi); channel_cccf_add_multipath (channel, NULL, hc_len); channel_cccf_add_resamp (channel, 0.0f, rate); // create symbol tracking synchronizer symtrack_cccf symtrack = symtrack_cccf_create(ftype,k,m,beta,ms); symtrack_cccf_set_bandwidth(symtrack,0.05f); // create spectral periodogram for estimating spectrum spgramcf periodogram = spgramcf_create_default(nfft); unsigned int total_samples = 0; unsigned int ny; unsigned int total_symbols = 0; while (total_samples < num_samples) { // write samples to buffer symstreamcf_write_samples(gen, x, buf_len); // apply channel channel_cccf_execute(channel, x, buf_len, y, &ny); // push resulting sample through periodogram spgramcf_write(periodogram, y, ny); // run resulting stream through synchronizer unsigned int num_symbols_sync; symtrack_cccf_execute_block(symtrack, y, ny, syms, &num_symbols_sync); total_symbols += num_symbols_sync; // write resulting symbols to window buffer for plotting windowcf_write(sym_buf, syms, num_symbols_sync); // accumulated samples total_samples += buf_len; } printf("total samples: %u\n", total_samples); printf("total symbols: %u\n", total_symbols); // write accumulated power spectral density estimate float psd[nfft]; spgramcf_get_psd(periodogram, psd); // // export output file // FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s, auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n"); // read buffer and write last symbols to file float complex * rc; windowcf_read(sym_buf, &rc); fprintf(fid,"syms = zeros(1,%u);\n", buf_len); for (i=0; i<buf_len; i++) fprintf(fid,"syms(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(rc[i]), cimagf(rc[i])); // power spectral density estimate fprintf(fid,"nfft = %u;\n", nfft); fprintf(fid,"f=[0:(nfft-1)]/nfft - 0.5;\n"); fprintf(fid,"psd = zeros(1,nfft);\n"); for (i=0; i<nfft; i++) fprintf(fid,"psd(%3u) = %12.8f;\n", i+1, psd[i]); fprintf(fid,"figure('Color','white','position',[500 500 1400 400]);\n"); fprintf(fid,"subplot(1,3,1);\n"); fprintf(fid,"plot(real(syms),imag(syms),'x','MarkerSize',4);\n"); fprintf(fid," axis square;\n"); fprintf(fid," grid on;\n"); fprintf(fid," axis([-1 1 -1 1]*1.6);\n"); fprintf(fid," xlabel('In-phase');\n"); fprintf(fid," ylabel('Quadrature');\n"); fprintf(fid," title('Last %u symbols');\n", buf_len); fprintf(fid,"subplot(1,3,2:3);\n"); fprintf(fid," plot(f, psd, 'LineWidth',1.5,'Color',[0 0.5 0.2]);\n"); fprintf(fid," grid on;\n"); fprintf(fid," pmin = 10*floor(0.1*min(psd - 5));\n"); fprintf(fid," pmax = 10*ceil (0.1*max(psd + 5));\n"); fprintf(fid," axis([-0.5 0.5 pmin pmax]);\n"); fprintf(fid," xlabel('Normalized Frequency [f/F_s]');\n"); fprintf(fid," ylabel('Power Spectral Density [dB]');\n"); fclose(fid); printf("results written to %s.\n", OUTPUT_FILENAME); // destroy objects symstreamcf_destroy (gen); spgramcf_destroy (periodogram); channel_cccf_destroy (channel); symtrack_cccf_destroy(symtrack); windowcf_destroy (sym_buf); // clean it up printf("done.\n"); return 0; }
void ofdmoqamframe64sync_debug_print(ofdmoqamframe64sync _q) { FILE * fid = fopen(DEBUG_OFDMOQAMFRAME64SYNC_FILENAME,"w"); if (!fid) { printf("error: ofdmoqamframe64_debug_print(), could not open file for writing\n"); return; } fprintf(fid,"%% %s : auto-generated file\n", DEBUG_OFDMOQAMFRAME64SYNC_FILENAME); fprintf(fid,"close all;\n"); fprintf(fid,"clear all;\n"); fprintf(fid,"n = %u;\n", DEBUG_OFDMOQAMFRAME64SYNC_BUFFER_LEN); unsigned int i; float complex * rc; float * r; // gain vectors fprintf(fid,"g = %12.4e;\n", _q->g); for (i=0; i<_q->num_subcarriers; i++) { fprintf(fid,"G(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(_q->G[i]), cimagf(_q->G[i])); //fprintf(fid,"G0(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(_q->G0[i]), cimagf(_q->G0[i])); //fprintf(fid,"G1(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(_q->G1[i]), cimagf(_q->G1[i])); } for (i=0; i<4; i++) { fprintf(fid,"phi(%3u) = %12.8f;\n", i+1, _q->y_phase[i]); } fprintf(fid,"figure;\n"); fprintf(fid,"f = -32:31;\n"); fprintf(fid,"subplot(2,1,1);\n"); fprintf(fid," plot(f,fftshift(abs(G)));\n"); fprintf(fid," xlabel('subcarrier index');\n"); fprintf(fid," ylabel('|G|');\n"); fprintf(fid," grid on;\n"); fprintf(fid,"subplot(2,1,2);\n"); fprintf(fid," plot(f,fftshift(arg(G)));\n"); fprintf(fid," xlabel('subcarrier index');\n"); fprintf(fid," ylabel('arg\\{G\\}');\n"); fprintf(fid," grid on;\n"); // CFO estimate fprintf(fid,"nu_hat = %12.4e;\n", _q->nu_hat); // short, long, training sequences for (i=0; i<_q->num_subcarriers; i++) { fprintf(fid,"S0(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(_q->S0[i]), cimagf(_q->S0[i])); fprintf(fid,"S1(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(_q->S1[i]), cimagf(_q->S1[i])); fprintf(fid,"S2(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(_q->S2[i]), cimagf(_q->S2[i])); } fprintf(fid,"x = zeros(1,n);\n"); windowcf_read(_q->debug_x, &rc); for (i=0; i<DEBUG_OFDMOQAMFRAME64SYNC_BUFFER_LEN; i++) fprintf(fid,"x(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(rc[i]), cimagf(rc[i])); fprintf(fid,"figure;\n"); fprintf(fid,"plot(0:(n-1),real(x),0:(n-1),imag(x));\n"); fprintf(fid,"xlabel('sample index');\n"); fprintf(fid,"ylabel('received signal, x');\n"); fprintf(fid,"rxx = zeros(1,n);\n"); windowcf_read(_q->debug_rxx, &rc); for (i=0; i<DEBUG_OFDMOQAMFRAME64SYNC_BUFFER_LEN; i++) fprintf(fid,"rxx(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(rc[i]), cimagf(rc[i])); fprintf(fid,"figure;\n"); fprintf(fid,"plot(0:(n-1),abs(rxx),'-k','LineWidth',2);\n"); fprintf(fid,"xlabel('sample index');\n"); fprintf(fid,"ylabel('|r_{xx}|');\n"); fprintf(fid,"rxy = zeros(1,n);\n"); windowcf_read(_q->debug_rxy, &rc); for (i=0; i<DEBUG_OFDMOQAMFRAME64SYNC_BUFFER_LEN; i++) fprintf(fid,"rxy(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(rc[i]), cimagf(rc[i])); fprintf(fid,"figure;\n"); fprintf(fid,"plot(0:(n-1),abs(rxy));\n"); fprintf(fid,"xlabel('sample index');\n"); fprintf(fid,"ylabel('|r_{xy}|');\n"); // decoded long sequences fprintf(fid,"S1 = zeros(1,64);\n"); fprintf(fid,"S1a = zeros(1,64);\n"); fprintf(fid,"S1b = zeros(1,64);\n"); fprintf(fid,"Y0 = zeros(1,64);\n"); fprintf(fid,"Y1 = zeros(1,64);\n"); for (i=0; i<64; i++) { fprintf(fid,"S1(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(_q->S1[i]), cimagf(_q->S1[i])); fprintf(fid,"S1a(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(_q->S1a[i]), cimagf(_q->S1a[i])); fprintf(fid,"S1b(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(_q->S1b[i]), cimagf(_q->S1b[i])); fprintf(fid,"Y0(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(_q->Y0[i]), cimagf(_q->Y0[i])); fprintf(fid,"Y1(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(_q->Y1[i]), cimagf(_q->Y1[i])); } fprintf(fid,"zeta = 64/sqrt(52/2);\n"); fprintf(fid,"S1 = S1 / zeta;\n"); fprintf(fid,"S1a = S1a / zeta;\n"); fprintf(fid,"S1b = S1b / zeta;\n"); fprintf(fid,"Y0 = Y0 / zeta;\n"); fprintf(fid,"Y1 = Y1 / zeta;\n"); fprintf(fid,"t0 = 1:2:64;\n"); fprintf(fid,"t1 = 2:2:64;\n"); fprintf(fid,"S = zeros(1,64);\n"); fprintf(fid,"S(t0) = real(S1a(t0)) + j*imag(S1b(t0));\n"); fprintf(fid,"S(t1) = real(S1b(t1)) + j*imag(S1a(t1));\n"); fprintf(fid,"Y = zeros(1,64);\n"); fprintf(fid,"Y(t0) = real(Y0(t0)) + j*imag(Y1(t0));\n"); fprintf(fid,"Y(t1) = real(Y1(t1)) + j*imag(Y0(t1));\n"); fprintf(fid,"figure;\n"); //fprintf(fid,"f = [(0:63)]/64 - 0.5;\n"); //fprintf(fid,"plot(S1,'x',S1a,'x',S1b,'x');\n"); fprintf(fid,"plot(S1,'x',S,'x',S1a,'x',S1b,'x');\n"); fprintf(fid,"legend('S1','S','S1a','S1b',0);\n"); fprintf(fid,"xlabel('I');\n"); fprintf(fid,"ylabel('Q');\n"); fprintf(fid,"axis square;\n"); fprintf(fid,"axis([-1 1 -1 1]*1.3);\n"); fprintf(fid,"title('PLCP long sequences');\n"); // pilot phase fprintf(fid,"pilotphase = zeros(1,n);\n"); windowf_read(_q->debug_pilotphase, &r); for (i=0; i<DEBUG_OFDMOQAMFRAME64SYNC_BUFFER_LEN; i++) fprintf(fid,"pilotphase(%4u) = %12.4e;\n", i+1, r[i]); fprintf(fid,"pilotphase_hat = zeros(1,n);\n"); windowf_read(_q->debug_pilotphase_hat, &r); for (i=0; i<DEBUG_OFDMOQAMFRAME64SYNC_BUFFER_LEN; i++) fprintf(fid,"pilotphase_hat(%4u) = %12.4e;\n", i+1, r[i]); fprintf(fid,"figure;\n"); fprintf(fid,"plot(0:(127),pilotphase([n-128+1]:n),'-k',0:(127),pilotphase_hat([n-128+1]:n),'-k','LineWidth',2);\n"); fprintf(fid,"xlabel('sample index');\n"); fprintf(fid,"ylabel('pilot phase');\n"); // rssi (received signal strength indication) fprintf(fid,"rssi = zeros(1,n);\n"); windowf_read(_q->debug_rssi, &r); for (i=0; i<DEBUG_OFDMOQAMFRAME64SYNC_BUFFER_LEN; i++) fprintf(fid,"rssi(%4u) = %12.4e;\n", i+1, r[i]); fprintf(fid,"figure;\n"); fprintf(fid,"plot(0:(n-1),rssi,'-k','LineWidth',2);\n"); fprintf(fid,"xlabel('sample index');\n"); fprintf(fid,"ylabel('RSSI');\n"); // frame symbols fprintf(fid,"framesyms = zeros(1,n);\n"); windowcf_read(_q->debug_framesyms, &rc); for (i=0; i<DEBUG_OFDMOQAMFRAME64SYNC_BUFFER_LEN; i++) fprintf(fid,"framesyms(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(rc[i]), cimagf(rc[i])); fprintf(fid,"figure;\n"); fprintf(fid,"plot(real(framesyms),imag(framesyms),'x','MarkerSize',1);\n"); fprintf(fid,"axis square;\n"); fprintf(fid,"axis([-1.5 1.5 -1.5 1.5]);\n"); fprintf(fid,"xlabel('in-phase');\n"); fprintf(fid,"ylabel('quadrature phase');\n"); fprintf(fid,"title('Frame Symbols');\n"); fclose(fid); printf("ofdmoqamframe64sync/debug: results written to %s\n", DEBUG_OFDMOQAMFRAME64SYNC_FILENAME); }
// print debugging information void flexframesync_debug_print(flexframesync _q, const char * _filename) { #if DEBUG_FLEXFRAMESYNC if (!_q->debug_objects_created) { fprintf(stderr,"error: flexframesync_debug_print(), debugging objects don't exist; enable debugging first\n"); return; } unsigned int i; float complex * rc; FILE* fid = fopen(_filename,"w"); fprintf(fid,"%% %s: auto-generated file", _filename); fprintf(fid,"\n\n"); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n\n"); fprintf(fid,"n = %u;\n", DEBUG_BUFFER_LEN); // main figure fprintf(fid,"figure('Color','white','position',[100 100 800 600]);\n"); // write x fprintf(fid,"x = zeros(1,n);\n"); windowcf_read(_q->debug_x, &rc); for (i=0; i<DEBUG_BUFFER_LEN; i++) fprintf(fid,"x(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(rc[i]), cimagf(rc[i])); fprintf(fid,"\n\n"); fprintf(fid,"subplot(3,2,1:2);\n"); fprintf(fid,"plot(1:length(x),real(x), 1:length(x),imag(x));\n"); fprintf(fid,"grid on;\n"); fprintf(fid,"xlabel('sample index');\n"); fprintf(fid,"ylabel('received signal, x');\n"); // write p/n sequence fprintf(fid,"preamble_pn = zeros(1,64);\n"); rc = _q->preamble_pn; for (i=0; i<64; i++) fprintf(fid,"preamble_pn(%4u) = %12.4e + 1i*%12.4e;\n", i+1, crealf(rc[i]), cimagf(rc[i])); // write p/n symbols fprintf(fid,"preamble_rx = zeros(1,64);\n"); rc = _q->preamble_rx; for (i=0; i<64; i++) fprintf(fid,"preamble_rx(%4u) = %12.4e + 1i*%12.4e;\n", i+1, crealf(rc[i]), cimagf(rc[i])); // write recovered header symbols (after qpilotsync) fprintf(fid,"header_mod = zeros(1,%u);\n", _q->header_mod_len); rc = _q->header_mod; for (i=0; i<_q->header_mod_len; i++) fprintf(fid,"header_mod(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(rc[i]), cimagf(rc[i])); // write raw payload symbols fprintf(fid,"payload_sym = zeros(1,%u);\n", _q->payload_sym_len); rc = _q->payload_sym; for (i=0; i<_q->payload_sym_len; i++) fprintf(fid,"payload_sym(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(rc[i]), cimagf(rc[i])); fprintf(fid,"subplot(3,2,[3 5]);\n"); fprintf(fid,"plot(real(header_mod),imag(header_mod),'o');\n"); fprintf(fid,"xlabel('in-phase');\n"); fprintf(fid,"ylabel('quadrature phase');\n"); fprintf(fid,"grid on;\n"); fprintf(fid,"axis([-1 1 -1 1]*1.5);\n"); fprintf(fid,"axis square;\n"); fprintf(fid,"title('Received Header Symbols');\n"); fprintf(fid,"subplot(3,2,[4 6]);\n"); fprintf(fid,"plot(real(payload_sym),imag(payload_sym),'+');\n"); fprintf(fid,"xlabel('in-phase');\n"); fprintf(fid,"ylabel('quadrature phase');\n"); fprintf(fid,"grid on;\n"); fprintf(fid,"axis([-1 1 -1 1]*1.5);\n"); fprintf(fid,"axis square;\n"); fprintf(fid,"title('Received Payload Symbols');\n"); fprintf(fid,"\n\n"); fclose(fid); printf("flexframesync/debug: results written to %s\n", _filename); #else fprintf(stderr,"flexframesync_debug_print(): compile-time debugging disabled\n"); #endif }
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; }
void wlanframesync_debug_print(wlanframesync _q, const char * _filename) { #if DEBUG_WLANFRAMESYNC if (_q->agc_rx == NULL || _q->debug_x == NULL || _q->debug_rssi == NULL || _q->debug_framesyms == NULL) { fprintf(stderr,"error: wlanframe_debug_print(), debugging objects don't exist; enable debugging first\n"); return; } FILE * fid = fopen(_filename,"w"); if (!fid) { fprintf(stderr,"error: wlanframe_debug_print(), could not open '%s' for writing\n", _filename); return; } fprintf(fid,"%% %s : auto-generated file\n", _filename); fprintf(fid,"close all;\n"); fprintf(fid,"clear all;\n"); fprintf(fid,"n = %u;\n", DEBUG_WLANFRAMESYNC_BUFFER_LEN); unsigned int i; float complex * rc; float * r; fprintf(fid,"x = zeros(1,n);\n"); windowcf_read(_q->debug_x, &rc); for (i=0; i<DEBUG_WLANFRAMESYNC_BUFFER_LEN; i++) fprintf(fid,"x(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(rc[i]), cimagf(rc[i])); fprintf(fid,"figure;\n"); fprintf(fid,"plot(0:(n-1),real(x),0:(n-1),imag(x));\n"); fprintf(fid,"xlabel('sample index');\n"); fprintf(fid,"ylabel('received signal, x');\n"); // write agc_rssi fprintf(fid,"\n\n"); fprintf(fid,"agc_rssi = zeros(1,%u);\n", DEBUG_WLANFRAMESYNC_BUFFER_LEN); windowf_read(_q->debug_rssi, &r); for (i=0; i<DEBUG_WLANFRAMESYNC_BUFFER_LEN; i++) fprintf(fid,"agc_rssi(%4u) = %12.4e;\n", i+1, r[i]); fprintf(fid,"figure;\n"); fprintf(fid,"plot(agc_rssi)\n"); fprintf(fid,"ylabel('RSSI [dB]');\n"); // write frame symbols fprintf(fid,"framesyms = zeros(1,n);\n"); windowcf_read(_q->debug_framesyms, &rc); for (i=0; i<DEBUG_WLANFRAMESYNC_BUFFER_LEN; i++) fprintf(fid,"framesyms(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(rc[i]), cimagf(rc[i])); fprintf(fid,"figure;\n"); fprintf(fid,"plot(real(framesyms),imag(framesyms),'x','MarkerSize',2);\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"); // write gain arrays fprintf(fid,"\n\n"); fprintf(fid,"G0a = zeros(1,64);\n"); fprintf(fid,"G0b = zeros(1,64);\n"); fprintf(fid,"G1a = zeros(1,64);\n"); fprintf(fid,"G1b = zeros(1,64);\n"); fprintf(fid,"G = zeros(1,64);\n"); for (i=0; i<64; i++) { unsigned int k = (i + 32) % 64; fprintf(fid,"G0a(%3u) = %12.8f + j*%12.8f;\n", k+1, crealf(_q->G0a[i]), cimagf(_q->G0a[i])); fprintf(fid,"G0b(%3u) = %12.8f + j*%12.8f;\n", k+1, crealf(_q->G0b[i]), cimagf(_q->G0b[i])); fprintf(fid,"G1a(%3u) = %12.8f + j*%12.8f;\n", k+1, crealf(_q->G1a[i]), cimagf(_q->G1a[i])); fprintf(fid,"G1b(%3u) = %12.8f + j*%12.8f;\n", k+1, crealf(_q->G1b[i]), cimagf(_q->G1b[i])); fprintf(fid,"G(%3u) = %12.8f + j*%12.8f;\n", k+1, crealf(_q->G[i]), cimagf(_q->G[i])); } fprintf(fid,"%% apply timing offset (backoff) phase shift\n"); fprintf(fid,"f = -32:31;\n"); fprintf(fid,"b = 2;\n"); fprintf(fid,"G0a = G0a.*exp(j*b*2*pi*f/64);\n"); fprintf(fid,"G0b = G0b.*exp(j*b*2*pi*f/64);\n"); fprintf(fid,"G1a = G1a.*exp(j*b*2*pi*f/64);\n"); fprintf(fid,"G1b = G1b.*exp(j*b*2*pi*f/64);\n"); fprintf(fid,"G = G.*exp(j*b*2*pi*f/64);\n"); fprintf(fid,"figure;\n"); fprintf(fid,"subplot(2,1,1);\n"); fprintf(fid," plot(f,abs(G1a),'x', f,abs(G1b),'x', f,abs(G),'-k','LineWidth',2);\n"); fprintf(fid," ylabel('G (mag)');\n"); fprintf(fid,"subplot(2,1,2);\n"); fprintf(fid," plot(f,arg(G1a),'x', f,arg(G1b),'x', f,arg(G),'-k','LineWidth',2);\n"); fprintf(fid," ylabel('G (phase)');\n"); fclose(fid); printf("wlanframesync/debug: results written to '%s'\n", _filename); #else fprintf(stderr,"wlanframesync_debug_print(): compile-time debugging disabled\n"); #endif }
void gmskframesync_debug_print(gmskframesync _q, const char * _filename) { #if DEBUG_GMSKFRAMESYNC if (!_q->debug_objects_created) { fprintf(stderr,"error: gmskframe_debug_print(), debugging objects don't exist; enable debugging first\n"); return; } FILE* fid = fopen(_filename,"w"); if (!fid) { fprintf(stderr, "error: gmskframesync_debug_print(), could not open '%s' for writing\n", _filename); return; } fprintf(fid,"%% %s: auto-generated file", _filename); fprintf(fid,"\n\n"); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n\n"); fprintf(fid,"num_samples = %u;\n", DEBUG_GMSKFRAMESYNC_BUFFER_LEN); fprintf(fid,"t = 0:(num_samples-1);\n"); unsigned int i; float complex * rc; // write x fprintf(fid,"x = zeros(1,num_samples);\n"); windowcf_read(_q->debug_x, &rc); for (i=0; i<DEBUG_GMSKFRAMESYNC_BUFFER_LEN; i++) fprintf(fid,"x(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(rc[i]), cimagf(rc[i])); fprintf(fid,"\n\n"); fprintf(fid,"figure;\n"); fprintf(fid,"plot(1:length(x),real(x), 1:length(x),imag(x));\n"); fprintf(fid,"ylabel('received signal, x');\n"); fprintf(fid,"\n\n"); // write instantaneous frequency float * r; fprintf(fid,"fi = zeros(1,num_samples);\n"); windowf_read(_q->debug_fi, &r); for (i=0; i<DEBUG_GMSKFRAMESYNC_BUFFER_LEN; i++) fprintf(fid,"fi(%4u) = %12.4e;\n", i+1, r[i]); fprintf(fid,"\n\n"); fprintf(fid,"figure;\n"); fprintf(fid,"plot(1:length(fi),fi);\n"); fprintf(fid,"ylabel('Inst. Freq.');\n"); fprintf(fid,"\n\n"); // write matched filter output fprintf(fid,"mf = zeros(1,num_samples);\n"); windowf_read(_q->debug_mf, &r); for (i=0; i<DEBUG_GMSKFRAMESYNC_BUFFER_LEN; i++) fprintf(fid,"mf(%4u) = %12.4e;\n", i+1, r[i]); fprintf(fid,"\n\n"); fprintf(fid,"figure;\n"); fprintf(fid,"plot(1:length(mf),mf);\n"); fprintf(fid,"ylabel('MF output');\n"); fprintf(fid,"\n\n"); #if 0 // write framesyms fprintf(fid,"framesyms = zeros(1,num_samples);\n"); windowf_read(_q->debug_framesyms, &r); for (i=0; i<DEBUG_GMSKFRAMESYNC_BUFFER_LEN; i++) fprintf(fid,"framesyms(%4u) = %12.4e;\n", i+1, r[i]); fprintf(fid,"\n\n"); fprintf(fid,"figure;\n"); fprintf(fid,"plot(t,framesyms,'x')\n"); fprintf(fid,"xlabel('time (symbol index)');\n"); fprintf(fid,"ylabel('GMSK demodulator output');\n"); fprintf(fid,"grid on;\n"); fprintf(fid,"\n\n"); #endif fclose(fid); printf("gmskframesync/debug: results written to '%s'\n", _filename); #else fprintf(stderr,"gmskframesync_debug_print(): compile-time debugging disabled\n"); #endif }
// 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; }
void ofdmframesync_execute_S1(ofdmframesync _q) { _q->timer--; if (_q->timer > 0) return; // increment number of symbols observed _q->num_symbols++; // run fft float complex * rc; windowcf_read(_q->input_buffer, &rc); // estimate S1 gain // TODO : add backoff in gain estimation ofdmframesync_estimate_gain_S1(_q, &rc[_q->cp_len], _q->G); // compute detector output float complex g_hat = 0.0f; unsigned int i; for (i=0; i<_q->M; i++) { //g_hat += _q->G[(i+1+_q->M)%_q->M]*conjf(_q->G[(i+_q->M)%_q->M]); g_hat += _q->G[(i+1)%_q->M]*conjf(_q->G[i]); } g_hat /= _q->M_S1; // normalize output g_hat *= _q->g0; // rotate by complex phasor relative to timing backoff g_hat *= liquid_cexpjf((float)(_q->backoff)*2.0f*M_PI/(float)(_q->M)); #if DEBUG_OFDMFRAMESYNC_PRINT printf(" g_hat : %12.4f <%12.8f>\n", cabsf(g_hat), cargf(g_hat)); #endif // check conditions for g_hat: // 1. magnitude should be large (near unity) when aligned // 2. phase should be very near zero (time aligned) if (cabsf(g_hat) > _q->plcp_sync_thresh && fabsf(cargf(g_hat)) < 0.1f*M_PI ) { //printf(" acquisition\n"); _q->state = OFDMFRAMESYNC_STATE_RXSYMBOLS; // reset timer _q->timer = _q->M + _q->cp_len + _q->backoff; _q->num_symbols = 0; // normalize gain by subcarriers, apply timing backoff correction float g = (float)(_q->M) / sqrtf(_q->M_pilot + _q->M_data); for (i=0; i<_q->M; i++) { _q->G[i] *= g; // gain due to relative subcarrier allocation _q->G[i] *= _q->B[i]; // timing backoff correction } #if 0 // TODO : choose number of taps more appropriately //unsigned int ntaps = _q->M / 4; unsigned int ntaps = (_q->M < 8) ? 2 : 8; // FIXME : this is by far the most computationally complex part of synchronization ofdmframesync_estimate_eqgain(_q, ntaps); #else unsigned int poly_order = 4; if (poly_order >= _q->M_pilot + _q->M_data) poly_order = _q->M_pilot + _q->M_data - 1; ofdmframesync_estimate_eqgain_poly(_q, poly_order); #endif #if 1 // compute composite gain unsigned int i; for (i=0; i<_q->M; i++) _q->R[i] = _q->B[i] / _q->G[i]; #endif return; #if 0 printf("exiting prematurely\n"); ofdmframesync_destroy(_q); exit(1); #endif } // check if we are stuck searching for the S1 symbol if (_q->num_symbols == 16) { #if DEBUG_OFDMFRAMESYNC_PRINT printf("could not find S1 symbol. bailing...\n"); #endif ofdmframesync_reset(_q); } // 'reset' timer (wait another half symbol) _q->timer = _q->M2; }
// frame detection void wlanframesync_execute_seekplcp(wlanframesync _q) { _q->timer++; // TODO : only check every 100 - 150 (decimates/reduced complexity) if (_q->timer < 64) return; // reset timer _q->timer = 0; // read contents of input buffer float complex * rc; windowcf_read(_q->input_buffer, &rc); // estimate gain // TODO : use gain from result of FFT unsigned int i; float g = 0.0f; for (i=16; i<80; i+=4) { // compute |rc[i]|^2 efficiently g += crealf(rc[i ])*crealf(rc[i ]) + cimagf(rc[i ])*cimagf(rc[i ]); g += crealf(rc[i+1])*crealf(rc[i+1]) + cimagf(rc[i+1])*cimagf(rc[i+1]); g += crealf(rc[i+2])*crealf(rc[i+2]) + cimagf(rc[i+2])*cimagf(rc[i+2]); g += crealf(rc[i+3])*crealf(rc[i+3]) + cimagf(rc[i+3])*cimagf(rc[i+3]); } g = 64.0f / (g + 1e-12f); // save gain (permits dynamic invocation of get_rssi() method) _q->g0 = g; // estimate S0 gain wlanframesync_estimate_gain_S0(_q, &rc[16], _q->G0a); // compute S0 metrics float complex s_hat; wlanframesync_S0_metrics(_q, _q->G0a, &s_hat); s_hat *= g; float tau_hat = cargf(s_hat) * (float)(16.0f) / (2*M_PI); #if DEBUG_WLANFRAMESYNC_PRINT printf(" - gain=%12.3f, rssi=%8.2f dB, s_hat=%12.4f <%12.8f>, tau_hat=%8.3f\n", sqrt(g), -10*log10(g), cabsf(s_hat), cargf(s_hat), tau_hat); #endif // if (cabsf(s_hat) > WLANFRAMESYNC_S0A_ABS_THRESH) { int dt = (int)roundf(tau_hat); // set timer appropriately... _q->timer = (16 + dt) % 16; //_q->timer += 32; // add delay to help ensure good S0 estimate (multiple of 16) _q->state = WLANFRAMESYNC_STATE_RXSHORT0; #if DEBUG_WLANFRAMESYNC_PRINT printf("********** frame detected! ************\n"); printf(" s_hat : %12.8f <%12.8f>\n", cabsf(s_hat), cargf(s_hat)); printf(" tau_hat : %12.8f\n", tau_hat); printf(" dt : %12d\n", dt); printf(" timer : %12u\n", _q->timer); #endif } }
void ofdmframesync_debug_print(ofdmframesync _q, const char * _filename) { #if DEBUG_OFDMFRAMESYNC if (!_q->debug_objects_created) { fprintf(stderr,"error: ofdmframe_debug_print(), debugging objects don't exist; enable debugging first\n"); return; } FILE * fid = fopen(_filename,"w"); if (!fid) { fprintf(stderr,"error: ofdmframe_debug_print(), could not open '%s' for writing\n", _filename); return; } fprintf(fid,"%% %s : auto-generated file\n", DEBUG_OFDMFRAMESYNC_FILENAME); fprintf(fid,"close all;\n"); fprintf(fid,"clear all;\n"); fprintf(fid,"n = %u;\n", DEBUG_OFDMFRAMESYNC_BUFFER_LEN); fprintf(fid,"M = %u;\n", _q->M); fprintf(fid,"M_null = %u;\n", _q->M_null); fprintf(fid,"M_pilot = %u;\n", _q->M_pilot); fprintf(fid,"M_data = %u;\n", _q->M_data); unsigned int i; float complex * rc; float * r; // save subcarrier allocation fprintf(fid,"p = zeros(1,M);\n"); for (i=0; i<_q->M; i++) fprintf(fid,"p(%4u) = %d;\n", i+1, _q->p[i]); fprintf(fid,"i_null = find(p==%d);\n", OFDMFRAME_SCTYPE_NULL); fprintf(fid,"i_pilot = find(p==%d);\n", OFDMFRAME_SCTYPE_PILOT); fprintf(fid,"i_data = find(p==%d);\n", OFDMFRAME_SCTYPE_DATA); // short, long, training sequences for (i=0; i<_q->M; i++) { fprintf(fid,"S0(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(_q->S0[i]), cimagf(_q->S0[i])); fprintf(fid,"S1(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(_q->S1[i]), cimagf(_q->S1[i])); } fprintf(fid,"x = zeros(1,n);\n"); windowcf_read(_q->debug_x, &rc); for (i=0; i<DEBUG_OFDMFRAMESYNC_BUFFER_LEN; i++) fprintf(fid,"x(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(rc[i]), cimagf(rc[i])); fprintf(fid,"figure;\n"); fprintf(fid,"plot(0:(n-1),real(x),0:(n-1),imag(x));\n"); fprintf(fid,"xlabel('sample index');\n"); fprintf(fid,"ylabel('received signal, x');\n"); fprintf(fid,"s1 = [];\n"); for (i=0; i<_q->M; i++) fprintf(fid,"s1(%3u) = %12.4e + j*%12.4e;\n", i+1, crealf(_q->s1[i]), cimagf(_q->s1[i])); // write agc_rssi fprintf(fid,"\n\n"); fprintf(fid,"agc_rssi = zeros(1,%u);\n", DEBUG_OFDMFRAMESYNC_BUFFER_LEN); windowf_read(_q->debug_rssi, &r); for (i=0; i<DEBUG_OFDMFRAMESYNC_BUFFER_LEN; i++) fprintf(fid,"agc_rssi(%4u) = %12.4e;\n", i+1, r[i]); fprintf(fid,"agc_rssi = filter([0.00362168 0.00724336 0.00362168],[1 -1.82269490 0.83718163],agc_rssi);\n"); fprintf(fid,"agc_rssi = 10*log10( agc_rssi );\n"); fprintf(fid,"figure;\n"); fprintf(fid,"plot(agc_rssi)\n"); fprintf(fid,"ylabel('RSSI [dB]');\n"); // write short, long symbols fprintf(fid,"\n\n"); fprintf(fid,"S0 = zeros(1,M);\n"); fprintf(fid,"S1 = zeros(1,M);\n"); for (i=0; i<_q->M; i++) { fprintf(fid,"S0(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(_q->S0[i]), cimagf(_q->S0[i])); fprintf(fid,"S1(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(_q->S1[i]), cimagf(_q->S1[i])); } // write gain arrays fprintf(fid,"\n\n"); fprintf(fid,"G0 = zeros(1,M);\n"); fprintf(fid,"G1 = zeros(1,M);\n"); fprintf(fid,"G_hat = zeros(1,M);\n"); fprintf(fid,"G = zeros(1,M);\n"); for (i=0; i<_q->M; i++) { fprintf(fid,"G0(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(_q->G0[i]), cimagf(_q->G0[i])); fprintf(fid,"G1(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(_q->G1[i]), cimagf(_q->G1[i])); fprintf(fid,"G_hat(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(_q->G_hat[i]),cimagf(_q->G_hat[i])); fprintf(fid,"G(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(_q->G[i]), cimagf(_q->G[i])); } fprintf(fid,"f = [0:(M-1)];\n"); fprintf(fid,"figure;\n"); fprintf(fid,"subplot(2,1,1);\n"); fprintf(fid," plot(f, fftshift(abs(G_hat)),'sb',...\n"); fprintf(fid," f, fftshift(abs(G)),'-k','LineWidth',2);\n"); fprintf(fid," grid on;\n"); fprintf(fid," xlabel('subcarrier index');\n"); fprintf(fid," ylabel('gain estimate (mag)');\n"); fprintf(fid,"subplot(2,1,2);\n"); fprintf(fid," plot(f, fftshift(arg(G_hat).*[abs(G0) > 1e-3]),'sb',...\n"); fprintf(fid," f, fftshift(arg(G)),'-k','LineWidth',2);\n"); fprintf(fid," grid on;\n"); fprintf(fid," xlabel('subcarrier index');\n"); fprintf(fid," ylabel('gain estimate (phase)');\n"); // write pilot response fprintf(fid,"\n\n"); fprintf(fid,"px = zeros(1,M_pilot);\n"); fprintf(fid,"py = zeros(1,M_pilot);\n"); for (i=0; i<_q->M_pilot; i++) { fprintf(fid,"px(%3u) = %12.8f;\n", i+1, _q->px[i]); fprintf(fid,"py(%3u) = %12.8f;\n", i+1, _q->py[i]); } fprintf(fid,"p_phase(1) = %12.8f;\n", _q->p_phase[0]); fprintf(fid,"p_phase(2) = %12.8f;\n", _q->p_phase[1]); // save pilot history fprintf(fid,"p0 = zeros(1,M);\n"); windowf_read(_q->debug_pilot_0, &r); for (i=0; i<DEBUG_OFDMFRAMESYNC_BUFFER_LEN; i++) fprintf(fid,"p0(%4u) = %12.4e;\n", i+1, r[i]); fprintf(fid,"p1 = zeros(1,M);\n"); windowf_read(_q->debug_pilot_1, &r); for (i=0; i<DEBUG_OFDMFRAMESYNC_BUFFER_LEN; i++) fprintf(fid,"p1(%4u) = %12.4e;\n", i+1, r[i]); fprintf(fid,"figure;\n"); fprintf(fid,"fp = (-M/2):(M/2);\n"); fprintf(fid,"subplot(3,1,1);\n"); fprintf(fid," plot(px, py, 'sb',...\n"); fprintf(fid," fp, polyval(p_phase, fp), '-k');\n"); fprintf(fid," grid on;\n"); fprintf(fid," legend('pilots','polyfit',0);\n"); fprintf(fid," xlabel('subcarrier');\n"); fprintf(fid," ylabel('phase');\n"); fprintf(fid,"subplot(3,1,2);\n"); fprintf(fid," plot(1:length(p0), p0);\n"); fprintf(fid," grid on;\n"); fprintf(fid," ylabel('p0 (phase offset)');\n"); fprintf(fid,"subplot(3,1,3);\n"); fprintf(fid," plot(1:length(p1), p1);\n"); fprintf(fid," grid on;\n"); fprintf(fid," ylabel('p1 (phase slope)');\n"); // write frame symbols fprintf(fid,"framesyms = zeros(1,n);\n"); windowcf_read(_q->debug_framesyms, &rc); for (i=0; i<DEBUG_OFDMFRAMESYNC_BUFFER_LEN; i++) fprintf(fid,"framesyms(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(rc[i]), cimagf(rc[i])); fprintf(fid,"figure;\n"); fprintf(fid,"plot(real(framesyms), imag(framesyms), 'x');\n"); fprintf(fid,"xlabel('I');\n"); fprintf(fid,"ylabel('Q');\n"); fprintf(fid,"axis([-1 1 -1 1]*1.6);\n"); fprintf(fid,"axis square;\n"); fprintf(fid,"grid on;\n"); fclose(fid); printf("ofdmframesync/debug: results written to '%s'\n", _filename); #else fprintf(stderr,"ofdmframesync_debug_print(): compile-time debugging disabled\n"); #endif }
void wlanframesync_execute_rxlong1(wlanframesync _q) { _q->timer++; if (_q->timer < 64) return; // run fft float complex * rc; windowcf_read(_q->input_buffer, &rc); // estimate S1 gain, adding backoff in gain estimation wlanframesync_estimate_gain_S1(_q, &rc[16-2], _q->G1b); // compute S1 metrics float complex s_hat; wlanframesync_S1_metrics(_q, _q->G1b, &s_hat); s_hat *= _q->g0; // scale output by raw gain estimate // rotate by complex phasor relative to timing backoff //s_hat *= cexpf(_Complex_I * 2.0f * 2.0f * M_PI / 64.0f); s_hat *= cexpf(_Complex_I * 0.19635f); // save second 'long' symbol statistic _q->s1b_hat = s_hat; // rotate by complex phasor relative to timing backoff //s_hat *= liquid_cexpjf((float)(_q->backoff)*2.0f*M_PI/(float)(_q->M)); #if DEBUG_WLANFRAMESYNC_PRINT printf(" s_hat : %12.8f <%12.8f>\n", cabsf(s_hat), cargf(s_hat)); #endif // check conditions for s_hat float s_hat_abs = cabsf(s_hat); float s_hat_arg = cargf(s_hat); if (s_hat_arg > M_PI) s_hat_arg -= 2.0f*M_PI; if (s_hat_arg < -M_PI) s_hat_arg += 2.0f*M_PI; // check conditions for s_hat: // 1. magnitude should be large (near unity) when aligned // 2. phase should be very near zero (time aligned) if (s_hat_abs > WLANFRAMESYNC_S1B_ABS_THRESH && fabsf(s_hat_arg) < WLANFRAMESYNC_S1B_ARG_THRESH) { #if DEBUG_WLANFRAMESYNC_PRINT printf(" acquisition S1[b]\n"); #endif // refine CFO estimate with G1a, G1b and adjust NCO appropriately float nu_hat = wlanframesync_estimate_cfo_S1(_q->G1a, _q->G1b); nco_crcf_adjust_frequency(_q->nco_rx, nu_hat); #if DEBUG_WLANFRAMESYNC_PRINT printf(" nu_hat[1]: %12.8f\n", nu_hat); #endif // TODO : de-rotate S1b by phase offset (help with equalizer) // estimate equalizer with G1a, G1b wlanframesync_estimate_eqgain_poly(_q); // set state _q->state = WLANFRAMESYNC_STATE_RXLONG1; // reset timer _q->timer = 0; } // set state _q->state = WLANFRAMESYNC_STATE_RXSIGNAL; // reset timer _q->timer = 0; }
// frame detection void ofdmframesync_execute_seekplcp(ofdmframesync _q) { _q->timer++; if (_q->timer < _q->M) return; // reset timer _q->timer = 0; // float complex * rc; windowcf_read(_q->input_buffer, &rc); // estimate gain unsigned int i; float g = 0.0f; for (i=_q->cp_len; i<_q->M + _q->cp_len; i++) { // compute |rc[i]|^2 efficiently g += crealf(rc[i])*crealf(rc[i]) + cimagf(rc[i])*cimagf(rc[i]); } g = (float)(_q->M) / g; #if OFDMFRAMESYNC_ENABLE_SQUELCH // TODO : squelch here if ( -10*log10f( sqrtf(g) ) < _q->squelch_threshold && _q->squelch_enabled) { printf("squelch\n"); return; } #endif // estimate S0 gain ofdmframesync_estimate_gain_S0(_q, &rc[_q->cp_len], _q->G0); float complex s_hat; ofdmframesync_S0_metrics(_q, _q->G0, &s_hat); s_hat *= g; float tau_hat = cargf(s_hat) * (float)(_q->M2) / (2*M_PI); #if DEBUG_OFDMFRAMESYNC_PRINT printf(" - gain=%12.3f, rssi=%12.8f, s_hat=%12.4f <%12.8f>, tau_hat=%8.3f\n", sqrt(g), -10*log10(g), cabsf(s_hat), cargf(s_hat), tau_hat); #endif // save gain (permits dynamic invocation of get_rssi() method) _q->g0 = g; // if (cabsf(s_hat) > _q->plcp_detect_thresh) { int dt = (int)roundf(tau_hat); // set timer appropriately... _q->timer = (_q->M + dt) % (_q->M2); _q->timer += _q->M; // add delay to help ensure good S0 estimate _q->state = OFDMFRAMESYNC_STATE_PLCPSHORT0; #if DEBUG_OFDMFRAMESYNC_PRINT printf("********** frame detected! ************\n"); printf(" s_hat : %12.8f <%12.8f>\n", cabsf(s_hat), cargf(s_hat)); printf(" tau_hat : %12.8f\n", tau_hat); printf(" dt : %12d\n", dt); printf(" timer : %12u\n", _q->timer); #endif //printf("exiting prematurely\n"); //ofdmframesync_destroy(_q); //exit(1); } }
// 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); } }
// frame detection void ofdmframesync_execute_S0b(ofdmframesync _q) { //printf("t = %u\n", _q->timer); _q->timer++; if (_q->timer < _q->M2) return; // reset timer _q->timer = _q->M + _q->cp_len - _q->backoff; // float complex * rc; windowcf_read(_q->input_buffer, &rc); // estimate S0 gain ofdmframesync_estimate_gain_S0(_q, &rc[_q->cp_len], _q->G1); float complex s_hat; ofdmframesync_S0_metrics(_q, _q->G1, &s_hat); s_hat *= _q->g0; _q->s_hat_1 = s_hat; #if DEBUG_OFDMFRAMESYNC_PRINT float tau_hat = cargf(s_hat) * (float)(_q->M2) / (2*M_PI); printf("********** S0[1] received ************\n"); printf(" s_hat : %12.8f <%12.8f>\n", cabsf(s_hat), cargf(s_hat)); printf(" tau_hat : %12.8f\n", tau_hat); // new timing offset estimate tau_hat = cargf(_q->s_hat_0 + _q->s_hat_1) * (float)(_q->M2) / (2*M_PI); printf(" tau_hat * : %12.8f\n", tau_hat); printf("**********\n"); #endif // re-adjust timer accordingly float tau_prime = cargf(_q->s_hat_0 + _q->s_hat_1) * (float)(_q->M2) / (2*M_PI); _q->timer -= (int)roundf(tau_prime); #if 0 if (cabsf(s_hat) < 0.3f) { #if DEBUG_OFDMFRAMESYNC_PRINT printf("false alarm S0[1]\n"); #endif // false alarm ofdmframesync_reset(_q); return; } #endif float complex g_hat = 0.0f; unsigned int i; for (i=0; i<_q->M; i++) g_hat += _q->G1[i] * conjf(_q->G0[i]); #if 0 // compute carrier frequency offset estimate using freq. domain method float nu_hat = 2.0f * cargf(g_hat) / (float)(_q->M); #else // compute carrier frequency offset estimate using ML method float complex t0 = 0.0f; for (i=0; i<_q->M2; i++) { t0 += conjf(rc[i]) * _q->s0[i] * rc[i+_q->M2] * conjf(_q->s0[i+_q->M2]); } float nu_hat = cargf(t0) / (float)(_q->M2); #endif #if DEBUG_OFDMFRAMESYNC_PRINT printf(" nu_hat : %12.8f\n", nu_hat); #endif // set NCO frequency nco_crcf_set_frequency(_q->nco_rx, nu_hat); _q->state = OFDMFRAMESYNC_STATE_PLCPLONG; }
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; }
// print debugging information void flexframesync_debug_print(flexframesync _q, const char * _filename) { #if DEBUG_FLEXFRAMESYNC if (!_q->debug_objects_created) { fprintf(stderr,"error: flexframesync_debug_print(), debugging objects don't exist; enable debugging first\n"); return; } unsigned int i; float complex * rc; float * r; FILE* fid = fopen(_filename,"w"); fprintf(fid,"%% %s: auto-generated file", _filename); fprintf(fid,"\n\n"); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n\n"); fprintf(fid,"n = %u;\n", DEBUG_BUFFER_LEN); // write x fprintf(fid,"x = zeros(1,n);\n"); windowcf_read(_q->debug_x, &rc); for (i=0; i<DEBUG_BUFFER_LEN; i++) fprintf(fid,"x(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(rc[i]), cimagf(rc[i])); fprintf(fid,"\n\n"); fprintf(fid,"figure;\n"); fprintf(fid,"plot(1:length(x),real(x), 1:length(x),imag(x));\n"); fprintf(fid,"ylabel('received signal, x');\n"); // write pre-demod sample buffer fprintf(fid,"k = %u;\n", _q->k); fprintf(fid,"m = %u;\n", _q->m); fprintf(fid,"presync_samples = zeros(1,k*(64+m));\n"); windowcf_read(_q->buffer, &rc); for (i=0; i<_q->k*(64+_q->m); i++) fprintf(fid,"presync_samples(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(rc[i]), cimagf(rc[i])); // write p/n sequence fprintf(fid,"preamble_pn = zeros(1,64);\n"); r = _q->preamble_pn; for (i=0; i<64; i++) fprintf(fid,"preamble_pn(%4u) = %12.4e;\n", i+1, r[i]); // write p/n symbols fprintf(fid,"preamble_rx = zeros(1,64);\n"); rc = _q->preamble_rx; for (i=0; i<64; i++) fprintf(fid,"preamble_rx(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(rc[i]), cimagf(rc[i])); // write payload symbols unsigned int num_payload_syms = _q->payload_mod_len > 256 ? 256 : _q->payload_mod_len; fprintf(fid,"payload_syms = zeros(1,%u);\n", num_payload_syms); rc = _q->payload_sym; for (i=0; i<num_payload_syms; i++) fprintf(fid,"payload_syms(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(rc[i]), cimagf(rc[i])); fprintf(fid,"figure;\n"); fprintf(fid,"plot(real(payload_syms),imag(payload_syms),'x',...\n"); fprintf(fid," real(preamble_rx), imag(preamble_rx), 'x');\n"); fprintf(fid,"xlabel('in-phase');\n"); fprintf(fid,"ylabel('quadrature phase');\n"); fprintf(fid,"legend('p/n syms','payload syms','location','northeast');\n"); fprintf(fid,"grid on;\n"); fprintf(fid,"axis([-1 1 -1 1]*1.5);\n"); fprintf(fid,"axis square;\n"); #if 0 // NCO, timing, etc. fprintf(fid,"symsync_index = zeros(1,664);\n"); fprintf(fid,"nco_phase = zeros(1,664);\n"); for (i=0; i<664; i++) { fprintf(fid,"symsync_index(%4u) = %12.4e;\n", i+1, _q->debug_symsync_index[i]); fprintf(fid,"nco_phase(%4u) = %12.4e;\n", i+1, _q->debug_nco_phase[i]); } fprintf(fid,"figure;\n"); fprintf(fid,"subplot(2,1,1);\n"); fprintf(fid," plot(nco_phase);\n"); fprintf(fid," ylabel('nco phase');\n"); fprintf(fid," grid on;\n"); fprintf(fid,"subplot(2,1,2);\n"); fprintf(fid," plot(symsync_index);\n"); fprintf(fid," ylabel('symsync index');\n"); fprintf(fid," grid on;\n"); #endif fprintf(fid,"\n\n"); fclose(fid); printf("flexframesync/debug: results written to %s\n", _filename); #else fprintf(stderr,"flexframesync_debug_print(): compile-time debugging disabled\n"); #endif }
// main program int main (int argc, char **argv) { // command-line options int verbose = 1; int ppm_error = 0; int gain = 0; unsigned int nfft = 64; float offset = -65.0f; float scale = 5.0f; float fft_rate = 10.0f; float rx_resamp_rate; float bandwidth = 800e3f; unsigned int logsize = 4096; char filename[256] = "rtl_asgram.dat"; int r, n_read; uint32_t frequency = 100000000; uint32_t samp_rate = DEFAULT_SAMPLE_RATE; uint32_t out_block_size = DEFAULT_BUF_LENGTH; uint8_t *buffer; int dev_index = 0; int dev_given = 0; struct sigaction sigact; normalizer_t *norm; // int d; while ((d = getopt(argc,argv,"hf:b:B:G:n:p:s:o:r:L:F:")) != EOF) { switch (d) { case 'h': usage(); return 0; case 'f': frequency = atof(optarg); break; case 'b': bandwidth = atof(optarg); break; case 'B': out_block_size = (uint32_t)atof(optarg); break; case 'G': gain = (int)(atof(optarg) * 10); break; case 'n': nfft = atoi(optarg); break; case 'o': offset = atof(optarg); break; case 'p': ppm_error = atoi(optarg); break; case 's': samp_rate = (uint32_t)atofs(optarg); break; case 'r': fft_rate = atof(optarg); break; case 'L': logsize = atoi(optarg); break; case 'F': strncpy(filename,optarg,255); break; case 'd': dev_index = verbose_device_search(optarg); dev_given = 1; break; default: usage(); return 1; } } // validate parameters if (fft_rate <= 0.0f || fft_rate > 100.0f) { fprintf(stderr,"error: %s, fft rate must be in (0, 100) Hz\n", argv[0]); exit(1); } if (!dev_given) { dev_index = verbose_device_search("0"); } if (dev_index < 0) { exit(1); } r = rtlsdr_open(&dev, (uint32_t)dev_index); if (r < 0) { fprintf(stderr, "Failed to open rtlsdr device #%d.\n", dev_index); exit(1); } sigact.sa_handler = sighandler; sigemptyset(&sigact.sa_mask); sigact.sa_flags = 0; sigaction(SIGINT, &sigact, NULL); sigaction(SIGTERM, &sigact, NULL); sigaction(SIGQUIT, &sigact, NULL); sigaction(SIGPIPE, &sigact, NULL); /* Set the sample rate */ verbose_set_sample_rate(dev, samp_rate); /* Set the frequency */ verbose_set_frequency(dev, frequency); if (0 == gain) { /* Enable automatic gain */ verbose_auto_gain(dev); } else { /* Enable manual gain */ gain = nearest_gain(dev, gain); verbose_gain_set(dev, gain); } verbose_ppm_set(dev, ppm_error); rx_resamp_rate = bandwidth/samp_rate; printf("frequency : %10.4f [MHz]\n", frequency*1e-6f); printf("bandwidth : %10.4f [kHz]\n", bandwidth*1e-3f); printf("sample rate : %10.4f kHz = %10.4f kHz * %8.6f\n", samp_rate * 1e-3f, bandwidth * 1e-3f, 1.0f / rx_resamp_rate); printf("verbosity : %s\n", (verbose?"enabled":"disabled")); unsigned int i; // add arbitrary resampling component msresamp_crcf resamp = msresamp_crcf_create(rx_resamp_rate, 60.0f); assert(resamp); // create buffer for sample logging windowcf log = windowcf_create(logsize); // create ASCII spectrogram object float maxval; float maxfreq; char ascii[nfft+1]; ascii[nfft] = '\0'; // append null character to end of string asgram q = asgram_create(nfft); asgram_set_scale(q, offset, scale); // assemble footer unsigned int footer_len = nfft + 16; char footer[footer_len+1]; for (i=0; i<footer_len; i++) footer[i] = ' '; footer[1] = '['; footer[nfft/2 + 3] = '+'; footer[nfft + 4] = ']'; sprintf(&footer[nfft+6], "%8.3f MHz", frequency*1e-6f); unsigned int msdelay = 1000 / fft_rate; // create/initialize Hamming window float w[nfft]; for (i=0; i<nfft; i++) w[i] = hamming(i,nfft); //allocate recv buffer buffer = malloc(out_block_size * sizeof(uint8_t)); assert(buffer); // create buffer for arbitrary resamper output int b_len = ((int)(out_block_size * rx_resamp_rate) + 64) >> 1; complex float buffer_resamp[b_len]; debug("resamp_buffer_len: %d", b_len); // timer to control asgram output timer t1 = timer_create(); timer_tic(t1); norm = normalizer_create(); verbose_reset_buffer(dev); while (!do_exit) { // grab data from device r = rtlsdr_read_sync(dev, buffer, out_block_size, &n_read); if (r < 0) { fprintf(stderr, "WARNING: sync read failed.\n"); break; } if ((bytes_to_read > 0) && (bytes_to_read < (uint32_t)n_read)) { n_read = bytes_to_read; do_exit = 1; } // push data through arbitrary resampler and give to frame synchronizer // TODO : apply bandwidth-dependent gain for (i=0; i<n_read/2; i++) { // grab sample from usrp buffer complex float rtlsdr_sample = normalizer_normalize(norm, *((uint16_t*)buffer+i)); // push through resampler (one at a time) unsigned int nw; msresamp_crcf_execute(resamp, &rtlsdr_sample, 1, buffer_resamp, &nw); // push resulting samples into asgram object asgram_push(q, buffer_resamp, nw); // write samples to log windowcf_write(log, buffer_resamp, nw); } if ((uint32_t)n_read < out_block_size) { fprintf(stderr, "Short read, samples lost, exiting!\n"); break; } if (bytes_to_read > 0) bytes_to_read -= n_read; if (timer_toc(t1) > msdelay*1e-3f) { // reset timer timer_tic(t1); // run the spectrogram asgram_execute(q, ascii, &maxval, &maxfreq); // print the spectrogram printf(" > %s < pk%5.1fdB [%5.2f]\n", ascii, maxval, maxfreq); printf("%s\r", footer); fflush(stdout); } } // try to write samples to file FILE * fid = fopen(filename,"w"); if (fid != NULL) { // write header fprintf(fid, "# %s : auto-generated file\n", filename); fprintf(fid, "#\n"); fprintf(fid, "# num_samples : %u\n", logsize); fprintf(fid, "# frequency : %12.8f MHz\n", frequency*1e-6f); fprintf(fid, "# bandwidth : %12.8f kHz\n", bandwidth*1e-3f); // save results to file complex float * rc; // read pointer windowcf_read(log, &rc); for (i=0; i<logsize; i++) fprintf(fid, "%12.4e %12.4e\n", crealf(rc[i]), cimagf(rc[i])); // close it up fclose(fid); printf("results written to '%s'\n", filename); } else { fprintf(stderr,"error: %s, could not open '%s' for writing\n", argv[0], filename); } // destroy objects normalizer_destroy(&norm); msresamp_crcf_destroy(resamp); windowcf_destroy(log); asgram_destroy(q); timer_destroy(t1); rtlsdr_close(dev); free (buffer); return 0; }