void autotest_nco_crcf_mix_block_up() { // options unsigned int buf_len = 4096; float phase = 0.7123f; float freq = 0; //0.1324f; float tol = 1e-2f; // create object nco_crcf nco = nco_crcf_create(LIQUID_NCO); nco_crcf_set_phase (nco, phase); nco_crcf_set_frequency(nco, freq); // generate signal float complex buf_0[buf_len]; float complex buf_1[buf_len]; unsigned int i; for (i=0; i<buf_len; i++) buf_0[i] = cexpf(_Complex_I*2*M_PI*randf()); // mix signal nco_crcf_mix_block_up(nco, buf_0, buf_1, buf_len); // compare result to expected float phi = phase; for (i=0; i<buf_len; i++) { float complex v = buf_0[i] * cexpf(_Complex_I*phi); CONTEND_DELTA( crealf(buf_1[i]), crealf(v), tol); CONTEND_DELTA( cimagf(buf_1[i]), cimagf(v), tol); phi += freq; } // destroy object nco_crcf_destroy(nco); }
// // test floating point precision nco // void autotest_nco_basic() { nco_crcf p = nco_crcf_create(LIQUID_NCO); unsigned int i; // loop index float s, c; // sine/cosine result float tol=1e-4f; // error tolerance float f=0.0f; // frequency to test nco_crcf_set_phase( p, 0.0f); CONTEND_DELTA( nco_crcf_cos(p), 1.0f, tol ); CONTEND_DELTA( nco_crcf_sin(p), 0.0f, tol ); nco_crcf_sincos(p, &s, &c); CONTEND_DELTA( s, 0.0f, tol ); CONTEND_DELTA( c, 1.0f, tol ); nco_crcf_set_phase(p, M_PI/2); CONTEND_DELTA( nco_crcf_cos(p), 0.0f, tol ); CONTEND_DELTA( nco_crcf_sin(p), 1.0f, tol ); nco_crcf_sincos(p, &s, &c); CONTEND_DELTA( s, 1.0f, tol ); CONTEND_DELTA( c, 0.0f, tol ); // cycle through one full period in 64 steps nco_crcf_set_phase(p, 0.0f); f = 2.0f * M_PI / 64.0f; nco_crcf_set_frequency(p, f); for (i=0; i<128; i++) { nco_crcf_sincos(p, &s, &c); CONTEND_DELTA( s, sinf(i*f), tol ); CONTEND_DELTA( c, cosf(i*f), tol ); nco_crcf_step(p); } // double frequency: cycle through one full period in 32 steps nco_crcf_set_phase(p, 0.0f); f = 2.0f * M_PI / 32.0f; nco_crcf_set_frequency(p, f); for (i=0; i<128; i++) { nco_crcf_sincos(p, &s, &c); CONTEND_DELTA( s, sinf(i*f), tol ); CONTEND_DELTA( c, cosf(i*f), tol ); nco_crcf_step(p); } // destroy NCO object nco_crcf_destroy(p); }
quiet_beacon_encoder *quiet_beacon_encoder_create(float sample_rate, float target_freq, float gain) { quiet_beacon_encoder *e = calloc(1, sizeof(quiet_beacon_encoder)); float omega = (target_freq/sample_rate) * 2 * M_PI; e->nco = nco_crcf_create(LIQUID_NCO); nco_crcf_set_phase(e->nco, 0.0f); nco_crcf_set_frequency(e->nco, omega); e->gain = gain; return e; }
// // test nco block mixing // void autotest_nco_block_mixing() { // frequency, phase float f = 0.1f; float phi = M_PI; // error tolerance (high for NCO) float tol = 0.05f; unsigned int i; // number of samples unsigned int num_samples = 1024; // store samples float complex * x = (float complex*)malloc(num_samples*sizeof(float complex)); float complex * y = (float complex*)malloc(num_samples*sizeof(float complex)); // generate complex sin/cos for (i=0; i<num_samples; i++) x[i] = cexpf(_Complex_I*(f*i + phi)); // initialize nco object nco_crcf p = nco_crcf_create(LIQUID_NCO); nco_crcf_set_frequency(p, f); nco_crcf_set_phase(p, phi); // mix signal back to zero phase (in pieces) unsigned int num_remaining = num_samples; i = 0; while (num_remaining > 0) { unsigned int n = 7 < num_remaining ? 7 : num_remaining; nco_crcf_mix_block_down(p, &x[i], &y[i], n); i += n; num_remaining -= n; } // assert mixer output is correct for (i=0; i<num_samples; i++) { CONTEND_DELTA( crealf(y[i]), 1.0f, tol ); CONTEND_DELTA( cimagf(y[i]), 0.0f, tol ); } // free those buffers free(x); free(y); // destroy NCO object nco_crcf_destroy(p); }
// // test phase-locked loop // _type : NCO type (e.g. LIQUID_NCO) // _phase_offset : initial phase offset // _freq_offset : initial frequency offset // _pll_bandwidth : bandwidth of phase-locked loop // _num_iterations : number of iterations to run // _tol : error tolerance void nco_crcf_pll_test(int _type, float _phase_offset, float _freq_offset, float _pll_bandwidth, unsigned int _num_iterations, float _tol) { // objects nco_crcf nco_tx = nco_crcf_create(_type); nco_crcf nco_rx = nco_crcf_create(_type); // initialize objects nco_crcf_set_phase(nco_tx, _phase_offset); nco_crcf_set_frequency(nco_tx, _freq_offset); nco_crcf_pll_set_bandwidth(nco_rx, _pll_bandwidth); // run loop unsigned int i; float phase_error; float complex r, v; for (i=0; i<_num_iterations; i++) { // received complex signal nco_crcf_cexpf(nco_tx,&r); nco_crcf_cexpf(nco_rx,&v); // error estimation phase_error = cargf(r*conjf(v)); // update pll nco_crcf_pll_step(nco_rx, phase_error); // update nco objects nco_crcf_step(nco_tx); nco_crcf_step(nco_rx); } // ensure phase of oscillators is locked float nco_tx_phase = nco_crcf_get_phase(nco_tx); float nco_rx_phase = nco_crcf_get_phase(nco_rx); CONTEND_DELTA(nco_tx_phase, nco_rx_phase, _tol); // ensure frequency of oscillators is locked float nco_tx_freq = nco_crcf_get_frequency(nco_tx); float nco_rx_freq = nco_crcf_get_frequency(nco_rx); CONTEND_DELTA(nco_tx_freq, nco_rx_freq, _tol); // clean it up nco_crcf_destroy(nco_tx); nco_crcf_destroy(nco_rx); }
// execute synchronizer, seeking p/n sequence // _q : frame synchronizer object // _x : input sample // _sym : demodulated symbol void flexframesync_execute_seekpn(flexframesync _q, float complex _x) { // push through pre-demod synchronizer float complex * v = qdetector_cccf_execute(_q->detector, _x); // check if frame has been detected if (v != NULL) { // get estimates _q->tau_hat = qdetector_cccf_get_tau (_q->detector); _q->gamma_hat = qdetector_cccf_get_gamma(_q->detector); _q->dphi_hat = qdetector_cccf_get_dphi (_q->detector); _q->phi_hat = qdetector_cccf_get_phi (_q->detector); #if DEBUG_FLEXFRAMESYNC_PRINT printf("***** frame detected! tau-hat:%8.4f, dphi-hat:%8.4f, gamma:%8.2f dB\n", _q->tau_hat, _q->dphi_hat, 20*log10f(_q->gamma_hat)); #endif // set appropriate filterbank index if (_q->tau_hat > 0) { _q->pfb_index = (unsigned int)( _q->tau_hat * _q->npfb) % _q->npfb; _q->mf_counter = 0; } else { _q->pfb_index = (unsigned int)((1.0f+_q->tau_hat) * _q->npfb) % _q->npfb; _q->mf_counter = 1; } // output filter scale (gain estimate, scaled by 1/2 for k=2 samples/symbol) firpfb_crcf_set_scale(_q->mf, 0.5f / _q->gamma_hat); // set frequency/phase of mixer nco_crcf_set_frequency(_q->mixer, _q->dphi_hat); nco_crcf_set_phase (_q->mixer, _q->phi_hat ); // update state _q->state = FLEXFRAMESYNC_STATE_RXPREAMBLE; #if DEBUG_FLEXFRAMESYNC // the debug_qdetector_flush prevents samples from being written twice _q->debug_qdetector_flush = 1; #endif // run buffered samples through synchronizer unsigned int buf_len = qdetector_cccf_get_buf_len(_q->detector); flexframesync_execute(_q, v, buf_len); #if DEBUG_FLEXFRAMESYNC _q->debug_qdetector_flush = 0; #endif } }
// once p/n symbols are buffered, estimate residual carrier // frequency and phase offsets, push through fine-tuned NCO void flexframesync_syncpn(flexframesync _q) { unsigned int i; // estimate residual carrier frequency offset from p/n symbols float complex dphi_metric = 0.0f; float complex r0 = 0.0f; float complex r1 = 0.0f; for (i=0; i<64; i++) { r0 = r1; r1 = _q->preamble_rx[i]*_q->preamble_pn[i]; dphi_metric += r1 * conjf(r0); } float dphi_hat = cargf(dphi_metric); // estimate carrier phase offset from p/n symbols float complex theta_metric = 0.0f; for (i=0; i<64; i++) theta_metric += _q->preamble_rx[i]*liquid_cexpjf(-dphi_hat*i)*_q->preamble_pn[i]; float theta_hat = cargf(theta_metric); // TODO: compute gain correction factor // initialize fine-tuned nco nco_crcf_set_frequency(_q->nco_fine, dphi_hat); nco_crcf_set_phase( _q->nco_fine, theta_hat); // correct for carrier offset, pushing through phase-locked loop for (i=0; i<64; i++) { // mix signal down nco_crcf_mix_down(_q->nco_fine, _q->preamble_rx[i], &_q->preamble_rx[i]); // push through phase-locked loop float phase_error = cimagf(_q->preamble_rx[i]*_q->preamble_pn[i]); nco_crcf_pll_step(_q->nco_fine, phase_error); #if DEBUG_FLEXFRAMESYNC //_q->debug_nco_phase[i] = nco_crcf_get_phase(_q->nco_fine); #endif // update nco phase nco_crcf_step(_q->nco_fine); } }
int main() { // create the NCO object nco_crcf p = nco_crcf_create(LIQUID_NCO); nco_crcf_set_phase(p, 0.0f); nco_crcf_set_frequency(p, M_PI/10); unsigned int i; float s, c; for (i=0; i<11; i++) { nco_crcf_sincos(p, &s, &c); printf(" %3u : %8.5f + j %8.5f\n", i, c, s); nco_crcf_step(p); } // clean up allocated memory nco_crcf_destroy(p); printf("done.\n"); return 0; }
// autotest helper function // _theta : input phase // _cos : expected output: cos(_theta) // _sin : expected output: sin(_theta) // _type : NCO type (e.g. LIQUID_NCO) // _tol : error tolerance void nco_crcf_phase_test(float _theta, float _cos, float _sin, int _type, float _tol) { // create object nco_crcf nco = nco_crcf_create(_type); // set phase nco_crcf_set_phase(nco, _theta); // compute cosine and sine outputs float c = nco_crcf_cos(nco); float s = nco_crcf_sin(nco); // run tests CONTEND_DELTA( c, _cos, _tol ); CONTEND_DELTA( s, _sin, _tol ); // destroy object nco_crcf_destroy(nco); }
demodulator *demodulator_create(const demodulator_options *opt) { if (!opt) { return NULL; } demodulator *d = malloc(sizeof(demodulator)); d->opt = *opt; d->nco = nco_crcf_create(LIQUID_NCO); nco_crcf_set_phase(d->nco, 0.0f); nco_crcf_set_frequency(d->nco, opt->center_rads); if (opt->samples_per_symbol > 1) { d->decim = firdecim_crcf_create_prototype(opt->shape, opt->samples_per_symbol, opt->symbol_delay, opt->excess_bw, 0); } else { d->opt.samples_per_symbol = 1; d->opt.symbol_delay = 0; d->decim = NULL; } return d; }
// // test nco mixing // void autotest_nco_mixing() { // frequency, phase float f = 0.1f; float phi = M_PI; // error tolerance (high for NCO) float tol = 0.05f; // initialize nco object nco_crcf p = nco_crcf_create(LIQUID_NCO); nco_crcf_set_frequency(p, f); nco_crcf_set_phase(p, phi); unsigned int i; float nco_i, nco_q; for (i=0; i<64; i++) { // generate sin/cos nco_crcf_sincos(p, &nco_q, &nco_i); // mix back to zero phase complex float nco_cplx_in = nco_i + _Complex_I*nco_q; complex float nco_cplx_out; nco_crcf_mix_down(p, nco_cplx_in, &nco_cplx_out); // assert mixer output is correct CONTEND_DELTA(crealf(nco_cplx_out), 1.0f, tol); CONTEND_DELTA(cimagf(nco_cplx_out), 0.0f, tol); //printf("%3u : %12.8f + j*%12.8f\n", i, crealf(nco_cplx_out), cimagf(nco_cplx_out)); // step nco nco_crcf_step(p); } // destroy NCO object nco_crcf_destroy(p); }
int main(int argc, char*argv[]) { srand( time(NULL) ); // parameters float phase_offset = M_PI/10; float frequency_offset = 0.001f; float SNRdB = 30.0f; float pll_bandwidth = 0.02f; modulation_scheme ms = LIQUID_MODEM_QPSK; unsigned int n=256; // number of iterations int dopt; while ((dopt = getopt(argc,argv,"uhs:b:n:P:F:m:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 's': SNRdB = atof(optarg); break; 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; case 'm': ms = liquid_getopt_str2mod(optarg); if (ms == LIQUID_MODEM_UNKNOWN) { fprintf(stderr,"error: %s, unknown/unsupported modulation scheme \"%s\"\n", argv[0], optarg); return 1; } break; default: exit(1); } } unsigned int d=n/32; // print every "d" lines FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid, "%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid, "clear all;\n"); fprintf(fid, "phi=zeros(1,%u);\n",n); fprintf(fid, "r=zeros(1,%u);\n",n); // objects nco_crcf nco_tx = nco_crcf_create(LIQUID_VCO); nco_crcf nco_rx = nco_crcf_create(LIQUID_VCO); modem mod = modem_create(ms); modem demod = modem_create(ms); unsigned int bps = modem_get_bps(mod); // 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); float noise_power = powf(10.0f, -SNRdB/20.0f); // print parameters printf("PLL example :\n"); printf("modem : %u-%s\n", 1<<bps, modulation_types[ms].name); printf("frequency offset: %6.3f, phase offset: %6.3f, SNR: %6.2fdB, pll b/w: %6.3f\n", frequency_offset, phase_offset, SNRdB, pll_bandwidth); // run loop unsigned int i, M=1<<bps, sym_in, sym_out, num_errors=0; float phase_error; float complex x, r, v, noise; for (i=0; i<n; i++) { // generate random symbol sym_in = rand() % M; // modulate modem_modulate(mod, sym_in, &x); // channel //r = nco_crcf_cexpf(nco_tx); nco_crcf_mix_up(nco_tx, x, &r); // add complex white noise crandnf(&noise); r += noise * noise_power; // //v = nco_crcf_cexpf(nco_rx); nco_crcf_mix_down(nco_rx, r, &v); // demodulate modem_demodulate(demod, v, &sym_out); num_errors += count_bit_errors(sym_in, sym_out); // error estimation //phase_error = cargf(r*conjf(v)); phase_error = modem_get_demodulator_phase_error(demod); // perfect error estimation //phase_error = nco_tx->theta - nco_rx->theta; // print every line in a format that octave can read fprintf(fid, "phi(%u) = %10.6E;\n", i+1, phase_error); fprintf(fid, "r(%u) = %10.6E + j*%10.6E;\n", i+1, crealf(v), cimagf(v)); if ((i+1)%d == 0 || i==n-1) { printf(" %4u: e_hat : %6.3f, phase error : %6.3f, freq error : %6.3f\n", i+1, // iteration phase_error, // estimated phase error nco_crcf_get_phase(nco_tx) - nco_crcf_get_phase(nco_rx),// true phase error nco_crcf_get_frequency(nco_tx) - nco_crcf_get_frequency(nco_rx)// true frequency error ); } // update tx nco object nco_crcf_step(nco_tx); // update pll nco_crcf_pll_step(nco_rx, phase_error); // update rx nco object nco_crcf_step(nco_rx); } fprintf(fid, "figure;\n"); fprintf(fid, "plot(1:length(phi),phi,'LineWidth',2,'Color',[0 0.25 0.5]);\n"); fprintf(fid, "xlabel('Symbol Index');\n"); fprintf(fid, "ylabel('Phase Error [radians]');\n"); fprintf(fid, "grid on;\n"); fprintf(fid, "t0 = round(0.25*length(r));\n"); fprintf(fid, "figure;\n"); fprintf(fid, "plot(r(1:t0),'x','Color',[0.6 0.6 0.6],r(t0:end),'x','Color',[0 0.25 0.5]);\n"); fprintf(fid, "grid on;\n"); fprintf(fid, "axis([-1.5 1.5 -1.5 1.5]);\n"); fprintf(fid, "axis('square');\n"); fprintf(fid, "xlabel('In-Phase');\n"); fprintf(fid, "ylabel('Quadrature');\n"); fprintf(fid, "legend(['first 25%%'],['last 75%%'],1);\n"); fclose(fid); printf("results written to %s.\n",OUTPUT_FILENAME); nco_crcf_destroy(nco_tx); nco_crcf_destroy(nco_rx); modem_destroy(mod); modem_destroy(demod); printf("bit errors: %u / %u\n", num_errors, bps*n); printf("done.\n"); return 0; }
int main(int argc, char*argv[]) { // options unsigned int sequence_len = 80; // number of sync symbols unsigned int k = 2; // samples/symbol unsigned int m = 7; // filter delay [symbols] float beta = 0.3f; // excess bandwidth factor int ftype = LIQUID_FIRFILT_ARKAISER; float gamma = 10.0f; // channel gain float tau = -0.3f; // fractional sample timing offset float dphi = -0.01f; // carrier frequency offset float phi = 0.5f; // carrier phase offset float SNRdB = 20.0f; // signal-to-noise ratio [dB] float threshold = 0.5f; // detection threshold int dopt; while ((dopt = getopt(argc,argv,"hn:k:m:b:F:T:S:t:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'n': sequence_len = atoi(optarg); break; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'b': beta = atof(optarg); break; case 'F': dphi = atof(optarg); break; case 'T': tau = atof(optarg); break; case 'S': SNRdB = atof(optarg); break; case 't': threshold = atof(optarg); break; default: exit(1); } } unsigned int i; // validate input if (tau < -0.5f || tau > 0.5f) { fprintf(stderr,"error: %s, fractional sample offset must be in [-0.5,0.5]\n", argv[0]); exit(1); } // generate synchronization sequence (QPSK symbols) float complex sequence[sequence_len]; for (i=0; i<sequence_len; i++) { sequence[i] = (rand() % 2 ? 1.0f : -1.0f) * M_SQRT1_2 + (rand() % 2 ? 1.0f : -1.0f) * M_SQRT1_2 * _Complex_I; } // float tau_hat = 0.0f; float gamma_hat = 0.0f; float dphi_hat = 0.0f; float phi_hat = 0.0f; int frame_detected = 0; // create detector qdetector_cccf q = qdetector_cccf_create_linear(sequence, sequence_len, ftype, k, m, beta); qdetector_cccf_set_threshold(q, threshold); qdetector_cccf_print(q); // unsigned int seq_len = qdetector_cccf_get_seq_len(q); unsigned int buf_len = qdetector_cccf_get_buf_len(q); unsigned int num_samples = 2*buf_len; // double buffer length to ensure detection unsigned int num_symbols = buf_len; // arrays float complex y[num_samples]; // received signal float complex syms_rx[num_symbols]; // recovered symbols // get pointer to sequence and generate full sequence float complex * v = (float complex*) qdetector_cccf_get_sequence(q); unsigned int filter_delay = 15; firfilt_crcf filter = firfilt_crcf_create_kaiser(2*filter_delay+1, 0.4f, 60.0f, -tau); float nstd = 0.1f; for (i=0; i<num_samples; i++) { // add delay firfilt_crcf_push(filter, i < seq_len ? v[i] : 0); firfilt_crcf_execute(filter, &y[i]); // channel gain y[i] *= gamma; // carrier offset y[i] *= cexpf(_Complex_I*(dphi*i + phi)); // noise y[i] += nstd*(randnf() + _Complex_I*randnf())*M_SQRT1_2; } firfilt_crcf_destroy(filter); // run detection on sequence for (i=0; i<num_samples; i++) { v = qdetector_cccf_execute(q,y[i]); if (v != NULL) { printf("\nframe detected!\n"); frame_detected = 1; // get statistics tau_hat = qdetector_cccf_get_tau(q); gamma_hat = qdetector_cccf_get_gamma(q); dphi_hat = qdetector_cccf_get_dphi(q); phi_hat = qdetector_cccf_get_phi(q); break; } } unsigned int num_syms_rx = 0; // output symbol counter unsigned int counter = 0; // decimation counter if (frame_detected) { // recover symbols firfilt_crcf mf = firfilt_crcf_create_rnyquist(ftype, k, m, beta, tau_hat); firfilt_crcf_set_scale(mf, 1.0f / (float)(k*gamma_hat)); nco_crcf nco = nco_crcf_create(LIQUID_VCO); nco_crcf_set_frequency(nco, dphi_hat); nco_crcf_set_phase (nco, phi_hat); for (i=0; i<buf_len; i++) { // float complex sample; nco_crcf_mix_down(nco, v[i], &sample); nco_crcf_step(nco); // apply decimator firfilt_crcf_push(mf, sample); counter++; if (counter == k-1) firfilt_crcf_execute(mf, &syms_rx[num_syms_rx++]); counter %= k; } nco_crcf_destroy(nco); firfilt_crcf_destroy(mf); } // destroy objects qdetector_cccf_destroy(q); // print results printf("\n"); printf("frame detected : %s\n", frame_detected ? "yes" : "no"); printf(" gamma hat : %8.3f, actual=%8.3f (error=%8.3f)\n", gamma_hat, gamma, gamma_hat - gamma); printf(" tau hat : %8.3f, actual=%8.3f (error=%8.3f) samples\n", tau_hat, tau, tau_hat - tau ); printf(" dphi hat : %8.5f, actual=%8.5f (error=%8.5f) rad/sample\n", dphi_hat, dphi, dphi_hat - dphi ); printf(" phi hat : %8.5f, actual=%8.5f (error=%8.5f) radians\n", phi_hat, phi, phi_hat - phi ); printf(" symbols rx : %u\n", num_syms_rx); printf("\n"); // // 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,"sequence_len= %u;\n", sequence_len); fprintf(fid,"num_samples = %u;\n", num_samples); fprintf(fid,"y = zeros(1,num_samples);\n"); for (i=0; i<num_samples; i++) fprintf(fid,"y(%4u) = %12.8f + j*%12.8f;\n", i+1, crealf(y[i]), cimagf(y[i])); fprintf(fid,"num_syms_rx = %u;\n", num_syms_rx); fprintf(fid,"syms_rx = zeros(1,num_syms_rx);\n"); for (i=0; i<num_syms_rx; i++) fprintf(fid,"syms_rx(%4u) = %12.8f + j*%12.8f;\n", i+1, crealf(syms_rx[i]), cimagf(syms_rx[i])); fprintf(fid,"t=[0:(num_samples-1)];\n"); fprintf(fid,"figure;\n"); fprintf(fid,"subplot(4,1,1);\n"); fprintf(fid," plot(t,real(y), t,imag(y));\n"); fprintf(fid," grid on;\n"); fprintf(fid," xlabel('time');\n"); fprintf(fid," ylabel('received signal');\n"); fprintf(fid,"subplot(4,1,2:4);\n"); fprintf(fid," plot(real(syms_rx), imag(syms_rx), 'x');\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"); fclose(fid); printf("results written to '%s'\n", OUTPUT_FILENAME); return 0; }
// decode header void flexframesync_decode_header(flexframesync _q) { // recover data symbols from pilots qpilotsync_execute(_q->header_pilotsync, _q->header_sym, _q->header_mod); // decode payload _q->header_valid = qpacketmodem_decode(_q->header_decoder, _q->header_mod, _q->header_dec); if (!_q->header_valid) return; // set fine carrier frequency and phase float dphi_hat = qpilotsync_get_dphi(_q->header_pilotsync); float phi_hat = qpilotsync_get_phi (_q->header_pilotsync); //printf("residual offset: dphi=%12.8f, phi=%12.8f\n", dphi_hat, phi_hat); nco_crcf_set_frequency(_q->pll, dphi_hat); nco_crcf_set_phase (_q->pll, phi_hat + dphi_hat * _q->header_sym_len); // first several bytes of header are user-defined unsigned int n = FLEXFRAME_H_USER; // first byte is for expansion/version validation unsigned int protocol = _q->header_dec[n+0]; if (protocol != FLEXFRAME_PROTOCOL) { fprintf(stderr,"warning: flexframesync_decode_header(), invalid framing protocol %u (expected %u)\n", protocol, FLEXFRAME_PROTOCOL); _q->header_valid = 0; return; } // strip off payload length unsigned int payload_dec_len = (_q->header_dec[n+1] << 8) | (_q->header_dec[n+2]); _q->payload_dec_len = payload_dec_len; // strip off modulation scheme/depth unsigned int mod_scheme = _q->header_dec[n+3]; // strip off CRC, forward error-correction schemes // CRC : most-significant 3 bits of [n+4] // fec0 : least-significant 5 bits of [n+4] // fec1 : least-significant 5 bits of [n+5] unsigned int check = (_q->header_dec[n+4] >> 5 ) & 0x07; unsigned int fec0 = (_q->header_dec[n+4] ) & 0x1f; unsigned int fec1 = (_q->header_dec[n+5] ) & 0x1f; // validate properties if (mod_scheme == 0 || mod_scheme >= LIQUID_MODEM_NUM_SCHEMES) { fprintf(stderr,"warning: flexframesync_decode_header(), invalid modulation scheme\n"); _q->header_valid = 0; return; } else if (check == LIQUID_CRC_UNKNOWN || check >= LIQUID_CRC_NUM_SCHEMES) { fprintf(stderr,"warning: flexframesync_decode_header(), decoded CRC exceeds available\n"); _q->header_valid = 0; return; } else if (fec0 == LIQUID_FEC_UNKNOWN || fec0 >= LIQUID_FEC_NUM_SCHEMES) { fprintf(stderr,"warning: flexframesync_decode_header(), decoded FEC (inner) exceeds available\n"); _q->header_valid = 0; return; } else if (fec1 == LIQUID_FEC_UNKNOWN || fec1 >= LIQUID_FEC_NUM_SCHEMES) { fprintf(stderr,"warning: flexframesync_decode_header(), decoded FEC (outer) exceeds available\n"); _q->header_valid = 0; return; } // re-create payload demodulator for phase-locked loop _q->payload_demod = modem_recreate(_q->payload_demod, mod_scheme); // reconfigure payload demodulator/decoder qpacketmodem_configure(_q->payload_decoder, payload_dec_len, check, fec0, fec1, mod_scheme); // set length appropriately _q->payload_sym_len = qpacketmodem_get_frame_len(_q->payload_decoder); // re-allocate buffers accordingly _q->payload_sym = (float complex*) realloc(_q->payload_sym, (_q->payload_sym_len)*sizeof(float complex)); _q->payload_dec = (unsigned char*) realloc(_q->payload_dec, (_q->payload_dec_len)*sizeof(unsigned char)); if (_q->payload_sym == NULL || _q->payload_dec == NULL) { fprintf(stderr,"error: flexframesync_decode_header(), could not re-allocate payload arrays\n"); _q->header_valid = 0; return; } #if DEBUG_FLEXFRAMESYNC_PRINT // print results printf("flexframesync_decode_header():\n"); printf(" header crc : %s\n", _q->header_valid ? "pass" : "FAIL"); printf(" check : %s\n", crc_scheme_str[check][1]); printf(" fec (inner) : %s\n", fec_scheme_str[fec0][1]); printf(" fec (outer) : %s\n", fec_scheme_str[fec1][1]); printf(" mod scheme : %s\n", modulation_types[mod_scheme].name); printf(" payload sym len : %u\n", _q->payload_sym_len); printf(" payload dec len : %u\n", _q->payload_dec_len); printf(" user data :"); unsigned int i; for (i=0; i<FLEXFRAME_H_USER; i++) printf(" %.2x", _q->header_dec[i]); printf("\n"); #endif }
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; }