// // autotest helper function // void validate_crc(crc_scheme _check, unsigned int _n) { unsigned int i; // generate pseudo-random data unsigned char data[_n]; msequence ms = msequence_create_default(9); for (i=0; i<_n; i++) data[i] = msequence_generate_symbol(ms,8); msequence_destroy(ms); // generate key unsigned int key = crc_generate_key(_check, data, _n); // contend data/key are valid CONTEND_EXPRESSION(crc_validate_message(_check, data, _n, key)); // unsigned char data_corrupt[_n]; unsigned int j; for (i=0; i<_n; i++) { for (j=0; j<8; j++) { // copy original data sequence memmove(data_corrupt, data, _n*sizeof(unsigned char)); // flip bit j at byte i data[i] ^= (1 << j); // contend data/key are invalid CONTEND_EXPRESSION(crc_validate_message(_check, data, _n, key)==0); } } }
// generate short sequence symbols // _p : subcarrier allocation array // _M : total number of subcarriers // _S0 : output symbol (freq) // _s0 : output symbol (time) // _M_S0 : total number of enabled subcarriers in S0 void ofdmframe_init_S0(unsigned char * _p, unsigned int _M, float complex * _S0, float complex * _s0, unsigned int * _M_S0) { unsigned int i; // compute m-sequence length unsigned int m = liquid_nextpow2(_M); if (m < 4) m = 4; else if (m > 8) m = 8; // generate m-sequence generator object msequence ms = msequence_create_default(m); unsigned int s; unsigned int M_S0 = 0; // short sequence for (i=0; i<_M; i++) { // generate symbol //s = msequence_generate_symbol(ms,1); s = msequence_generate_symbol(ms,3) & 0x01; if (_p[i] == OFDMFRAME_SCTYPE_NULL) { // NULL subcarrier _S0[i] = 0.0f; } else { if ( (i%2) == 0 ) { // even subcarrer _S0[i] = s ? 1.0f : -1.0f; M_S0++; } else { // odd subcarrer (ignore) _S0[i] = 0.0f; } } } // destroy objects msequence_destroy(ms); // ensure at least one subcarrier was enabled if (M_S0 == 0) { fprintf(stderr,"error: ofdmframe_init_S0(), no subcarriers enabled; check allocation\n"); exit(1); } // set return value(s) *_M_S0 = M_S0; // run inverse fft to get time-domain sequence fft_run(_M, _S0, _s0, FFT_REVERSE, 0); // normalize time-domain sequence level float g = 1.0f / sqrtf(M_S0); for (i=0; i<_M; i++) _s0[i] *= g; }
// generate long sequence symbols // _p : subcarrier allocation array // _M : total number of subcarriers // _S1 : output symbol (freq) // _s1 : output symbol (time) // _M_S1 : total number of enabled subcarriers in S1 void ofdmframe_init_S1(unsigned char * _p, unsigned int _M, float complex * _S1, float complex * _s1, unsigned int * _M_S1) { unsigned int i; // compute m-sequence length unsigned int m = liquid_nextpow2(_M); if (m < 4) m = 4; else if (m > 8) m = 8; // increase m such that the resulting S1 sequence will // differ significantly from S0 with the same subcarrier // allocation array m++; // generate m-sequence generator object msequence ms = msequence_create_default(m); unsigned int s; unsigned int M_S1 = 0; // long sequence for (i=0; i<_M; i++) { // generate symbol //s = msequence_generate_symbol(ms,1); s = msequence_generate_symbol(ms,3) & 0x01; if (_p[i] == OFDMFRAME_SCTYPE_NULL) { // NULL subcarrier _S1[i] = 0.0f; } else { _S1[i] = s ? 1.0f : -1.0f; M_S1++; } } // destroy objects msequence_destroy(ms); // ensure at least one subcarrier was enabled if (M_S1 == 0) { fprintf(stderr,"error: ofdmframe_init_S1(), no subcarriers enabled; check allocation\n"); exit(1); } // set return value(s) *_M_S1 = M_S1; // run inverse fft to get time-domain sequence fft_run(_M, _S1, _s1, FFT_REVERSE, 0); // normalize time-domain sequence level float g = 1.0f / sqrtf(M_S1); for (i=0; i<_M; i++) _s1[i] *= g; }
bpacketsync bpacketsync_create(unsigned int _m, bpacketsync_callback _callback, void * _userdata) { // create bpacketsync object bpacketsync q = (bpacketsync) malloc(sizeof(struct bpacketsync_s)); q->callback = _callback; q->userdata = _userdata; // default values q->dec_msg_len = 1; q->crc = LIQUID_CRC_NONE; q->fec0 = LIQUID_FEC_NONE; q->fec1 = LIQUID_FEC_NONE; // implied values q->g = 0; q->pnsequence_len = 8; // derived values q->enc_msg_len = packetizer_compute_enc_msg_len(q->dec_msg_len, q->crc, q->fec0, q->fec1); q->header_len = packetizer_compute_enc_msg_len(6, LIQUID_CRC_16, LIQUID_FEC_NONE, LIQUID_FEC_HAMMING128); // arrays q->pnsequence = (unsigned char*) malloc((q->pnsequence_len)*sizeof(unsigned char*)); q->payload_enc = (unsigned char*) malloc((q->enc_msg_len)*sizeof(unsigned char*)); q->payload_dec = (unsigned char*) malloc((q->dec_msg_len)*sizeof(unsigned char*)); // create m-sequence generator // TODO : configure sequence from generator polynomial q->ms = msequence_create_default(6); // create header packet encoder q->p_header = packetizer_create(6, LIQUID_CRC_16, LIQUID_FEC_NONE, LIQUID_FEC_HAMMING128); assert(q->header_len == packetizer_get_enc_msg_len(q->p_header)); // create payload packet encoder q->p_payload = packetizer_create(q->dec_msg_len, q->crc, q->fec0, q->fec1); // create binary sequence objects q->bpn = bsequence_create(q->pnsequence_len*8); q->brx = bsequence_create(q->pnsequence_len*8); // assemble semi-static framing structures bpacketsync_assemble_pnsequence(q); // reset synchronizer bpacketsync_reset(q); return q; }
// generate long sequence symbols // _p : subcarrier allocation array // _num_subcarriers : total number of subcarriers // _S1 : output symbol // _M_S1 : total number of enabled subcarriers in S1 void ofdmoqamframe_init_S1(unsigned char * _p, unsigned int _num_subcarriers, float complex * _S1, unsigned int * _M_S1) { unsigned int i; // compute m-sequence length unsigned int m = liquid_nextpow2(_num_subcarriers); if (m < 4) m = 4; else if (m > 8) m = 8; // increase m such that the resulting S1 sequence will // differ significantly from S0 with the same subcarrier // allocation array m++; // generate m-sequence generator object msequence ms = msequence_create_default(m); unsigned int s; unsigned int M_S1 = 0; // long sequence for (i=0; i<_num_subcarriers; i++) { // generate symbol //s = msequence_generate_symbol(ms,1); s = msequence_generate_symbol(ms,3) & 0x01; if (_p[i] == OFDMOQAMFRAME_SCTYPE_NULL) { // NULL subcarrier _S1[i] = 0.0f; } else { _S1[i] = s ? 1.0f : -1.0f; M_S1++; // rotate by pi/2 on odd subcarriers _S1[i] *= (i%2)==0 ? 1.0f : _Complex_I; } } // destroy objects msequence_destroy(ms); // ensure at least one subcarrier was enabled if (M_S1 == 0) { fprintf(stderr,"error: ofdmoqamframe_init_S1(), no subcarriers enabled; check allocation\n"); exit(1); } // set return value(s) *_M_S1 = M_S1; }
// generate short sequence symbols // _p : subcarrier allocation array // _num_subcarriers : total number of subcarriers // _S0 : output symbol // _M_S0 : total number of enabled subcarriers in S0 void ofdmoqamframe_init_S0(unsigned char * _p, unsigned int _num_subcarriers, float complex * _S0, unsigned int * _M_S0) { unsigned int i; // compute m-sequence length unsigned int m = liquid_nextpow2(_num_subcarriers); if (m < 4) m = 4; else if (m > 8) m = 8; // generate m-sequence generator object msequence ms = msequence_create_default(m); unsigned int s; unsigned int M_S0 = 0; // short sequence for (i=0; i<_num_subcarriers; i++) { // generate symbol //s = msequence_generate_symbol(ms,1); s = msequence_generate_symbol(ms,3) & 0x01; if (_p[i] == OFDMOQAMFRAME_SCTYPE_NULL) { // NULL subcarrier _S0[i] = 0.0f; } else { if ( (i%2) == 0 ) { // even subcarrer _S0[i] = s ? 1.0f : -1.0f; M_S0++; } else { // odd subcarrer (ignore) _S0[i] = 0.0f; } } } // destroy objects msequence_destroy(ms); // ensure at least one subcarrier was enabled if (M_S0 == 0) { fprintf(stderr,"error: ofdmoqamframe_init_S0(), no subcarriers enabled; check allocation\n"); exit(1); } // set return value(s) *_M_S0 = M_S0; }
// create bpacketgen object // _m : p/n sequence length (ignored) // _dec_msg_len : decoded message length (original uncoded data) // _crc : data validity check (e.g. cyclic redundancy check) // _fec0 : inner forward error-correction code scheme // _fec1 : outer forward error-correction code scheme bpacketgen bpacketgen_create(unsigned int _m, unsigned int _dec_msg_len, int _crc, int _fec0, int _fec1) { // validate input // create bpacketgen object bpacketgen q = (bpacketgen) malloc(sizeof(struct bpacketgen_s)); q->dec_msg_len = _dec_msg_len; q->crc = _crc; q->fec0 = _fec0; q->fec1 = _fec1; // implied values q->g = 0; q->pnsequence_len = 8; // derived values q->enc_msg_len = packetizer_compute_enc_msg_len(q->dec_msg_len, q->crc, q->fec0, q->fec1); q->header_len = packetizer_compute_enc_msg_len(6, LIQUID_CRC_16, LIQUID_FEC_NONE, LIQUID_FEC_HAMMING128); bpacketgen_compute_packet_len(q); // arrays q->pnsequence = (unsigned char*) malloc((q->pnsequence_len)*sizeof(unsigned char*)); // create m-sequence generator // TODO : configure sequence from generator polynomial q->ms = msequence_create_default(6); // create header packet encoder q->p_header = packetizer_create(6, LIQUID_CRC_16, LIQUID_FEC_NONE, LIQUID_FEC_HAMMING128); assert(q->header_len == packetizer_get_enc_msg_len(q->p_header)); // create payload packet encoder q->p_payload = packetizer_create(q->dec_msg_len, q->crc, q->fec0, q->fec1); // assemble semi-static framing structures bpacketgen_assemble_header(q); bpacketgen_assemble_pnsequence(q); return q; }
// re-create bpacketgen object from old object // _q : old bpacketgen object // _m : p/n sequence length (ignored) // _dec_msg_len : decoded message length (original uncoded data) // _crc : data validity check (e.g. cyclic redundancy check) // _fec0 : inner forward error-correction code scheme // _fec1 : outer forward error-correction code scheme bpacketgen bpacketgen_recreate(bpacketgen _q, unsigned int _m, unsigned int _dec_msg_len, int _crc, int _fec0, int _fec1) { // validate input // re-create internal packetizer object _q->dec_msg_len = _dec_msg_len; _q->crc = _crc; _q->fec0 = _fec0; _q->fec1 = _fec1; // derived values _q->enc_msg_len = packetizer_compute_enc_msg_len(_q->dec_msg_len, _q->crc, _q->fec0, _q->fec1); _q->header_len = packetizer_compute_enc_msg_len(6, LIQUID_CRC_16, LIQUID_FEC_NONE, LIQUID_FEC_HAMMING128); bpacketgen_compute_packet_len(_q); // arrays _q->g = 0; _q->pnsequence_len = 8; _q->pnsequence = (unsigned char*) realloc(_q->pnsequence, (_q->pnsequence_len)*sizeof(unsigned char*)); // re-create m-sequence generator // TODO : configure sequence from generator polynomial msequence_destroy(_q->ms); _q->ms = msequence_create_default(6); // re-create payload packet encoder _q->p_payload = packetizer_recreate(_q->p_payload, _q->dec_msg_len, _q->crc, _q->fec0, _q->fec1); // assemble semi-static framing structures bpacketgen_assemble_header(_q); bpacketgen_assemble_pnsequence(_q); return _q; }
// Helper function to keep code base small void symsync_crcf_bench(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations, unsigned int _k, unsigned int _m) { unsigned long int i; unsigned int npfb = 16; // number of filters in bank unsigned int k = _k; // samples/symbol unsigned int m = _m; // filter delay [symbols] float beta = 0.3f; // filter excess bandwidth factor // create symbol synchronizer symsync_crcf q = symsync_crcf_create_rnyquist(LIQUID_RNYQUIST_RRC, k, m, beta, npfb); // unsigned int num_samples = 64; *_num_iterations /= num_samples; unsigned int num_written; float complex x[num_samples]; float complex y[num_samples]; // generate pseudo-random data msequence ms = msequence_create_default(6); for (i=0; i<num_samples; i++) x[i] = ((float)msequence_generate_symbol(ms, 6) - 31.5) / 24.0f; msequence_destroy(ms); // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { symsync_crcf_execute(q, x, num_samples, y, &num_written); symsync_crcf_execute(q, x, num_samples, y, &num_written); symsync_crcf_execute(q, x, num_samples, y, &num_written); symsync_crcf_execute(q, x, num_samples, y, &num_written); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4 * num_samples; symsync_crcf_destroy(q); }
// create OFDM framing synchronizer object // _M : number of subcarriers, >10 typical // _cp_len : cyclic prefix length // _taper_len : taper length (OFDM symbol overlap) // _p : subcarrier allocation (null, pilot, data), [size: _M x 1] // _callback : user-defined callback function // _userdata : user-defined data pointer ofdmframesync ofdmframesync_create(unsigned int _M, unsigned int _cp_len, unsigned int _taper_len, unsigned char * _p, ofdmframesync_callback _callback, void * _userdata) { ofdmframesync q = (ofdmframesync) malloc(sizeof(struct ofdmframesync_s)); // validate input if (_M < 8) { fprintf(stderr,"warning: ofdmframesync_create(), less than 8 subcarriers\n"); } else if (_M % 2) { fprintf(stderr,"error: ofdmframesync_create(), number of subcarriers must be even\n"); exit(1); } else if (_cp_len > _M) { fprintf(stderr,"error: ofdmframesync_create(), cyclic prefix length cannot exceed number of subcarriers\n"); exit(1); } q->M = _M; q->cp_len = _cp_len; // derived values q->M2 = _M/2; // subcarrier allocation q->p = (unsigned char*) malloc((q->M)*sizeof(unsigned char)); if (_p == NULL) { ofdmframe_init_default_sctype(q->M, q->p); } else { memmove(q->p, _p, q->M*sizeof(unsigned char)); } // validate and count subcarrier allocation ofdmframe_validate_sctype(q->p, q->M, &q->M_null, &q->M_pilot, &q->M_data); if ( (q->M_pilot + q->M_data) == 0) { fprintf(stderr,"error: ofdmframesync_create(), must have at least one enabled subcarrier\n"); exit(1); } else if (q->M_data == 0) { fprintf(stderr,"error: ofdmframesync_create(), must have at least one data subcarriers\n"); exit(1); } else if (q->M_pilot < 2) { fprintf(stderr,"error: ofdmframesync_create(), must have at least two pilot subcarriers\n"); exit(1); } // create transform object q->X = (float complex*) malloc((q->M)*sizeof(float complex)); q->x = (float complex*) malloc((q->M)*sizeof(float complex)); q->fft = FFT_CREATE_PLAN(q->M, q->x, q->X, FFT_DIR_FORWARD, FFT_METHOD); // create input buffer the length of the transform q->input_buffer = windowcf_create(q->M + q->cp_len); // allocate memory for PLCP arrays q->S0 = (float complex*) malloc((q->M)*sizeof(float complex)); q->s0 = (float complex*) malloc((q->M)*sizeof(float complex)); q->S1 = (float complex*) malloc((q->M)*sizeof(float complex)); q->s1 = (float complex*) malloc((q->M)*sizeof(float complex)); ofdmframe_init_S0(q->p, q->M, q->S0, q->s0, &q->M_S0); ofdmframe_init_S1(q->p, q->M, q->S1, q->s1, &q->M_S1); // compute scaling factor q->g_data = sqrtf(q->M) / sqrtf(q->M_pilot + q->M_data); q->g_S0 = sqrtf(q->M) / sqrtf(q->M_S0); q->g_S1 = sqrtf(q->M) / sqrtf(q->M_S1); // gain q->g0 = 1.0f; q->G0 = (float complex*) malloc((q->M)*sizeof(float complex)); q->G1 = (float complex*) malloc((q->M)*sizeof(float complex)); q->G = (float complex*) malloc((q->M)*sizeof(float complex)); q->B = (float complex*) malloc((q->M)*sizeof(float complex)); q->R = (float complex*) malloc((q->M)*sizeof(float complex)); #if 1 memset(q->G0, 0x00, q->M*sizeof(float complex)); memset(q->G1, 0x00, q->M*sizeof(float complex)); memset(q->G , 0x00, q->M*sizeof(float complex)); memset(q->B, 0x00, q->M*sizeof(float complex)); #endif // timing backoff q->backoff = q->cp_len < 2 ? q->cp_len : 2; float phi = (float)(q->backoff)*2.0f*M_PI/(float)(q->M); unsigned int i; for (i=0; i<q->M; i++) q->B[i] = liquid_cexpjf(i*phi); // set callback data q->callback = _callback; q->userdata = _userdata; // // synchronizer objects // // numerically-controlled oscillator q->nco_rx = nco_crcf_create(LIQUID_NCO); // set pilot sequence q->ms_pilot = msequence_create_default(8); #if OFDMFRAMESYNC_ENABLE_SQUELCH // coarse detection q->squelch_threshold = -25.0f; q->squelch_enabled = 0; #endif // reset object ofdmframesync_reset(q); #if DEBUG_OFDMFRAMESYNC q->debug_enabled = 0; q->debug_objects_created = 0; q->debug_x = NULL; q->debug_rssi = NULL; q->debug_framesyms =NULL; q->G_hat = NULL; q->px = NULL; q->py = NULL; q->debug_pilot_0 = NULL; q->debug_pilot_1 = NULL; #endif // return object return q; }
// create OFDM framing generator object // _M : number of subcarriers, >10 typical // _cp_len : cyclic prefix length // _taper_len : taper length (OFDM symbol overlap) // _p : subcarrier allocation (null, pilot, data), [size: _M x 1] ofdmframegen ofdmframegen_create(unsigned int _M, unsigned int _cp_len, unsigned int _taper_len, unsigned char * _p) { // validate input if (_M < 2) { fprintf(stderr,"error: ofdmframegen_create(), number of subcarriers must be at least 2\n"); exit(1); } else if (_M % 2) { fprintf(stderr,"error: ofdmframegen_create(), number of subcarriers must be even\n"); exit(1); } else if (_cp_len > _M) { fprintf(stderr,"error: ofdmframegen_create(), cyclic prefix cannot exceed symbol length\n"); exit(1); } else if (_taper_len > _cp_len) { fprintf(stderr,"error: ofdmframegen_create(), taper length cannot exceed cyclic prefix\n"); exit(1); } ofdmframegen q = (ofdmframegen) malloc(sizeof(struct ofdmframegen_s)); q->M = _M; q->cp_len = _cp_len; q->taper_len = _taper_len; // allocate memory for subcarrier allocation IDs q->p = (unsigned char*) malloc((q->M)*sizeof(unsigned char)); if (_p == NULL) { // initialize default subcarrier allocation ofdmframe_init_default_sctype(q->M, q->p); } else { // copy user-defined subcarrier allocation memmove(q->p, _p, q->M*sizeof(unsigned char)); } // validate and count subcarrier allocation ofdmframe_validate_sctype(q->p, q->M, &q->M_null, &q->M_pilot, &q->M_data); if ( (q->M_pilot + q->M_data) == 0) { fprintf(stderr,"error: ofdmframegen_create(), must have at least one enabled subcarrier\n"); exit(1); } else if (q->M_data == 0) { fprintf(stderr,"error: ofdmframegen_create(), must have at least one data subcarriers\n"); exit(1); } else if (q->M_pilot < 2) { fprintf(stderr,"error: ofdmframegen_create(), must have at least two pilot subcarriers\n"); exit(1); } unsigned int i; // allocate memory for transform objects q->X = (float complex*) malloc((q->M)*sizeof(float complex)); q->x = (float complex*) malloc((q->M)*sizeof(float complex)); q->ifft = FFT_CREATE_PLAN(q->M, q->X, q->x, FFT_DIR_BACKWARD, FFT_METHOD); // allocate memory for PLCP arrays q->S0 = (float complex*) malloc((q->M)*sizeof(float complex)); q->s0 = (float complex*) malloc((q->M)*sizeof(float complex)); q->S1 = (float complex*) malloc((q->M)*sizeof(float complex)); q->s1 = (float complex*) malloc((q->M)*sizeof(float complex)); ofdmframe_init_S0(q->p, q->M, q->S0, q->s0, &q->M_S0); ofdmframe_init_S1(q->p, q->M, q->S1, q->s1, &q->M_S1); // create tapering window and transition buffer q->taper = (float*) malloc(q->taper_len * sizeof(float)); q->postfix = (float complex*) malloc(q->taper_len * sizeof(float complex)); for (i=0; i<q->taper_len; i++) { float t = ((float)i + 0.5f) / (float)(q->taper_len); float g = sinf(M_PI_2*t); q->taper[i] = g*g; } #if 0 // validate window symmetry for (i=0; i<q->taper_len; i++) { printf(" taper[%2u] = %12.8f (%12.8f)\n", i, q->taper[i], q->taper[i] + q->taper[q->taper_len - i - 1]); } #endif // compute scaling factor q->g_data = 1.0f / sqrtf(q->M_pilot + q->M_data); // set pilot sequence q->ms_pilot = msequence_create_default(8); return q; }
// // AUTOTEST: static channel filter, blind equalization on QPSK symbols // void autotest_eqlms_cccf_blind() { // parameters float tol = 2e-2f; // error tolerance unsigned int k = 2; // samples/symbol unsigned int m = 7; // filter delay float beta = 0.3f; // excess bandwidth factor unsigned int p = 7; // equalizer order float mu = 0.7f; // equalizer bandwidth unsigned int num_symbols = 400; // number of symbols to observe // create sequence generator for repeatability msequence ms = msequence_create_default(12); // create interpolating filter firinterp_crcf interp = firinterp_crcf_create_prototype(LIQUID_FIRFILT_ARKAISER,k,m,beta,0); // create equalizer eqlms_cccf eq = eqlms_cccf_create_rnyquist(LIQUID_FIRFILT_ARKAISER,k,p,beta,0); eqlms_cccf_set_bw(eq, mu); // create channel filter float complex h[5] = { { 1.00f, 0.00f}, { 0.00f, -0.01f}, {-0.11f, 0.02f}, { 0.02f, 0.01f}, {-0.09f, -0.04f} }; firfilt_cccf fchannel = firfilt_cccf_create(h,5); // arrays float complex buf[k]; // filter buffer float complex sym_in [num_symbols]; // input symbols float complex sym_out[num_symbols]; // equalized symbols // run equalization unsigned int i; unsigned int j; for (i=0; i<num_symbols; i++) { // generate input symbol sym_in[i] = ( msequence_advance(ms) ? M_SQRT1_2 : -M_SQRT1_2 ) + ( msequence_advance(ms) ? M_SQRT1_2 : -M_SQRT1_2 ) * _Complex_I; // interpolate firinterp_crcf_execute(interp, sym_in[i], buf); // apply channel filter (in place) firfilt_cccf_execute_block(fchannel, buf, k, buf); // apply equalizer as filter for (j=0; j<k; j++) { eqlms_cccf_push(eq, buf[j]); // decimate by k if ( (j%k) != 0 ) continue; eqlms_cccf_execute(eq, &sym_out[i]); // update equalization (blind operation) if (i > m + p) eqlms_cccf_step(eq, sym_out[i]/cabsf(sym_out[i]), sym_out[i]); } } // compare input, output unsigned int settling_delay = 285; for (i=m+p; i<num_symbols; i++) { // compensate for delay j = i-m-p; // absolute error float error = cabsf(sym_in[j]-sym_out[i]); if (liquid_autotest_verbose) { printf("x[%3u] = {%12.8f,%12.8f}, y[%3u] = {%12.8f,%12.8f}, error=%12.8f %s\n", j, crealf(sym_in [j]), cimagf(sym_in [j]), i, crealf(sym_out[i]), cimagf(sym_out[i]), error, error > tol ? "*" : ""); if (i == settling_delay + m + p) printf("--- start of test ---\n"); } // check error if (i > settling_delay + m + p) CONTEND_DELTA(error, 0.0f, tol); } // clean up objects firfilt_cccf_destroy(fchannel); eqlms_cccf_destroy(eq); msequence_destroy(ms); }
int main(int argc, char*argv[]) { // options unsigned int m=5; // shift register length, n=2^m - 1 // create and initialize m-sequence msequence ms = msequence_create_default(m); msequence_print(ms); unsigned int n = msequence_get_length(ms); signed int rxx[n]; // auto-correlation // create and initialize first binary sequence on m-sequence bsequence bs1 = bsequence_create(n); bsequence_init_msequence(bs1, ms); // create and initialize second binary sequence on same m-sequence bsequence bs2 = bsequence_create(n); bsequence_init_msequence(bs2, ms); // when sequences are aligned, autocorrelation is equal to length rxx[0] = 2*bsequence_correlate(bs1, bs2) - n; // when sequences are misaligned, autocorrelation is equal to -1 unsigned int i; for (i=0; i<n; i++) { // compute auto-correlation rxx[i] = 2*bsequence_correlate(bs1, bs2)-n; // circular shift the second sequence bsequence_circshift(bs2); } // p/n sequence signed int x[n]; for (i=0; i<n; i++) x[i] = bsequence_index(bs1, i); // clean up memory bsequence_destroy(bs1); bsequence_destroy(bs2); msequence_destroy(ms); // print results for (i=0; i<n; i++) printf("rxx[%3u] = %3d\n", i, rxx[i]); // // export results // FILE * fid = fopen(OUTPUT_FILENAME,"w"); if (!fid) { fprintf(stderr,"error: %s, cannot open output file '%s' for writing\n", argv[0], OUTPUT_FILENAME); exit(1); } fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n\n"); fprintf(fid,"n = %u;\n", n); fprintf(fid,"p = zeros(1,n);\n"); for (i=0; i<n; i++) { fprintf(fid,"x(%6u) = %3d;\n", i+1, x[i]); fprintf(fid,"rxx(%6u) = %12.8f;\n", i+1, rxx[i] / (float)n); } // plot results fprintf(fid,"figure;\n"); fprintf(fid,"t = 0:(n-1);\n"); fprintf(fid,"subplot(2,1,1);\n"); fprintf(fid," stairs(t,x);\n"); fprintf(fid," axis([-1 n -0.2 1.2]);\n"); fprintf(fid," ylabel('x');\n"); fprintf(fid,"subplot(2,1,2);\n"); fprintf(fid," plot(t,rxx,t,rxx);\n"); fprintf(fid," axis([-1 n -0.5 1.2]);\n"); fprintf(fid," xlabel('delay (samples)');\n"); fprintf(fid," ylabel('auto-correlation');\n"); fclose(fid); printf("results written to %s.\n", OUTPUT_FILENAME); return 0; }
int main(int argc, char*argv[]) { // options unsigned int m=5; // shift register length, n=2^m - 1 char filename[64] = ""; // output filename int dopt; while ((dopt = getopt(argc,argv,"uhm:f:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 'm': m = atoi(optarg); break; case 'f': // copy output filename string strncpy(filename,optarg,64); filename[63] = '\0'; break; default: exit(1); } } // ensure output filename is set if (strcmp(filename,"")==0) { fprintf(stderr,"error: %s, filename not set\n", argv[0]); exit(1); } // validate m if (m < 2) { fprintf(stderr,"error: %s, m is out of range\n", argv[0]); exit(1); } // create and initialize m-sequence msequence ms = msequence_create_default(m); msequence_print(ms); unsigned int n = msequence_get_length(ms); unsigned int sequence[n]; // sequence signed int rxx[n]; // auto-correlation // initialize sequence unsigned int i; for (i=0; i<n; i++) sequence[i] = msequence_advance(ms); // reset sequence msequence_reset(ms); // create and initialize first binary sequence on m-sequence bsequence bs1 = bsequence_create(n); bsequence_init_msequence(bs1, ms); // create and initialize second binary sequence on same m-sequence bsequence bs2 = bsequence_create(n); bsequence_init_msequence(bs2, ms); // when sequences are aligned, autocorrelation is equal to length unsigned int k=0; rxx[k++] = 2*bsequence_correlate(bs1, bs2) - n; // when sequences are misaligned, autocorrelation is equal to -1 for (i=0; i<n-1; i++) { bsequence_push(bs2, msequence_advance(ms)); rxx[k++] = 2*bsequence_correlate(bs1, bs2)-n; } // clean up memory bsequence_destroy(bs1); bsequence_destroy(bs2); msequence_destroy(ms); // // generate auto-correlation plot // // open output file FILE * fid = fopen(filename,"w"); if (fid == NULL) { fprintf(stderr,"error: %s, could not open file \"%s\" for writing.\n", argv[0], filename); exit(1); } // print header fprintf(fid,"# %s : auto-generated file (do not edit)\n", filename); fprintf(fid,"# invoked as :"); for (i=0; i<argc; i++) fprintf(fid," %s",argv[i]); fprintf(fid,"reset\n"); fprintf(fid,"set terminal postscript eps enhanced color solid rounded\n"); fprintf(fid,"set xrange [-1:%u];\n", n+1); fprintf(fid,"set size ratio 0.3\n"); fprintf(fid,"set xlabel 'delay (number of samples)'\n"); fprintf(fid,"set nokey # disable legned\n"); //fprintf(fid,"set grid xtics ytics\n"); //fprintf(fid,"set grid linetype 1 linecolor rgb '%s' lw 1\n", LIQUID_DOC_COLOR_GRID); fprintf(fid,"set multiplot layout 2,1 scale 1.0,1.0\n"); fprintf(fid,"# sequence\n"); fprintf(fid,"set ylabel 'sequence'\n"); fprintf(fid,"set yrange [-0.1:1.1]\n"); fprintf(fid,"plot '-' using 1:2 with steps linetype 1 linewidth 4 linecolor rgb '%s'\n",LIQUID_DOC_COLOR_BLUE); for (i=0; i<n; i++) { fprintf(fid," %6u %6u\n", i, sequence[i]); } fprintf(fid,"e\n"); fprintf(fid,"# auto-correlation\n"); fprintf(fid,"set ylabel 'auto-correlation'\n"); fprintf(fid,"set yrange [%f:1.1]\n", -5.0f / (float)n); fprintf(fid,"plot '-' using 1:2 with lines linetype 1 linewidth 4 linecolor rgb '%s'\n",LIQUID_DOC_COLOR_GREEN); for (i=0; i<n; i++) { fprintf(fid," %6u %12.4e\n", i, (float)rxx[i] / (float)n); } fprintf(fid,"e\n"); fprintf(fid,"unset multiplot\n"); // close output file fclose(fid); printf("results written to %s.\n", filename); return 0; }
ofdmoqamframe64sync ofdmoqamframe64sync_create(unsigned int _m, float _beta, ofdmoqamframe64sync_callback _callback, void * _userdata) { ofdmoqamframe64sync q = (ofdmoqamframe64sync) malloc(sizeof(struct ofdmoqamframe64sync_s)); q->num_subcarriers = 64; // validate input if (_m < 1) { fprintf(stderr,"error: ofdmoqamframe64sync_create(), filter delay must be > 0\n"); exit(1); } else if (_beta < 0.0f) { fprintf(stderr,"error: ofdmoqamframe64sync_create(), filter excess bandwidth must be > 0\n"); exit(1); } q->m = _m; q->beta = _beta; // synchronizer parameters q->rxx_thresh = 0.60f; // auto-correlation threshold q->rxy_thresh = 0.60f; // cross-correlation threshold q->zeta = 64.0f/sqrtf(52.0f); // scaling factor // create analysis filter banks q->ca0 = firpfbch_create(q->num_subcarriers, q->m, q->beta, 0.0f /*dt*/,FIRPFBCH_ROOTNYQUIST,0/*gradient*/); q->ca1 = firpfbch_create(q->num_subcarriers, q->m, q->beta, 0.0f /*dt*/,FIRPFBCH_ROOTNYQUIST,0/*gradient*/); q->X0 = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex)); q->X1 = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex)); q->Y0 = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex)); q->Y1 = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex)); // allocate memory for PLCP arrays q->S0 = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex)); q->S1 = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex)); q->S2 = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex)); ofdmoqamframe64_init_S0(q->S0); ofdmoqamframe64_init_S1(q->S1); ofdmoqamframe64_init_S2(q->S2); unsigned int i; for (i=0; i<q->num_subcarriers; i++) { q->S0[i] *= q->zeta; q->S1[i] *= q->zeta; q->S2[i] *= q->zeta; } q->S1a = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex)); q->S1b = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex)); // set pilot sequence q->ms_pilot = msequence_create_default(8); q->x_phase[0] = -21.0f; q->x_phase[1] = -7.0f; q->x_phase[2] = 7.0f; q->x_phase[3] = 21.0f; // create NCO for pilots q->nco_pilot = nco_crcf_create(LIQUID_VCO); q->pll_pilot = pll_create(); pll_set_bandwidth(q->pll_pilot,0.01f); pll_set_damping_factor(q->pll_pilot,4.0f); // create agc | signal detection object q->sigdet = agc_crcf_create(); agc_crcf_set_bandwidth(q->sigdet,0.1f); // create NCO for CFO compensation q->nco_rx = nco_crcf_create(LIQUID_VCO); // create auto-correlator objects q->autocorr_length = OFDMOQAMFRAME64SYNC_AUTOCORR_LEN; q->autocorr_delay = q->num_subcarriers / 4; q->autocorr = autocorr_cccf_create(q->autocorr_length, q->autocorr_delay); // create cross-correlator object q->hxy = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex)); ofdmoqam cs = ofdmoqam_create(q->num_subcarriers,q->m,q->beta, 0.0f, // dt OFDMOQAM_SYNTHESIZER, 0); // gradient for (i=0; i<2*(q->m); i++) ofdmoqam_execute(cs,q->S1,q->hxy); // time reverse, complex conjugate (same as fftshift for // this particular sequence) memmove(q->X0, q->hxy, 64*sizeof(float complex)); for (i=0; i<64; i++) q->hxy[i] = conjf(q->X0[64-i-1]); // fftshift //fft_shift(q->hxy,64); q->crosscorr = firfilt_cccf_create(q->hxy, q->num_subcarriers); ofdmoqam_destroy(cs); // input buffer q->input_buffer = windowcf_create((q->num_subcarriers)); // gain q->g = 1.0f; q->G0 = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex)); q->G1 = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex)); q->G = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex)); q->data = (float complex*) malloc((q->num_subcarriers)*sizeof(float complex)); // reset object ofdmoqamframe64sync_reset(q); #if DEBUG_OFDMOQAMFRAME64SYNC q->debug_x = windowcf_create(DEBUG_OFDMOQAMFRAME64SYNC_BUFFER_LEN); q->debug_rxx= windowcf_create(DEBUG_OFDMOQAMFRAME64SYNC_BUFFER_LEN); q->debug_rxy= windowcf_create(DEBUG_OFDMOQAMFRAME64SYNC_BUFFER_LEN); q->debug_framesyms= windowcf_create(DEBUG_OFDMOQAMFRAME64SYNC_BUFFER_LEN); q->debug_pilotphase= windowf_create(DEBUG_OFDMOQAMFRAME64SYNC_BUFFER_LEN); q->debug_pilotphase_hat= windowf_create(DEBUG_OFDMOQAMFRAME64SYNC_BUFFER_LEN); q->debug_rssi= windowf_create(DEBUG_OFDMOQAMFRAME64SYNC_BUFFER_LEN); #endif q->callback = _callback; q->userdata = _userdata; return q; }
// autotest helper function // _n : sequence length // _dt : fractional sample offset // _dphi : carrier frequency offset void detector_cccf_runtest(unsigned int _n, float _dt, float _dphi) { // TODO: validate input unsigned int i; // fixed values float noise_floor = -80.0f; // noise floor [dB] float SNRdB = 30.0f; // signal-to-noise ratio [dB] unsigned int m = 11; // resampling filter semi-length float threshold = 0.3f; // detection threshold // derived values unsigned int num_samples = _n + 2*m + 1; float nstd = powf(10.0f, noise_floor/20.0f); float gamma = powf(10.0f, (SNRdB + noise_floor)/20.0f); float delay = (float)(_n + m) + _dt; // expected delay // arrays float complex s[_n]; // synchronization pattern (samples) float complex x[num_samples]; // resampled signal with noise and offsets // generate synchronization pattern (two samples per symbol) unsigned int n2 = (_n - (_n%2)) / 2; // n2 = floor(n/2) unsigned int mm = liquid_nextpow2(n2); // mm = ceil( log2(n2) ) msequence ms = msequence_create_default(mm); float complex v = 0.0f; for (i=0; i<_n; i++) { if ( (i%2)==0 ) v = msequence_advance(ms) ? 1.0f : -1.0f; s[i] = v; } msequence_destroy(ms); // create fractional sample interpolator firfilt_crcf finterp = firfilt_crcf_create_kaiser(2*m+1, 0.45f, 40.0f, _dt); // generate sequence for (i=0; i<num_samples; i++) { // add fractional sample timing offset if (i < _n) firfilt_crcf_push(finterp, s[i]); else firfilt_crcf_push(finterp, 0.0f); // compute output firfilt_crcf_execute(finterp, &x[i]); // add channel gain x[i] *= gamma; // add carrier offset x[i] *= cexpf(_Complex_I*_dphi*i); // add noise x[i] += nstd * ( randnf() + _Complex_I*randnf() ) * M_SQRT1_2; } // destroy fractional sample interpolator firfilt_crcf_destroy(finterp); // create detector detector_cccf sync = detector_cccf_create(s, _n, threshold, 2*_dphi); // push signal through detector float tau_hat = 0.0f; // fractional sample offset estimate float dphi_hat = 0.0f; // carrier offset estimate float gamma_hat = 1.0f; // signal level estimate (linear) float delay_hat = 0.0f; // total delay offset estimate int signal_detected = 0; // signal detected flag for (i=0; i<num_samples; i++) { // correlate int detected = detector_cccf_correlate(sync, x[i], &tau_hat, &dphi_hat, &gamma_hat); if (detected) { signal_detected = 1; delay_hat = (float)i + (float)tau_hat; if (liquid_autotest_verbose) { printf("****** preamble found, tau_hat=%8.6f, dphi_hat=%8.6f, gamma_hat=%8.6f\n", tau_hat, dphi_hat, gamma_hat); } } } // destroy objects detector_cccf_destroy(sync); // // run tests // // convert to dB gamma = 20*log10f(gamma); gamma_hat = 20*log10f(gamma_hat); if (liquid_autotest_verbose) { printf("detector autotest [%3u]: signal detected? %s\n", _n, signal_detected ? "yes" : "no"); printf(" dphi : estimate = %12.6f (expected %12.6f)\n", dphi_hat, _dphi); printf(" delay : estimate = %12.6f (expected %12.6f)\n", delay_hat, delay); printf(" gamma : estimate = %12.6f (expected %12.6f)\n", gamma_hat, gamma); } // ensure signal was detected CONTEND_EXPRESSION( signal_detected ); // check carrier offset estimate CONTEND_DELTA( dphi_hat, _dphi, 0.01f ); // check delay estimate CONTEND_DELTA( delay_hat, delay, 0.2f ); // check signal level estimate CONTEND_DELTA( gamma_hat, gamma, 2.0f ); }