static void update_status_bar(struct view_s* v, int x2, int y2) { float pos[DIMS]; for (int i = 0; i < DIMS; i++) pos[i] = v->pos[i]; pos[v->xdim] = x2; pos[v->ydim] = y2; complex float val = sample(DIMS, pos, v->dims, v->strs, v->data); // FIXME: make sure this matches exactly the pixel char buf[100]; snprintf(buf, 100, "Pos: %03d %03d Magn: %.3e Val: %+.3e%+.3ei Arg: %+.2f", x2, y2, cabsf(val), crealf(val), cimagf(val), cargf(val)); gtk_entry_set_text(v->gtk_entry, buf); }
// estimate carrier frequency offset from S0 gains float wlanframesync_estimate_cfo_S0(float complex * _G0a, float complex * _G0b) { // compute carrier frequency offset estimate using freq. domain method float complex g_hat = 0.0f; g_hat += _G0b[40] * conjf(_G0a[40]); g_hat += _G0b[44] * conjf(_G0a[44]); g_hat += _G0b[48] * conjf(_G0a[48]); g_hat += _G0b[52] * conjf(_G0a[52]); g_hat += _G0b[56] * conjf(_G0a[56]); g_hat += _G0b[60] * conjf(_G0a[60]); // g_hat += _G0b[ 4] * conjf(_G0a[ 4]); g_hat += _G0b[ 8] * conjf(_G0a[ 8]); g_hat += _G0b[12] * conjf(_G0a[12]); g_hat += _G0b[16] * conjf(_G0a[16]); g_hat += _G0b[20] * conjf(_G0a[20]); g_hat += _G0b[24] * conjf(_G0a[24]); return 4.0f * cargf(g_hat) / 64.0f; }
float complex cpowf(float complex a, float complex z) { float complex w; float x, y, r, theta, absa, arga; x = crealf(z); y = cimagf(z); absa = cabsf(a); if (absa == 0.0f) { return (0.0f + 0.0f * I); } arga = cargf(a); r = powf(absa, x); theta = x * arga; if (y != 0.0f) { r = r * expf(-y * arga); theta = theta + y * logf(absa); } w = r * cosf(theta) + (r * sinf(theta)) * I; return w; }
int main(int argc, char**argv) { float complex z1 = 1.0 + 3.0 * I; printf("value = real %.2f imag %.2f\n",creal(z1),cimag(z1)); float abs_value = cabsf(z1); printf("abs = %.2f\n",abs_value); float complex z2 = conjf(z1); printf("value = real %.2f imag %.2f\n",creal(z2),cimag(z2)); float complex z3 = cexpf(z1); printf("value = real %.2f imag %.2f\n",creal(z3),cimag(z3)); float complex z4 = conj(z1); printf("value = real %.2f imag %.2f\n",creal(z4),cimag(z4)); float complex z5 = cargf(z1); printf("value = real %.2f imag %.2f\n",creal(z5),cimag(z5)); float complex z6 = 0.5 + 0.5 * I; float complex z7 = 0.5 - 0.5 * I; float complex z8 = z6 * z7; printf("value = real %.2f imag %.2f\n",creal(z8),cimag(z8)); float complex z9 = z6 / z7; printf("value = real %.2f imag %.2f\n",creal(z9),cimag(z9)); return 0; }
// iterative derivative estimation step // _t : time vector // _g : complex input // _n : size of inputs _t, _g float liquid_unwrapcf_iterative_step(float * _t, float complex * _g_hat, unsigned int _n) { // find mean of phase difference float dphi; float dphi_mean=0.0f; unsigned int i; for (i=1; i<_n; i++) { // unwrap phase dphi = cargf( _g_hat[i] * conjf(_g_hat[i-1]) ); // constrain dphi to be in [-pi,pi) while ( dphi > M_PI ) dphi -= 2*M_PI; while ( dphi < -M_PI ) dphi += 2*M_PI; dphi_mean += dphi; } dphi_mean /= (float)(_n-1); return dphi_mean; }
void fbdip(int n3, int n4, float ****in, float **dip, int nit, float eta) /*< omnidirectional dip estimation >*/ { int it, i1, j1, j2; double norm, s1, c1; for(i1=0; i1<n1*n2; i1++) p[0][i1] = p0; for (it=0; it<nit; it++) { for(i1=0; i1<n1*n2; i1++) { s1 = cimagf(p[0][i1]); c1 = crealf(p[0][i1]); u1[0][i1] = 0.0; u2[0][i1] = 0.0; u3[0][i1] = 0.0; for(j2=0; j2<n4; j2++) for(j1=0; j1<n3; j1++) { if((j1+j2)%2==0) continue; u1[0][i1] += 2.0*in[j2][j1][0][i1]*POW(s1, j1)*POW(c1,j2); u2[0][i1] += 2.0*in[j2][j1][0][i1]*j1*POW(s1, j1-1)*POW(c1,j2); u3[0][i1] += 2.0*in[j2][j1][0][i1]*POW(s1, j1)*j2*POW(c1,j2-1); } } if(verb) { for(i1=0, norm=0.0; i1<n1*n2; i1++) norm += (u1[0][i1]*u1[0][i1]); sf_warning("res1 %d %g", it+1, sqrtf(norm/n1/n2)); } if(use_divn) { for(i1=0, c1=0.0, s1=0.0; i1<n1*n2; i1++) { c1 += (u2[0][i1]*u2[0][i1]); s1 += (u3[0][i1]*u3[0][i1]); } c1=sqrtf(c1/(n1*n2)); s1=sqrtf(s1/(n1*n2)); for(i1=0; i1<n1*n2; i1++) { u1[0][i1] /= c1; u2[0][i1] /= c1; } sf_divn(u1[0], u2[0], u4[0]); for(i1=0; i1<n1*n2; i1++) { u1[0][i1] *= c1/s1; u3[0][i1] /= s1; } sf_divn(u1[0], u3[0], u5[0]); }else{ for(i1=0; i1<n1*n2; i1++) { u4[0][i1] = divn(u1[0][i1], u2[0][i1]); u5[0][i1] = divn(u1[0][i1], u3[0][i1]); } } for(i1=0; i1<n1*n2; i1++) { p[0][i1] -= eta * sf_cmplx(u5[0][i1], u4[0][i1]); p[0][i1] = p[0][i1]*r/(cabsf(p[0][i1])+ 1E-15); } } for(i1=0; i1<n1*n2; i1++) dip[0][i1] = atan(tan(cargf(p[0][i1]))); }
ld = clogl(ld); TEST_TRACE(C99 7.3.8.1) d = cabs(d); f = cabsf(f); ld = cabsl(ld); TEST_TRACE(C99 7.3.8.2) d = cpow(d, d); f = cpowf(f, f); ld = cpowl(ld, ld); TEST_TRACE(C99 7.3.8.3) d = csqrt(d); f = csqrtf(f); ld = csqrtl(ld); TEST_TRACE(C99 7.3.9.1) d = carg(d); f = cargf(f); ld = cargl(ld); TEST_TRACE(C99 7.3.9.2) d = cimag(d); f = cimagf(f); ld = cimagl(ld); TEST_TRACE(C99 7.3.9.3) d = conj(d); f = conjf(f); ld = conjl(ld); TEST_TRACE(C99 7.3.9.4) d = cproj(d); f = cprojf(f); ld = cprojl(ld); } TEST_TRACE(C99 7.3.9.5)
int main(int argc, char*argv[]) { srand( time(NULL) ); // options float phase_offset = M_PI / 4.0f; // phase offset float frequency_offset = 0.3f; // frequency offset float pll_bandwidth = 0.01f; // PLL bandwidth float zeta = 1/sqrtf(2.0f); // PLL damping factor float K = 1000.0f; // PLL loop gain unsigned int n=512; // number of iterations int dopt; while ((dopt = getopt(argc,argv,"uhb:z:K:n:p:f:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 'b': pll_bandwidth = atof(optarg); break; case 'z': zeta = atof(optarg); break; case 'K': K = atof(optarg); break; case 'n': n = atoi(optarg); break; case 'p': phase_offset = atof(optarg); break; case 'f': frequency_offset= atof(optarg); break; default: exit(1); } } unsigned int d=n/32; // print every "d" lines // validate input if (pll_bandwidth <= 0.0f) { fprintf(stderr,"error: bandwidth must be greater than 0\n"); exit(1); } else if (zeta <= 0.0f) { fprintf(stderr,"error: damping factor must be greater than 0\n"); exit(1); } else if (K <= 0.0f) { fprintf(stderr,"error: loop gain must be greater than 0\n"); exit(1); } // data arrays float complex x[n]; // input complex sinusoid float complex y[n]; // output complex sinusoid float phase_error[n]; // output phase error // generate PLL filter float b[3]; float a[3]; iirdes_pll_active_lag(pll_bandwidth, zeta, K, b, a); iirfilt_rrrf pll = iirfilt_rrrf_create(b,3,a,3); iirfilt_rrrf_print(pll); unsigned int i; float phi; for (i=0; i<n; i++) { phi = phase_offset + i*frequency_offset; x[i] = cexpf(_Complex_I*phi); } // run loop float theta = 0.0f; y[0] = 1.0f; for (i=0; i<n; i++) { // generate complex sinusoid y[i] = cexpf(_Complex_I*theta); // compute phase error phase_error[i] = cargf(x[i]*conjf(y[i])); // update pll iirfilt_rrrf_execute(pll, phase_error[i], &theta); // print phase error if ((i)%d == 0 || i==n-1 || i==0) printf("%4u : phase error = %12.8f\n", i, phase_error[i]); } // destroy filter object iirfilt_rrrf_destroy(pll); // write output file FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n"); fprintf(fid,"n = %u;\n", n); fprintf(fid,"x = zeros(1,n);\n"); fprintf(fid,"y = zeros(1,n);\n"); for (i=0; i<n; i++) { fprintf(fid,"x(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(x[i]), cimagf(x[i])); fprintf(fid,"y(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(y[i]), cimagf(y[i])); fprintf(fid,"e(%4u) = %12.4e;\n", i+1, phase_error[i]); } fprintf(fid,"t=0:(n-1);\n"); fprintf(fid,"figure;\n"); fprintf(fid,"subplot(2,1,1);\n"); fprintf(fid," plot(t,real(x),t,real(y));\n"); fprintf(fid," xlabel('time');\n"); fprintf(fid," ylabel('real');\n"); fprintf(fid,"subplot(2,1,2);\n"); fprintf(fid," plot(t,imag(x),t,imag(y));\n"); fprintf(fid," xlabel('time');\n"); fprintf(fid," ylabel('imag');\n"); fprintf(fid,"figure;\n"); fprintf(fid,"plot(t,e);\n"); fprintf(fid,"xlabel('time');\n"); fprintf(fid,"ylabel('phase error');\n"); fprintf(fid,"grid on;\n"); fclose(fid); printf("results written to %s.\n",OUTPUT_FILENAME); printf("done.\n"); return 0; }
int main() { // parameters float phase_offset = 0.8f; // carrier phase offset float frequency_offset = 0.01f; // carrier frequency offset float wn = 0.05f; // pll bandwidth float zeta = 0.707f; // pll damping factor float K = 1000; // pll loop gain unsigned int n = 256; // number of samples unsigned int d = n/32; // print every "d" lines // float theta[n]; // input phase float complex x[n]; // input sinusoid float phi[n]; // output phase float complex y[n]; // output sinusoid // generate iir loop filter object iirfilt_rrrf H = iirfilt_rrrf_create_pll(wn, zeta, K); iirfilt_rrrf_print(H); unsigned int i; // generate input float t=phase_offset; float dt = frequency_offset; for (i=0; i<n; i++) { theta[i] = t; x[i] = cexpf(_Complex_I*theta[i]); t += dt; } // run loop float phi_hat=0.0f; for (i=0; i<n; i++) { y[i] = cexpf(_Complex_I*phi_hat); // compute error float e = cargf(x[i]*conjf(y[i])); if ( (i%d)==0 ) printf("e(%3u) = %12.8f;\n", i, e); // filter error iirfilt_rrrf_execute(H,e,&phi_hat); phi[i] = phi_hat; } // destroy filter iirfilt_rrrf_destroy(H); // open output file FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"clear all;\n"); fprintf(fid,"n=%u;\n",n); for (i=0; i<n; i++) { fprintf(fid,"theta(%3u) = %16.8e;\n", i+1, theta[i]); fprintf(fid," phi(%3u) = %16.8e;\n", i+1, phi[i]); } fprintf(fid,"t=0:(n-1);\n"); fprintf(fid,"figure;\n"); fprintf(fid,"plot(t,theta,t,phi);\n"); fprintf(fid,"xlabel('sample index');\n"); fprintf(fid,"ylabel('phase');\n"); fclose(fid); printf("output written to %s.\n", OUTPUT_FILENAME); printf("done.\n"); return 0; }
// complex logarithm float complex liquid_clogf(float complex _z) { return logf(cabsf(_z)) + _Complex_I*cargf(_z); }
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; }
// 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; }
float complex sandbox_clogf(float complex _z) { return logf(cabsf(_z)) + _Complex_I*cargf(_z); }
int main(int argc, char*argv[]) { // options unsigned int m = 3; // number of bits/symbol unsigned int k = 0; // filter samples/symbol unsigned int num_symbols = 200; // number of data symbols float SNRdB = 40.0f; // signal-to-noise ratio [dB] float cfo = 0.0f; // carrier frequency offset float cpo = 0.0f; // carrier phase offset float tau = 0.0f; // fractional symbol timing offset float bandwidth = 0.20; // frequency spacing int dopt; while ((dopt = getopt(argc,argv,"hm:k:b:n:s:F:P:T:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'm': m = atoi(optarg); break; case 'k': k = atoi(optarg); break; case 'b': bandwidth = atof(optarg); break; case 'n': num_symbols = atoi(optarg); break; case 's': SNRdB = atof(optarg); break; case 'F': cfo = atof(optarg); break; case 'P': cpo = atof(optarg); break; case 'T': tau = atof(optarg); break; default: exit(1); } } unsigned int i; unsigned int j; // derived values if (k == 0) k = 2 << m; // set samples per symbol if not otherwise specified unsigned int num_samples = k*num_symbols; unsigned int M = 1 << m; float nstd = powf(10.0f, -SNRdB/20.0f); float M2 = 0.5f*(float)(M-1); // validate input if (k < M) { fprintf(stderr,"errors: %s, samples/symbol must be at least modulation size (M=%u)\n", __FILE__,M); exit(1); } else if (k > 2048) { fprintf(stderr,"errors: %s, samples/symbol exceeds maximum (2048)\n", __FILE__); exit(1); } else if (M > 1024) { fprintf(stderr,"errors: %s, modulation size (M=%u) exceeds maximum (1024)\n", __FILE__, M); exit(1); } else if (bandwidth <= 0.0f || bandwidth >= 0.5f) { fprintf(stderr,"errors: %s, bandwidht must be in (0,0.5)\n", __FILE__); exit(1); } // compute demodulation FFT size such that FFT output bin frequencies are // as close to modulated frequencies as possible unsigned int K = 0; // demodulation FFT size float df = bandwidth / M2; // frequency spacing float err_min = 1e9f; unsigned int K_min = k; // minimum FFT size unsigned int K_max = k*4 < 16 ? 16 : k*4; // maximum FFT size unsigned int K_hat; for (K_hat=K_min; K_hat<=K_max; K_hat++) { // compute candidate FFT size float v = 0.5f*df * (float)K_hat; // bin spacing float err = fabsf( roundf(v) - v ); // fractional bin spacing // print results printf(" K_hat = %4u : v = %12.8f, err=%12.8f %s\n", K_hat, v, err, err < err_min ? "*" : ""); // save best result if (K_hat==K_min || err < err_min) { K = K_hat; err_min = err; } // perfect match; no need to continue searching if (err < 1e-6f) break; } // arrays unsigned int sym_in[num_symbols]; // input symbols float complex x[num_samples]; // transmitted signal float complex y[num_samples]; // received signal unsigned int sym_out[num_symbols]; // output symbols // determine demodulation mapping between tones and frequency bins // TODO: use gray coding unsigned int demod_map[M]; for (i=0; i<M; i++) { // print frequency bins float freq = ((float)i - M2) * bandwidth / M2; float idx = freq * (float)K; unsigned int index = (unsigned int) (idx < 0 ? roundf(idx + K) : roundf(idx)); demod_map[i] = index; printf(" s=%3u, f = %12.8f, index=%3u\n", i, freq, index); } // check for uniqueness for (i=1; i<M; i++) { if (demod_map[i] == demod_map[i-1]) { fprintf(stderr,"warning: demod map is not unique; consider increasing bandwidth\n"); break; } } // generate message symbols and modulate // TODO: use gray coding for (i=0; i<num_symbols; i++) { // generate random symbol sym_in[i] = rand() % M; // compute frequency float dphi = 2*M_PI*((float)sym_in[i] - M2) * bandwidth / M2; // generate random phase float phi = randf() * 2 * M_PI; // modulate symbol for (j=0; j<k; j++) x[i*k+j] = cexpf(_Complex_I*phi + _Complex_I*j*dphi); } // push through channel for (i=0; i<num_samples; i++) y[i] = x[i] + nstd*(randnf() + _Complex_I*randnf())*M_SQRT1_2; #if 0 // demodulate signal: high SNR method float complex buf_time[k]; unsigned int n = 0; j = 0; for (i=0; i<num_samples; i++) { // start filling time buffer with samples (assume perfect symbol timing) buf_time[n++] = y[i]; // demodulate symbol if (n==k) { // reset counter n = 0; // estimate frequency float complex metric = 0; unsigned int s; for (s=1; s<k; s++) metric += buf_time[s] * conjf(buf_time[s-1]); float dphi_hat = cargf(metric) / (2*M_PI); unsigned int v=( (unsigned int) roundf(dphi_hat*M2/bandwidth + M2) ) % M; sym_out[j++] = v; printf("%3u : %12.8f : %u\n", j, dphi_hat, v); } } #else // demodulate signal: least-squares method float complex buf_time[K]; float complex buf_freq[K]; fftplan fft = fft_create_plan(K, buf_time, buf_freq, LIQUID_FFT_FORWARD, 0); for (i=0; i<K; i++) buf_time[i] = 0.0f; unsigned int n = 0; j = 0; for (i=0; i<num_samples; i++) { // start filling time buffer with samples (assume perfect symbol timing) buf_time[n++] = y[i]; // demodulate symbol if (n==k) { // reset counter n = 0; // compute transform, storing result in 'buf_freq' fft_execute(fft); // find maximum by looking at particular bins float vmax = 0; unsigned int s; unsigned int s_opt = 0; for (s=0; s<M; s++) { float v = cabsf( buf_freq[demod_map[s]] ); if (s==0 || v > vmax) { s_opt = s; vmax =v; } } // save best result sym_out[j++] = s_opt; } } // destroy fft object fft_destroy_plan(fft); #endif // count errors unsigned int num_symbol_errors = 0; for (i=0; i<num_symbols; i++) num_symbol_errors += (sym_in[i] == sym_out[i]) ? 0 : 1; printf("symbol errors: %u / %u\n", num_symbol_errors, num_symbols); // compute power spectral density of received signal unsigned int nfft = 1200; float psd[nfft]; spgramcf_estimate_psd(nfft, y, num_samples, psd); // // export results // // truncate to at most 10 symbols if (num_symbols > 10) num_symbols = 10; num_samples = k*num_symbols; FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all\n"); fprintf(fid,"close all\n"); fprintf(fid,"k = %u;\n", k); fprintf(fid,"M = %u;\n", M); fprintf(fid,"num_symbols = %u;\n", num_symbols); fprintf(fid,"num_samples = %u;\n", num_samples); fprintf(fid,"nfft = %u;\n", nfft); fprintf(fid,"x = zeros(1,num_samples);\n"); fprintf(fid,"y = zeros(1,num_samples);\n"); for (i=0; i<num_samples; i++) { fprintf(fid,"x(%4u) = %12.8f + j*%12.8f;\n", i+1, crealf(x[i]), cimagf(x[i])); fprintf(fid,"y(%4u) = %12.8f + j*%12.8f;\n", i+1, crealf(y[i]), cimagf(y[i])); } // save power spectral density fprintf(fid,"psd = zeros(1,nfft);\n"); for (i=0; i<nfft; i++) fprintf(fid,"psd(%4u) = %12.8f;\n", i+1, psd[i]); fprintf(fid,"t=[0:(num_samples-1)]/k;\n"); fprintf(fid,"i = 1:k:num_samples;\n"); fprintf(fid,"figure;\n"); // plot time signal fprintf(fid,"subplot(2,1,1),\n"); fprintf(fid,"hold on;\n"); fprintf(fid," plot(t,real(y),'-', 'Color',[0 0.3 0.5]);\n"); fprintf(fid," plot(t,imag(y),'-', 'Color',[0 0.5 0.3]);\n"); fprintf(fid,"hold off;\n"); fprintf(fid,"ymax = ceil(max(abs(y))*5)/5;\n"); fprintf(fid,"axis([0 num_symbols -ymax ymax]);\n"); fprintf(fid,"xlabel('time');\n"); fprintf(fid,"ylabel('x(t)');\n"); fprintf(fid,"grid on;\n"); // plot PSD fprintf(fid,"subplot(2,1,2),\n"); fprintf(fid,"f = [0:(nfft-1)]/nfft - 0.5;\n"); fprintf(fid,"plot(f,psd,'LineWidth',1.5,'Color',[0.5 0 0]);\n"); fprintf(fid,"axis([-0.5 0.5 -40 40]);\n"); fprintf(fid,"xlabel('Normalized Frequency [f/F_s]');\n"); fprintf(fid,"ylabel('PSD [dB]');\n"); fprintf(fid,"grid on;\n"); fclose(fid); printf("results written to '%s'\n", OUTPUT_FILENAME); return 0; }
// 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 } }
int main(int argc, char*argv[]) { // options unsigned int k = 8; // filter samples/symbol unsigned int bps= 1; // number of bits/symbol float h = 0.5f; // modulation index (h=1/2 for MSK) unsigned int num_data_symbols = 20; // number of data symbols float SNRdB = 80.0f; // signal-to-noise ratio [dB] float cfo = 0.0f; // carrier frequency offset float cpo = 0.0f; // carrier phase offset float tau = 0.0f; // fractional symbol offset enum { TXFILT_SQUARE=0, TXFILT_RCOS_FULL, TXFILT_RCOS_HALF, TXFILT_GMSK, } tx_filter_type = TXFILT_SQUARE; float gmsk_bt = 0.35f; // GMSK bandwidth-time factor int dopt; while ((dopt = getopt(argc,argv,"ht:k:b:H:B:n:s:F:P:T:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 't': if (strcmp(optarg,"square")==0) { tx_filter_type = TXFILT_SQUARE; } else if (strcmp(optarg,"rcos-full")==0) { tx_filter_type = TXFILT_RCOS_FULL; } else if (strcmp(optarg,"rcos-half")==0) { tx_filter_type = TXFILT_RCOS_HALF; } else if (strcmp(optarg,"gmsk")==0) { tx_filter_type = TXFILT_GMSK; } else { fprintf(stderr,"error: %s, unknown filter type '%s'\n", argv[0], optarg); exit(1); } break; case 'k': k = atoi(optarg); break; case 'b': bps = atoi(optarg); break; case 'H': h = atof(optarg); break; case 'B': gmsk_bt = atof(optarg); break; case 'n': num_data_symbols = atoi(optarg); break; case 's': SNRdB = atof(optarg); break; case 'F': cfo = atof(optarg); break; case 'P': cpo = atof(optarg); break; case 'T': tau = atof(optarg); break; default: exit(1); } } unsigned int i; // derived values unsigned int num_symbols = num_data_symbols; unsigned int num_samples = k*num_symbols; unsigned int M = 1 << bps; // constellation size float nstd = powf(10.0f, -SNRdB/20.0f); // arrays unsigned char sym_in[num_symbols]; // input symbols float phi[num_samples]; // transmitted phase float complex x[num_samples]; // transmitted signal float complex y[num_samples]; // received signal float complex z[num_samples]; // output... //unsigned char sym_out[num_symbols]; // output symbols unsigned int ht_len = 0; unsigned int tx_delay = 0; float * ht = NULL; switch (tx_filter_type) { case TXFILT_SQUARE: // regular MSK ht_len = k; tx_delay = 1; ht = (float*) malloc(ht_len *sizeof(float)); for (i=0; i<ht_len; i++) ht[i] = h * M_PI / (float)k; break; case TXFILT_RCOS_FULL: // full-response raised-cosine pulse ht_len = k; tx_delay = 1; ht = (float*) malloc(ht_len *sizeof(float)); for (i=0; i<ht_len; i++) ht[i] = h * M_PI / (float)k * (1.0f - cosf(2.0f*M_PI*i/(float)ht_len)); break; case TXFILT_RCOS_HALF: // partial-response raised-cosine pulse ht_len = 3*k; tx_delay = 2; ht = (float*) malloc(ht_len *sizeof(float)); for (i=0; i<ht_len; i++) ht[i] = 0.0f; for (i=0; i<2*k; i++) ht[i+k/2] = h * 0.5f * M_PI / (float)k * (1.0f - cosf(2.0f*M_PI*i/(float)(2*k))); break; case TXFILT_GMSK: ht_len = 2*k*3+1+k; tx_delay = 4; ht = (float*) malloc(ht_len *sizeof(float)); for (i=0; i<ht_len; i++) ht[i] = 0.0f; liquid_firdes_gmsktx(k,3,gmsk_bt,0.0f,&ht[k/2]); for (i=0; i<ht_len; i++) ht[i] *= h * 2.0f / (float)k; break; default: fprintf(stderr,"error: %s, invalid tx filter type\n", argv[0]); exit(1); } for (i=0; i<ht_len; i++) printf("ht(%3u) = %12.8f;\n", i+1, ht[i]); firinterp_rrrf interp_tx = firinterp_rrrf_create(k, ht, ht_len); // generate symbols and interpolate // phase-accumulating filter (trapezoidal integrator) float b[2] = {0.5f, 0.5f}; if (tx_filter_type == TXFILT_SQUARE) { // square filter: rectangular integration with one sample of delay b[0] = 0.0f; b[1] = 1.0f; } float a[2] = {1.0f, -1.0f}; iirfilt_rrrf integrator = iirfilt_rrrf_create(b,2,a,2); float theta = 0.0f; for (i=0; i<num_symbols; i++) { sym_in[i] = rand() % M; float v = 2.0f*sym_in[i] - (float)(M-1); // +/-1, +/-3, ... +/-(M-1) firinterp_rrrf_execute(interp_tx, v, &phi[k*i]); // accumulate phase unsigned int j; for (j=0; j<k; j++) { iirfilt_rrrf_execute(integrator, phi[i*k+j], &theta); x[i*k+j] = cexpf(_Complex_I*theta); } } iirfilt_rrrf_destroy(integrator); // push through channel for (i=0; i<num_samples; i++) { // add carrier frequency/phase offset y[i] = x[i]*cexpf(_Complex_I*(cfo*i + cpo)); // add noise y[i] += nstd*(randnf() + _Complex_I*randnf())*M_SQRT1_2; } // create decimator unsigned int m = 3; float bw = 0.0f; float beta = 0.0f; firfilt_crcf decim_rx = NULL; switch (tx_filter_type) { case TXFILT_SQUARE: //bw = 0.9f / (float)k; bw = 0.4f; decim_rx = firfilt_crcf_create_kaiser(2*k*m+1, bw, 60.0f, 0.0f); firfilt_crcf_set_scale(decim_rx, 2.0f * bw); break; case TXFILT_RCOS_FULL: if (M==2) { decim_rx = firfilt_crcf_create_rnyquist(LIQUID_FIRFILT_GMSKRX,k,m,0.5f,0); firfilt_crcf_set_scale(decim_rx, 1.33f / (float)k); } else { decim_rx = firfilt_crcf_create_rnyquist(LIQUID_FIRFILT_GMSKRX,k/2,2*m,0.9f,0); firfilt_crcf_set_scale(decim_rx, 3.25f / (float)k); } break; case TXFILT_RCOS_HALF: if (M==2) { decim_rx = firfilt_crcf_create_rnyquist(LIQUID_FIRFILT_GMSKRX,k,m,0.3f,0); firfilt_crcf_set_scale(decim_rx, 1.10f / (float)k); } else { decim_rx = firfilt_crcf_create_rnyquist(LIQUID_FIRFILT_GMSKRX,k/2,2*m,0.27f,0); firfilt_crcf_set_scale(decim_rx, 2.90f / (float)k); } break; case TXFILT_GMSK: bw = 0.5f / (float)k; // TODO: figure out beta value here beta = (M == 2) ? 0.8*gmsk_bt : 1.0*gmsk_bt; decim_rx = firfilt_crcf_create_rnyquist(LIQUID_FIRFILT_GMSKRX,k,m,beta,0); firfilt_crcf_set_scale(decim_rx, 2.0f * bw); break; default: fprintf(stderr,"error: %s, invalid tx filter type\n", argv[0]); exit(1); } printf("bw = %f\n", bw); // run receiver unsigned int n=0; unsigned int num_errors = 0; unsigned int num_symbols_checked = 0; float complex z_prime = 0.0f; for (i=0; i<num_samples; i++) { // push through filter firfilt_crcf_push(decim_rx, y[i]); firfilt_crcf_execute(decim_rx, &z[i]); // decimate output if ( (i%k)==0 ) { // compute instantaneous frequency scaled by modulation index float phi_hat = cargf(conjf(z_prime) * z[i]) / (h * M_PI); // estimate transmitted symbol float v = (phi_hat + (M-1.0))*0.5f; unsigned int sym_out = ((int) roundf(v)) % M; // save current point z_prime = z[i]; // print result to screen printf("%3u : %12.8f + j%12.8f, <f=%8.4f : %8.4f> (%1u)", n, crealf(z[i]), cimagf(z[i]), phi_hat, v, sym_out); if (n >= m+tx_delay) { num_errors += (sym_out == sym_in[n-m-tx_delay]) ? 0 : 1; num_symbols_checked++; printf(" (%1u)\n", sym_in[n-m-tx_delay]); } else { printf("\n"); } n++; } } // print number of errors printf("errors : %3u / %3u\n", num_errors, num_symbols_checked); // destroy objects firinterp_rrrf_destroy(interp_tx); firfilt_crcf_destroy(decim_rx); // compute power spectral density of transmitted signal unsigned int nfft = 1024; float psd[nfft]; spgramcf periodogram = spgramcf_create_kaiser(nfft, nfft/2, 8.0f); spgramcf_estimate_psd(periodogram, y, num_samples, psd); spgramcf_destroy(periodogram); // // export results // FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all\n"); fprintf(fid,"close all\n"); fprintf(fid,"k = %u;\n", k); fprintf(fid,"h = %f;\n", h); fprintf(fid,"num_symbols = %u;\n", num_symbols); fprintf(fid,"num_samples = %u;\n", num_samples); fprintf(fid,"nfft = %u;\n", nfft); fprintf(fid,"delay = %u; %% receive filter delay\n", tx_delay); fprintf(fid,"x = zeros(1,num_samples);\n"); fprintf(fid,"y = zeros(1,num_samples);\n"); fprintf(fid,"z = zeros(1,num_samples);\n"); fprintf(fid,"phi = zeros(1,num_samples);\n"); for (i=0; i<num_samples; i++) { fprintf(fid,"x(%4u) = %12.8f + j*%12.8f;\n", i+1, crealf(x[i]), cimagf(x[i])); fprintf(fid,"y(%4u) = %12.8f + j*%12.8f;\n", i+1, crealf(y[i]), cimagf(y[i])); fprintf(fid,"z(%4u) = %12.8f + j*%12.8f;\n", i+1, crealf(z[i]), cimagf(z[i])); fprintf(fid,"phi(%4u) = %12.8f;\n", i+1, phi[i]); } // save PSD fprintf(fid,"psd = zeros(1,nfft);\n"); for (i=0; i<nfft; i++) fprintf(fid,"psd(%4u) = %12.8f;\n", i+1, psd[i]); fprintf(fid,"t=[0:(num_samples-1)]/k;\n"); fprintf(fid,"i = 1:k:num_samples;\n"); fprintf(fid,"figure;\n"); fprintf(fid,"subplot(3,4,1:3);\n"); fprintf(fid," plot(t,real(x),'-', t(i),real(x(i)),'bs','MarkerSize',4,...\n"); fprintf(fid," t,imag(x),'-', t(i),imag(x(i)),'gs','MarkerSize',4);\n"); fprintf(fid," axis([0 num_symbols -1.2 1.2]);\n"); fprintf(fid," xlabel('time');\n"); fprintf(fid," ylabel('x(t)');\n"); fprintf(fid," grid on;\n"); fprintf(fid,"subplot(3,4,5:7);\n"); fprintf(fid," plot(t-delay,real(z),'-', t(i)-delay,real(z(i)),'bs','MarkerSize',4,...\n"); fprintf(fid," t-delay,imag(z),'-', t(i)-delay,imag(z(i)),'gs','MarkerSize',4);\n"); fprintf(fid," axis([0 num_symbols -1.2 1.2]);\n"); fprintf(fid," xlabel('time');\n"); fprintf(fid," ylabel('\"matched\" filter output');\n"); fprintf(fid," grid on;\n"); // plot I/Q constellations fprintf(fid,"subplot(3,4,4);\n"); fprintf(fid," plot(real(y),imag(y),'-',real(y(i)),imag(y(i)),'rs','MarkerSize',3);\n"); fprintf(fid," xlabel('I');\n"); fprintf(fid," ylabel('Q');\n"); fprintf(fid," axis([-1 1 -1 1]*1.2);\n"); fprintf(fid," axis square;\n"); fprintf(fid," grid on;\n"); fprintf(fid,"subplot(3,4,8);\n"); fprintf(fid," plot(real(z),imag(z),'-',real(z(i)),imag(z(i)),'rs','MarkerSize',3);\n"); fprintf(fid," xlabel('I');\n"); fprintf(fid," ylabel('Q');\n"); fprintf(fid," axis([-1 1 -1 1]*1.2);\n"); fprintf(fid," axis square;\n"); fprintf(fid," grid on;\n"); // plot PSD fprintf(fid,"f = [0:(nfft-1)]/nfft - 0.5;\n"); fprintf(fid,"subplot(3,4,9:12);\n"); fprintf(fid," plot(f,psd,'LineWidth',1.5);\n"); fprintf(fid," axis([-0.5 0.5 -40 20]);\n"); fprintf(fid," xlabel('Normalized Frequency [f/F_s]');\n"); fprintf(fid," ylabel('PSD [dB]');\n"); fprintf(fid," grid on;\n"); #if 0 fprintf(fid,"figure;\n"); fprintf(fid," %% compute instantaneous received frequency\n"); fprintf(fid," freq_rx = arg( conj(z(:)) .* circshift(z(:),-1) )';\n"); fprintf(fid," freq_rx(1:(k*delay)) = 0;\n"); fprintf(fid," freq_rx(end) = 0;\n"); fprintf(fid," %% compute instantaneous tx/rx phase\n"); if (tx_filter_type == TXFILT_SQUARE) { fprintf(fid," theta_tx = filter([0 1],[1 -1],phi)/(h*pi);\n"); fprintf(fid," theta_rx = filter([0 1],[1 -1],freq_rx)/(h*pi);\n"); } else { fprintf(fid," theta_tx = filter([0.5 0.5],[1 -1],phi)/(h*pi);\n"); fprintf(fid," theta_rx = filter([0.5 0.5],[1 -1],freq_rx)/(h*pi);\n"); } fprintf(fid," %% plot instantaneous tx/rx phase\n"); fprintf(fid," plot(t, theta_tx,'-b', t(i), theta_tx(i),'sb',...\n"); fprintf(fid," t-delay,theta_rx,'-r', t(i)-delay,theta_rx(i),'sr');\n"); fprintf(fid," xlabel('time');\n"); fprintf(fid," ylabel('instantaneous phase/(h \\pi)');\n"); fprintf(fid," legend('transmitted','syms','received/filtered','syms','location','northwest');\n"); fprintf(fid," grid on;\n"); #else // plot filter response fprintf(fid,"ht_len = %u;\n", ht_len); fprintf(fid,"ht = zeros(1,ht_len);\n"); for (i=0; i<ht_len; i++) fprintf(fid,"ht(%4u) = %12.8f;\n", i+1, ht[i]); fprintf(fid,"gt1 = filter([0.5 0.5],[1 -1],ht) / (pi*h);\n"); fprintf(fid,"gt2 = filter([0.0 1.0],[1 -1],ht) / (pi*h);\n"); fprintf(fid,"tfilt = [0:(ht_len-1)]/k - delay + 0.5;\n"); fprintf(fid,"figure;\n"); fprintf(fid,"plot(tfilt,ht, '-x','MarkerSize',4,...\n"); fprintf(fid," tfilt,gt1,'-x','MarkerSize',4,...\n"); fprintf(fid," tfilt,gt2,'-x','MarkerSize',4);\n"); fprintf(fid,"axis([tfilt(1) tfilt(end) -0.1 1.1]);\n"); fprintf(fid,"legend('pulse','trap. int.','rect. int.','location','northwest');\n"); fprintf(fid,"grid on;\n"); #endif fclose(fid); printf("results written to '%s'\n", OUTPUT_FILENAME); // free allocated filter memory free(ht); return 0; }
void docomplexf (void) { #ifndef NO_FLOAT complex float ca, cb, cc; float f1; ca = 1.0 + 1.0 * I; cb = 1.0 - 1.0 * I; f1 = cabsf (ca); fprintf (stdout, "cabsf : %f\n", f1); cc = cacosf (ca); fprintf (stdout, "cacosf : %f %fi\n", crealf (cc), cimagf (cc)); cc = cacoshf (ca); fprintf (stdout, "cacoshf: %f %fi\n", crealf (cc), cimagf (cc)); f1 = cargf (ca); fprintf (stdout, "cargf : %f\n", f1); cc = casinf (ca); fprintf (stdout, "casinf : %f %fi\n", crealf (cc), cimagf (cc)); cc = casinhf (ca); fprintf (stdout, "casinhf: %f %fi\n", crealf (cc), cimagf (cc)); cc = catanf (ca); fprintf (stdout, "catanf : %f %fi\n", crealf (cc), cimagf (cc)); cc = catanhf (ca); fprintf (stdout, "catanhf: %f %fi\n", crealf (cc), cimagf (cc)); cc = ccosf (ca); fprintf (stdout, "ccosf : %f %fi\n", crealf (cc), cimagf (cc)); cc = ccoshf (ca); fprintf (stdout, "ccoshf : %f %fi\n", crealf (cc), cimagf (cc)); cc = cexpf (ca); fprintf (stdout, "cexpf : %f %fi\n", crealf (cc), cimagf (cc)); f1 = cimagf (ca); fprintf (stdout, "cimagf : %f\n", f1); cc = clogf (ca); fprintf (stdout, "clogf : %f %fi\n", crealf (cc), cimagf (cc)); cc = conjf (ca); fprintf (stdout, "conjf : %f %fi\n", crealf (cc), cimagf (cc)); cc = cpowf (ca, cb); fprintf (stdout, "cpowf : %f %fi\n", crealf (cc), cimagf (cc)); cc = cprojf (ca); fprintf (stdout, "cprojf : %f %fi\n", crealf (cc), cimagf (cc)); f1 = crealf (ca); fprintf (stdout, "crealf : %f\n", f1); cc = csinf (ca); fprintf (stdout, "csinf : %f %fi\n", crealf (cc), cimagf (cc)); cc = csinhf (ca); fprintf (stdout, "csinhf : %f %fi\n", crealf (cc), cimagf (cc)); cc = csqrtf (ca); fprintf (stdout, "csqrtf : %f %fi\n", crealf (cc), cimagf (cc)); cc = ctanf (ca); fprintf (stdout, "ctanf : %f %fi\n", crealf (cc), cimagf (cc)); cc = ctanhf (ca); fprintf (stdout, "ctanhf : %f %fi\n", crealf (cc), cimagf (cc)); #endif }
TEST(complex, cargf) { ASSERT_EQ(0.0, cargf(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); } }
int main(int argc, char*argv[]) { // set random seed srand( time(NULL) ); // parameters float phase_offset = 0.0f; // initial phase offset float frequency_offset = 0.40f; // initial frequency offset float pll_bandwidth = 0.003f; // phase-locked loop bandwidth unsigned int n = 512; // number of iterations int dopt; while ((dopt = getopt(argc,argv,"uhb:n:p:f:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 'b': pll_bandwidth = atof(optarg); break; case 'n': n = atoi(optarg); break; case 'p': phase_offset = atof(optarg); break; case 'f': frequency_offset= atof(optarg); break; default: exit(1); } } // objects nco_crcf nco_tx = nco_crcf_create(LIQUID_VCO); nco_crcf nco_rx = nco_crcf_create(LIQUID_VCO); // initialize objects nco_crcf_set_phase(nco_tx, phase_offset); nco_crcf_set_frequency(nco_tx, frequency_offset); nco_crcf_pll_set_bandwidth(nco_rx, pll_bandwidth); // generate input float complex x[n]; float complex y[n]; float phase_error[n]; unsigned int i; for (i=0; i<n; i++) { // generate complex sinusoid nco_crcf_cexpf(nco_tx, &x[i]); // update nco nco_crcf_step(nco_tx); } // run loop for (i=0; i<n; i++) { #if 0 // test resetting bandwidth in middle of acquisition if (i == 100) nco_pll_set_bandwidth(nco_rx, pll_bandwidth*0.2f); #endif // generate input nco_crcf_cexpf(nco_rx, &y[i]); // update rx nco object nco_crcf_step(nco_rx); // compute phase error phase_error[i] = cargf(x[i]*conjf(y[i])); // update pll nco_crcf_pll_step(nco_rx, phase_error[i]); // print phase error if ( (i+1)%50 == 0 || i==n-1 || i==0) printf("%4u : phase error = %12.8f\n", i+1, phase_error[i]); } nco_crcf_destroy(nco_tx); nco_crcf_destroy(nco_rx); // write output file FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n"); fprintf(fid,"n = %u;\n", n); fprintf(fid,"x = zeros(1,n);\n"); fprintf(fid,"y = zeros(1,n);\n"); for (i=0; i<n; i++) { fprintf(fid,"x(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(x[i]), cimagf(x[i])); fprintf(fid,"y(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(y[i]), cimagf(y[i])); fprintf(fid,"e(%4u) = %12.4e;\n", i+1, phase_error[i]); } fprintf(fid,"t=0:(n-1);\n"); fprintf(fid,"figure;\n"); fprintf(fid,"subplot(3,1,1);\n"); fprintf(fid," hold on;\n"); fprintf(fid," plot(t,real(x),'Color',[1 1 1]*0.8);\n"); fprintf(fid," plot(t,real(y),'Color',[0 0.2 0.5]);\n"); fprintf(fid," hold off;\n"); fprintf(fid," xlabel('time');\n"); fprintf(fid," ylabel('real');\n"); fprintf(fid," axis([0 n -1.2 1.2]);\n"); fprintf(fid," grid on;\n"); fprintf(fid,"subplot(3,1,2);\n"); fprintf(fid," hold on;\n"); fprintf(fid," plot(t,imag(x),'Color',[1 1 1]*0.8);\n"); fprintf(fid," plot(t,imag(y),'Color',[0 0.5 0.2]);\n"); fprintf(fid," hold off;\n"); fprintf(fid," xlabel('time');\n"); fprintf(fid," ylabel('imag');\n"); fprintf(fid," axis([0 n -1.2 1.2]);\n"); fprintf(fid," grid on;\n"); fprintf(fid,"subplot(3,1,3);\n"); fprintf(fid," plot(t,e,'Color',[0.5 0 0]);\n"); fprintf(fid," xlabel('time');\n"); fprintf(fid," ylabel('phase error');\n"); fprintf(fid," axis([0 n -pi pi]);\n"); fprintf(fid," grid on;\n"); fclose(fid); printf("results written to %s.\n",OUTPUT_FILENAME); printf("done.\n"); return 0; }
// 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 sync_block(int blocksize, csample_t **buffers, float *timediffs, float *phasediffs) { int ri, i; if(blocksize < corrlen) return -1; for(ri = 0; ri < nreceivers; ri++) { csample_t *buf = buffers[ri]; fftwf_complex *floatbuf = fft1in + ri * fft1n; for(i = 0; i < corrlen; i++) floatbuf[i] = (buf[i][0] + I*buf[i][1]) - (127.4f+127.4f*I); } fftwf_execute(fft1plan); for(ri = 1; ri < nreceivers; ri++) { /* cross correlation of receiver number ri and receiver 0 */ fftwf_complex *f1o = fft1out + ri * fft1n; fftwf_complex *f2i = fft2in + (ri-1) * fft2n; /* positive frequencies: */ for(i = 0; i < fft1n/2; i++) f2i[i] = fft1out[i] * conjf(f1o[i]); /* negative frequencies: */ f2i += fft2n - fft1n; for(i = fft1n/2; i < fft1n; i++) f2i[i] = fft1out[i] * conjf(f1o[i]); } fftwf_execute(fft2plan); timediffs[0] = 0; phasediffs[0] = 0; if(sync_debug) printf("%d ",(int)time(NULL)); for(ri = 1; ri < nreceivers; ri++) { fftwf_complex *f2o = fft2out + (ri-1) * fft2n; float maxmagsq = 0, phasedifference; float timedifference = 0; float complex maxc = 0; float y1, y2, y3; int maxi = 1; for(i = 0; i < fft2n; i++) { float complex c = f2o[i]; float magsq = crealf(c)*crealf(c) + cimagf(c)*cimagf(c); if(magsq > maxmagsq) { maxmagsq = magsq; maxc = c; maxi = i; } } /* parabolic interpolation for more fractional sample resolution (math from http://dspguru.com/dsp/howtos/how-to-interpolate-fft-peak ) */ y1 = cabsf(f2o[(maxi-1 + fft2n) % fft2n]); y2 = cabsf(maxc); y3 = cabsf(f2o[(maxi+1 + fft2n) % fft2n]); //printf("%E %E %E ", y1, y2, y3); if(maxi >= fft2n/2) maxi -= fft2n; timedifference = maxi; timedifference += (y3-y1) / (2*(2*y2-y1-y3)); timedifference *= 1.0 / CORRELATION_OVERSAMPLE; timediffs[ri] = timedifference; phasediffs[ri] = phasedifference = cargf(maxc); if(sync_debug) printf("%9.2f %E %6.2f ", timedifference, maxmagsq, 57.2957795 * phasedifference); } if(sync_debug) { printf("\n"); fflush(stdout); } return 0; }
// estimate complex equalizer gain from G0 and G1 using polynomial fit // _q : ofdmframesync object // _order : polynomial order void ofdmframesync_estimate_eqgain_poly(ofdmframesync _q, unsigned int _order) { #if DEBUG_OFDMFRAMESYNC if (_q->debug_enabled) { // copy pre-smoothed gain memmove(_q->G_hat, _q->G, _q->M*sizeof(float complex)); } #endif // polynomial interpolation unsigned int i; unsigned int N = _q->M_pilot + _q->M_data; if (_order > N-1) _order = N-1; if (_order > 10) _order = 10; float x_freq[N]; float y_abs[N]; float y_arg[N]; float p_abs[_order+1]; float p_arg[_order+1]; unsigned int n=0; unsigned int k; 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_NULL) { if (n == N) { fprintf(stderr, "error: ofdmframesync_estimate_eqgain_poly(), pilot subcarrier mismatch\n"); exit(1); } // store resulting... x_freq[n] = (k > _q->M2) ? (float)k - (float)(_q->M) : (float)k; x_freq[n] = x_freq[n] / (float)(_q->M); y_abs[n] = cabsf(_q->G[k]); y_arg[n] = cargf(_q->G[k]); // update counter n++; } } if (n != N) { fprintf(stderr, "error: ofdmframesync_estimate_eqgain_poly(), pilot subcarrier mismatch\n"); exit(1); } // try to unwrap phase for (i=1; i<N; i++) { while ((y_arg[i] - y_arg[i-1]) > M_PI) y_arg[i] -= 2*M_PI; while ((y_arg[i] - y_arg[i-1]) < -M_PI) y_arg[i] += 2*M_PI; } // fit to polynomial polyf_fit(x_freq, y_abs, N, p_abs, _order+1); polyf_fit(x_freq, y_arg, N, p_arg, _order+1); // compute subcarrier gain for (i=0; i<_q->M; i++) { float freq = (i > _q->M2) ? (float)i - (float)(_q->M) : (float)i; freq = freq / (float)(_q->M); float A = polyf_val(p_abs, _order+1, freq); float theta = polyf_val(p_arg, _order+1, freq); _q->G[i] = (_q->p[i] == OFDMFRAME_SCTYPE_NULL) ? 0.0f : A * liquid_cexpjf(theta); } #if 0 for (i=0; i<N; i++) printf("x(%3u) = %12.8f; y_abs(%3u) = %12.8f; y_arg(%3u) = %12.8f;\n", i+1, x_freq[i], i+1, y_abs[i], i+1, y_arg[i]); for (i=0; i<=_order; i++) printf("p_abs(%3u) = %12.8f;\n", i+1, p_abs[i]); for (i=0; i<=_order; i++) printf("p_arg(%3u) = %12.8f;\n", i+1, p_arg[i]); #endif }
static void zarg(long N, complex float* dst, const complex float* src) { for (long i = 0; i < N; i++) dst[i] = cargf( src[i] ); }
// estimate complex equalizer gain from G0 and G1 using polynomial fit void wlanframesync_estimate_eqgain_poly(wlanframesync _q) { // polynomial order unsigned int order = 2; // equalizer (polynomial) float x_eq[52]; // frequency array float y_eq_abs[52]; // magnitude array float y_eq_arg[52]; // phase array float p_eq_abs[order+1]; // polynomial coefficients (magnitude) float p_eq_arg[order+1]; // polynomial coefficients (phase) // average complex gains unsigned int i; unsigned int k; unsigned int n=0; for (i=0; i<64; i++) { // start at mid-point (effective fftshift) k = (i + 32) % 64; if (k == 0 || (k>26 && k<38) ) { // NULL subcarrier } else { // validate counter assert(n < 52); // DATA/PILOT subcarrier (S1 enabled) //float complex G = 0.5f*(_q->G1a + _q->G1b); float complex G = _q->G1b[k]; // store resulting... x_eq[n] = (k > 31) ? (float)k - (float)(64) : (float)k; x_eq[n] = x_eq[n] / (float)(64); y_eq_abs[n] = cabsf(G); y_eq_arg[n] = cargf(G); // update counter n++; } } // validate counter assert(n == 52); // try to unwrap phase for (i=1; i<52; i++) { while ((y_eq_arg[i] - y_eq_arg[i-1]) > M_PI) y_eq_arg[i] -= 2*M_PI; while ((y_eq_arg[i] - y_eq_arg[i-1]) < -M_PI) y_eq_arg[i] += 2*M_PI; } // fit to polynomial(s) polyf_fit(x_eq, y_eq_abs, 52, p_eq_abs, order+1); polyf_fit(x_eq, y_eq_arg, 52, p_eq_arg, order+1); // compute subcarrier gain for (i=0; i<64; i++) { if (i == 0 || (i>26 && i<38) ) { // NULL subcarrier _q->G[i] = 0.0f; _q->R[i] = 0.0f; } else { // DATA/PILOT subcarrier (S1 enabled) float freq = (i > 31) ? (float)i - (float)(64) : (float)i; freq = freq / (float)(64); float A = polyf_val(p_eq_abs, order+1, freq); float theta = polyf_val(p_eq_arg, order+1, freq); // composite channel estimation _q->G[i] = A * cexpf(_Complex_I*theta); // composite channel correction // 0.11267 = sqrt(52)/64 _q->R[i] = 0.11267f / (A + 1e-12f) * cexpf(-_Complex_I*theta); } } }
int main(int argc, char **argv) { chest_t eq; cf_t *input = NULL, *ce = NULL, *h = NULL; refsignal_t refs; int i, j, n_port, n_slot, cid, num_re; int ret = -1; int max_cid; FILE *fmatlab = NULL; float mse_mag, mse_phase; parse_args(argc,argv); if (output_matlab) { fmatlab=fopen(output_matlab, "w"); if (!fmatlab) { perror("fopen"); goto do_exit; } } num_re = nof_prb * RE_X_RB * CP_NSYMB(cp); input = malloc(num_re * sizeof(cf_t)); if (!input) { perror("malloc"); goto do_exit; } h = malloc(num_re * sizeof(cf_t)); if (!h) { perror("malloc"); goto do_exit; } ce = malloc(num_re * sizeof(cf_t)); if (!ce) { perror("malloc"); goto do_exit; } if (cell_id == -1) { cid = 0; max_cid = 504; } else { cid = cell_id; max_cid = cell_id; } while(cid <= max_cid) { if (chest_init(&eq, LINEAR, cp, nof_prb, MAX_PORTS)) { fprintf(stderr, "Error initializing equalizer\n"); goto do_exit; } if (chest_ref_LTEDL(&eq, cid)) { fprintf(stderr, "Error initializing reference signal\n"); goto do_exit; } for (n_slot=0;n_slot<NSLOTS_X_FRAME;n_slot++) { for (n_port=0;n_port<MAX_PORTS;n_port++) { if (refsignal_init_LTEDL(&refs, n_port, n_slot, cid, cp, nof_prb)) { fprintf(stderr, "Error initiating CRS slot=%d\n", i); return -1; } bzero(input, sizeof(cf_t) * num_re); for (i=0;i<num_re;i++) { input[i] = 0.5-rand()/RAND_MAX+I*(0.5-rand()/RAND_MAX); } bzero(ce, sizeof(cf_t) * num_re); bzero(h, sizeof(cf_t) * num_re); refsignal_put(&refs, input); refsignal_free(&refs); for (i=0;i<CP_NSYMB(cp);i++) { for (j=0;j<nof_prb * RE_X_RB;j++) { float x = -1+(float) i/CP_NSYMB(cp) + cosf(2 * M_PI * (float) j/nof_prb/RE_X_RB); h[i*nof_prb * RE_X_RB+j] = (3+x) * cexpf(I * x); input[i*nof_prb * RE_X_RB+j] *= h[i*nof_prb * RE_X_RB+j]; } } chest_ce_slot_port(&eq, input, ce, n_slot, n_port); mse_mag = mse_phase = 0; for (i=0;i<num_re;i++) { mse_mag += (cabsf(h[i]) - cabsf(ce[i])) * (cabsf(h[i]) - cabsf(ce[i])) / num_re; mse_phase += (cargf(h[i]) - cargf(ce[i])) * (cargf(h[i]) - cargf(ce[i])) / num_re; } if (check_mse(mse_mag, mse_phase, n_port)) { goto do_exit; } if (fmatlab) { fprintf(fmatlab, "input="); vec_fprint_c(fmatlab, input, num_re); fprintf(fmatlab, ";\n"); fprintf(fmatlab, "h="); vec_fprint_c(fmatlab, h, num_re); fprintf(fmatlab, ";\n"); fprintf(fmatlab, "ce="); vec_fprint_c(fmatlab, ce, num_re); fprintf(fmatlab, ";\n"); chest_fprint(&eq, fmatlab, n_slot, n_port); } } } chest_free(&eq); cid+=10; INFO("cid=%d\n", cid); } ret = 0; do_exit: if (ce) { free(ce); } if (input) { free(input); } if (h) { free(h); } if (!ret) { printf("OK\n"); } else { printf("Error at cid=%d, slot=%d, port=%d\n",cid, n_slot, n_port); } exit(ret); }
void iceFsk3(int * data, const size_t len){ int i,j; int * output = (int* ) malloc(sizeof(int) * len); memset(output, 0x00, len); float fc = 0.1125f; // center frequency size_t adjustedLen = len; // create very simple low-pass filter to remove images (2nd-order Butterworth) float complex iir_buf[3] = {0,0,0}; float b[3] = {0.003621681514929, 0.007243363029857, 0.003621681514929}; float a[3] = {1.000000000000000, -1.822694925196308, 0.837181651256023}; float sample = 0; // input sample read from file float complex x_prime = 1.0f; // save sample for estimating frequency float complex x; for (i=0; i<adjustedLen; ++i) { sample = data[i]+128; // remove DC offset and mix to complex baseband x = (sample - 127.5f) * cexpf( _Complex_I * 2 * M_PI * fc * i ); // apply low-pass filter, removing spectral image (IIR using direct-form II) iir_buf[2] = iir_buf[1]; iir_buf[1] = iir_buf[0]; iir_buf[0] = x - a[1]*iir_buf[1] - a[2]*iir_buf[2]; x = b[0]*iir_buf[0] + b[1]*iir_buf[1] + b[2]*iir_buf[2]; // compute instantaneous frequency by looking at phase difference // between adjacent samples float freq = cargf(x*conjf(x_prime)); x_prime = x; // retain this sample for next iteration output[i] =(freq > 0)? 10 : -10; } // show data for (j=0; j<adjustedLen; ++j) data[j] = output[j]; CmdLtrim("30"); adjustedLen -= 30; // zero crossings. for (j=0; j<adjustedLen; ++j){ if ( data[j] == 10) break; } int startOne =j; for (;j<adjustedLen; ++j){ if ( data[j] == -10 ) break; } int stopOne = j-1; int fieldlen = stopOne-startOne; fieldlen = (fieldlen == 39 || fieldlen == 41)? 40 : fieldlen; fieldlen = (fieldlen == 59 || fieldlen == 51)? 50 : fieldlen; if ( fieldlen != 40 && fieldlen != 50){ printf("Detected field Length: %d \n", fieldlen); printf("Can only handle 40 or 50. Aborting...\n"); return; } // FSK sequence start == 000111 int startPos = 0; for (i =0; i<adjustedLen; ++i){ int dec = 0; for ( j = 0; j < 6*fieldlen; ++j){ dec += data[i + j]; } if (dec == 0) { startPos = i; break; } } printf("000111 position: %d \n", startPos); startPos += 6*fieldlen+5; int bit =0; printf("BINARY\n"); printf("R/40 : "); for (i =startPos ; i < adjustedLen; i += 40){ bit = data[i]>0 ? 1:0; printf("%d", bit ); } printf("\n"); printf("R/50 : "); for (i =startPos ; i < adjustedLen; i += 50){ bit = data[i]>0 ? 1:0; printf("%d", bit ); } printf("\n"); free(output); }
int main() { // parameters float phase_offset = 0.8f; float frequency_offset = 0.01f; float pll_bandwidth = 0.05f; float pll_damping_factor = 0.707f; unsigned int n=256; // number of iterations unsigned int d=n/32; // print every "d" lines // float theta[n]; // input phase float complex x[n]; // input sinusoid float phi[n]; // output phase float complex y[n]; // output sinusoid // generate iir loop filter(s) float a[3]; float b[3]; float wn = pll_bandwidth; float zeta = pll_damping_factor; float K = 10; // loop gain #if 0 // loop filter (active lag) float t1 = K/(wn*wn); float t2 = 2*zeta/wn - 1/K; b[0] = 2*K*(1.+t2/2.0f); b[1] = 2*K*2.; b[2] = 2*K*(1.-t2/2.0f); a[0] = 1 + t1/2.0f; a[1] = -t1; a[2] = -1 + t1/2.0f; #else // loop filter (active PI) float t1 = K/(wn*wn); float t2 = 2*zeta/wn; b[0] = 2*K*(1.+t2/2.0f); b[1] = 2*K*2.; b[2] = 2*K*(1.-t2/2.0f); a[0] = t1/2.0f; a[1] = -t1; a[2] = t1/2.0f; #endif iirfilt_rrrf H = iirfilt_rrrf_create(b,3,a,3); iirfilt_rrrf_print(H); unsigned int i; // generate input float t=phase_offset; float dt = frequency_offset; for (i=0; i<n; i++) { theta[i] = t; x[i] = cexpf(_Complex_I*theta[i]); t += dt; } // run loop float phi_hat=0.0f; for (i=0; i<n; i++) { y[i] = cexpf(_Complex_I*phi_hat); // compute error float e = cargf(x[i]*conjf(y[i])); if ( (i%d)==0 ) printf("e(%3u) = %12.8f;\n", i, e); // filter error iirfilt_rrrf_execute(H,e,&phi_hat); phi[i] = phi_hat; } // destroy filter iirfilt_rrrf_destroy(H); // open output file FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"clear all;\n"); fprintf(fid,"n=%u;\n",n); fprintf(fid,"a(1) = %16.8e;\n", a[0]); fprintf(fid,"a(2) = %16.8e;\n", a[1]); fprintf(fid,"a(3) = %16.8e;\n", a[2]); fprintf(fid,"b(1) = %16.8e;\n", b[0]); fprintf(fid,"b(2) = %16.8e;\n", b[1]); fprintf(fid,"b(3) = %16.8e;\n", b[2]); //fprintf(fid,"figure;\n"); //fprintf(fid,"freqz(b,a);\n"); for (i=0; i<n; i++) { fprintf(fid,"theta(%3u) = %16.8e;\n", i+1, theta[i]); fprintf(fid," phi(%3u) = %16.8e;\n", i+1, phi[i]); } fprintf(fid,"t=0:(n-1);\n"); fprintf(fid,"figure;\n"); fprintf(fid,"plot(t,theta,t,phi);\n"); fprintf(fid,"xlabel('sample index');\n"); fprintf(fid,"ylabel('phase');\n"); fclose(fid); printf("output written to %s.\n", OUTPUT_FILENAME); printf("done.\n"); return 0; }