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; } }
// recover symbol, correcting for gain, pilot phase, etc. void wlanframesync_rxsymbol(wlanframesync _q) { // apply gain unsigned int i; for (i=0; i<64; i++) _q->X[i] *= _q->R[i]; // polynomial curve-fit float x_phase[4] = {-21.0f, -7.0f, 7.0f, 21.0f}; float y_phase[4]; float p_phase[2]; // update pilot phase unsigned int pilot_phase = wlan_lfsr_advance(_q->ms_pilot); y_phase[0] = pilot_phase ? cargf(-_q->X[43]) : cargf( _q->X[43]); y_phase[1] = pilot_phase ? cargf(-_q->X[57]) : cargf( _q->X[57]); y_phase[2] = pilot_phase ? cargf(-_q->X[ 7]) : cargf( _q->X[ 7]); y_phase[3] = pilot_phase ? cargf( _q->X[21]) : cargf(-_q->X[21]); // unwrap phase if ( (y_phase[1]-y_phase[0]) > M_PI ) y_phase[1] -= 2*M_PI; if ( (y_phase[1]-y_phase[0]) < -M_PI ) y_phase[1] += 2*M_PI; if ( (y_phase[2]-y_phase[1]) > M_PI ) y_phase[2] -= 2*M_PI; if ( (y_phase[2]-y_phase[1]) < -M_PI ) y_phase[2] += 2*M_PI; if ( (y_phase[3]-y_phase[2]) > M_PI ) y_phase[3] -= 2*M_PI; if ( (y_phase[3]-y_phase[2]) < -M_PI ) y_phase[3] += 2*M_PI; #if 0 printf(" x = [-21 -7 7 21]; y = [%6.3f %6.3f %6.3f %6.3f];\n", y_phase[0], y_phase[1], y_phase[2], y_phase[3]); #endif // fit phase to 1st-order polynomial (2 coefficients) polyf_fit(x_phase, y_phase, 4, p_phase, 2); // compensate for phase offset // TODO : find more computationally efficient way to do this for (i=0; i<64; i++) { float fx = (i > 31) ? (float)i - (float)(64) : (float)i; float theta = polyf_val(p_phase, 2, fx); _q->X[i] *= cexpf(-_Complex_I*theta); } // adjust NCO frequency based on differential phase if (_q->num_symbols > 0) { // compute phase error (unwrapped) float dphi_prime = p_phase[0] - _q->phi_prime; if (dphi_prime > M_PI) dphi_prime -= M_2_PI; if (dphi_prime < -M_PI) dphi_prime += M_2_PI; // adjust NCO proportionally to phase error nco_crcf_adjust_frequency(_q->nco_rx, 1e-3f*dphi_prime); } // set internal phase state _q->phi_prime = p_phase[0]; }
int main() { // options unsigned int num_channels=8; // number of channels unsigned int m=2; // filter delay float As=-60; // stop-band attenuation unsigned int num_frames=25; // number of frames // create objects firpfbch_crcf c = firpfbch_crcf_create_kaiser(LIQUID_ANALYZER, num_channels, m, As); //firpfbch_crcf_print(c); FILE*fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s: auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\nclose all;\n\n"); fprintf(fid,"num_channels=%u;\n", num_channels); fprintf(fid,"num_frames=%u;\n", num_frames); fprintf(fid,"x = zeros(1,%u);\n", num_channels * num_frames); fprintf(fid,"y = zeros(%u,%u);\n", num_channels, num_frames); unsigned int i, j, n=0; float complex x[num_channels]; // time-domain input float complex y[num_channels]; // channelized output // create nco: sweeps entire range of frequencies over the evaluation interval nco_crcf nco_tx = nco_crcf_create(LIQUID_VCO); nco_crcf_set_frequency(nco_tx, 0.0f); float df = 2*M_PI/(num_channels*num_frames); printf("fr/ch:"); for (j=0; j<num_channels; j++) printf("%3u",j); printf("\n"); for (i=0; i<num_frames; i++) { // generate frame of data for (j=0; j<num_channels; j++) { nco_crcf_cexpf(nco_tx, &x[j]); nco_crcf_adjust_frequency(nco_tx, df); nco_crcf_step(nco_tx); } // execute analysis filter bank firpfbch_crcf_analyzer_execute(c, x, y); printf("%4u : ", i); for (j=0; j<num_channels; j++) { if (cabsf(y[j]) > num_channels / 4) printf(" x "); else printf(" . "); } printf("\n"); // write output to file for (j=0; j<num_channels; j++) { // frequency data fprintf(fid,"y(%4u,%4u) = %12.4e + j*%12.4e;\n", j+1, i+1, crealf(y[j]), cimagf(y[j])); // time data fprintf(fid,"x(%4u) = %12.4e + j*%12.4e;\n", n+1, crealf(x[j]), cimag(x[j])); n++; } } // destroy objects nco_crcf_destroy(nco_tx); firpfbch_crcf_destroy(c); // plot results fprintf(fid,"\n\n"); fprintf(fid,"figure;\n"); fprintf(fid,"subplot(2,1,1);\n"); fprintf(fid," plot(1:length(x),real(x),1:length(x),imag(x));\n"); fprintf(fid," xlabel('time');\n"); fprintf(fid," ylabel('signal');\n"); fprintf(fid,"subplot(2,1,2);\n"); fprintf(fid," plot(20*log10(abs(y.')/num_channels));\n"); fprintf(fid," xlabel('time (decimated)');\n"); fprintf(fid," ylabel('channelized energy [dB]');\n"); fprintf(fid,"n=min(num_channels,8);\n"); fprintf(fid,"figure;\n"); fprintf(fid,"for i=1:n\n"); fprintf(fid," subplot(n,1,i);\n"); fprintf(fid," plot(1:num_frames,real(y(i,:)),1:num_frames,imag(y(i,:)));\n"); fprintf(fid," axis off;\n"); fprintf(fid," ylabel(num2str(i));\n"); fprintf(fid,"end;\n"); fclose(fid); printf("results written to %s\n", OUTPUT_FILENAME); printf("done.\n"); return 0; }
// recover symbol, correcting for gain, pilot phase, etc. void ofdmframesync_rxsymbol(ofdmframesync _q) { // apply gain unsigned int i; for (i=0; i<_q->M; i++) _q->X[i] *= _q->R[i]; // polynomial curve-fit float x_phase[_q->M_pilot]; float y_phase[_q->M_pilot]; float p_phase[2]; unsigned int n=0; unsigned int k; float complex pilot = 1.0f; for (i=0; i<_q->M; i++) { // start at mid-point (effective fftshift) k = (i + _q->M2) % _q->M; if (_q->p[k]==OFDMFRAME_SCTYPE_PILOT) { if (n == _q->M_pilot) { fprintf(stderr,"warning: ofdmframesync_rxsymbol(), pilot subcarrier mismatch\n"); return; } pilot = (msequence_advance(_q->ms_pilot) ? 1.0f : -1.0f); #if 0 printf("pilot[%3u] = %12.4e + j*%12.4e (expected %12.4e + j*%12.4e)\n", k, crealf(_q->X[k]), cimagf(_q->X[k]), crealf(pilot), cimagf(pilot)); #endif // store resulting... x_phase[n] = (k > _q->M2) ? (float)k - (float)(_q->M) : (float)k; y_phase[n] = cargf(_q->X[k]*conjf(pilot)); // update counter n++; } } if (n != _q->M_pilot) { fprintf(stderr,"warning: ofdmframesync_rxsymbol(), pilot subcarrier mismatch\n"); return; } // try to unwrap phase for (i=1; i<_q->M_pilot; i++) { while ((y_phase[i] - y_phase[i-1]) > M_PI) y_phase[i] -= 2*M_PI; while ((y_phase[i] - y_phase[i-1]) < -M_PI) y_phase[i] += 2*M_PI; } // fit phase to 1st-order polynomial (2 coefficients) polyf_fit(x_phase, y_phase, _q->M_pilot, p_phase, 2); // filter slope estimate (timing offset) float alpha = 0.3f; p_phase[1] = alpha*p_phase[1] + (1-alpha)*_q->p1_prime; _q->p1_prime = p_phase[1]; #if DEBUG_OFDMFRAMESYNC if (_q->debug_enabled) { // save pilots memmove(_q->px, x_phase, _q->M_pilot*sizeof(float)); memmove(_q->py, y_phase, _q->M_pilot*sizeof(float)); // NOTE : swapping values for octave _q->p_phase[0] = p_phase[1]; _q->p_phase[1] = p_phase[0]; windowf_push(_q->debug_pilot_0, p_phase[0]); windowf_push(_q->debug_pilot_1, p_phase[1]); } #endif // compensate for phase offset // TODO : find more computationally efficient way to do this for (i=0; i<_q->M; i++) { // only apply to data/pilot subcarriers if (_q->p[i] == OFDMFRAME_SCTYPE_NULL) { _q->X[i] = 0.0f; } else { float fx = (i > _q->M2) ? (float)i - (float)(_q->M) : (float)i; float theta = polyf_val(p_phase, 2, fx); _q->X[i] *= liquid_cexpjf(-theta); } } // adjust NCO frequency based on differential phase if (_q->num_symbols > 0) { // compute phase error (unwrapped) float dphi_prime = p_phase[0] - _q->phi_prime; while (dphi_prime > M_PI) dphi_prime -= M_2_PI; while (dphi_prime < -M_PI) dphi_prime += M_2_PI; // adjust NCO proportionally to phase error nco_crcf_adjust_frequency(_q->nco_rx, 1e-3f*dphi_prime); } // set internal phase state _q->phi_prime = p_phase[0]; //printf("%3u : theta : %12.8f, nco freq: %12.8f\n", _q->num_symbols, p_phase[0], nco_crcf_get_frequency(_q->nco_rx)); // increment symbol counter _q->num_symbols++; #if 0 for (i=0; i<_q->M_pilot; i++) printf("x_phase(%3u) = %12.8f; y_phase(%3u) = %12.8f;\n", i+1, x_phase[i], i+1, y_phase[i]); printf("poly : p0=%12.8f, p1=%12.8f\n", p_phase[0], p_phase[1]); #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; }