// destroy frame synchronizer object, freeing all internal memory void flexframesync_destroy(flexframesync _q) { #if DEBUG_FLEXFRAMESYNC // clean up debug objects (if created) if (_q->debug_objects_created) { windowcf_destroy(_q->debug_x); } #endif // destroy synchronization objects detector_cccf_destroy(_q->frame_detector); // frame detector windowcf_destroy(_q->buffer); // p/n sample buffer firpfb_crcf_destroy(_q->mf); // matched filter firpfb_crcf_destroy(_q->dmf); // derivative matched filter nco_crcf_destroy(_q->nco_coarse); // coarse NCO nco_crcf_destroy(_q->nco_fine); // fine-tuned NCO modem_destroy(_q->demod_header); // header demodulator packetizer_destroy(_q->p_header); // header packetizer modem_destroy(_q->demod_payload); // payload demodulator packetizer_destroy(_q->p_payload); // payload decoder // free buffers and arrays free(_q->payload_mod); // free(_q->payload_enc); // free(_q->payload_dec); // // free main object memory free(_q); }
// destroy WLAN framing synchronizer object void wlanframesync_destroy(wlanframesync _q) { #if DEBUG_WLANFRAMESYNC // free debugging objects if necessary if (_q->agc_rx != NULL) agc_crcf_destroy(_q->agc_rx); if (_q->debug_x != NULL) windowcf_destroy(_q->debug_x); if (_q->debug_rssi != NULL) windowf_destroy(_q->debug_rssi); if (_q->debug_framesyms != NULL) windowcf_destroy(_q->debug_framesyms); #endif // free transform object windowcf_destroy(_q->input_buffer); free(_q->X); free(_q->x); FFT_DESTROY_PLAN(_q->fft); // destroy synchronizer objects nco_crcf_destroy(_q->nco_rx); // numerically-controlled oscillator wlan_lfsr_destroy(_q->ms_pilot); // pilot sequence generator // free memory for encoded message free(_q->msg_enc); // free main object memory free(_q); }
// Helper function to keep code base small void window_push_bench(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations, unsigned int _n) { // normalize number of iterations *_num_iterations *= 8; if (*_num_iterations < 1) *_num_iterations = 1; // initialize port windowcf w = windowcf_create(_n); unsigned long int i; // start trials: // write to port, read from port getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { windowcf_push(w, 1.0f); windowcf_push(w, 1.0f); windowcf_push(w, 1.0f); windowcf_push(w, 1.0f); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; windowcf_destroy(w); }
// destroy frame synchronizer object, freeing all internal memory void flexframesync_destroy(flexframesync _q) { #if DEBUG_FLEXFRAMESYNC // clean up debug objects (if created) if (_q->debug_objects_created) windowcf_destroy(_q->debug_x); #endif // free allocated arrays free(_q->preamble_pn); free(_q->preamble_rx); free(_q->header_sym); free(_q->header_mod); free(_q->header_dec); free(_q->payload_sym); free(_q->payload_dec); // destroy synchronization objects qpilotsync_destroy (_q->header_pilotsync); // header demodulator/decoder qpacketmodem_destroy (_q->header_decoder); // header demodulator/decoder modem_destroy (_q->payload_demod); // payload demodulator (for PLL) qpacketmodem_destroy (_q->payload_decoder); // payload demodulator/decoder qdetector_cccf_destroy(_q->detector); // frame detector firpfb_crcf_destroy (_q->mf); // matched filter nco_crcf_destroy (_q->mixer); // oscillator (coarse) nco_crcf_destroy (_q->pll); // oscillator (fine) #if FLEXFRAMESYNC_ENABLE_EQ eqlms_cccf_destroy (_q->equalizer); // LMS equalizer #endif // free main object memory free(_q); }
void ofdmframesync_destroy(ofdmframesync _q) { #if DEBUG_OFDMFRAMESYNC // destroy debugging objects if (_q->debug_x != NULL) windowcf_destroy(_q->debug_x); if (_q->debug_rssi != NULL) windowf_destroy(_q->debug_rssi); if (_q->debug_framesyms != NULL) windowcf_destroy(_q->debug_framesyms); if (_q->G_hat != NULL) free(_q->G_hat); if (_q->px != NULL) free(_q->px); if (_q->py != NULL) free(_q->py); if (_q->debug_pilot_0 != NULL) windowf_destroy(_q->debug_pilot_0); if (_q->debug_pilot_1 != NULL) windowf_destroy(_q->debug_pilot_1); #endif // free subcarrier type array memory free(_q->p); // free transform object windowcf_destroy(_q->input_buffer); free(_q->X); free(_q->x); FFT_DESTROY_PLAN(_q->fft); // clean up PLCP arrays free(_q->S0); free(_q->s0); free(_q->S1); free(_q->s1); // free gain arrays free(_q->G0); free(_q->G1); free(_q->G); free(_q->B); free(_q->R); // destroy synchronizer objects nco_crcf_destroy(_q->nco_rx); // numerically-controlled oscillator msequence_destroy(_q->ms_pilot); // free main object memory free(_q); }
// destroy frame synchronizer object, freeing all internal memory void gmskframesync_destroy(gmskframesync _q) { #if DEBUG_GMSKFRAMESYNC // destroy debugging objects if (_q->debug_objects_created) { windowcf_destroy(_q->debug_x); windowf_destroy(_q->debug_fi); windowf_destroy(_q->debug_mf); windowf_destroy( _q->debug_framesyms); } #endif // destroy synchronizer objects #if GMSKFRAMESYNC_PREFILTER iirfilt_crcf_destroy(_q->prefilter);// pre-demodulator filter #endif firpfb_rrrf_destroy(_q->mf); // matched filter firpfb_rrrf_destroy(_q->dmf); // derivative matched filter nco_crcf_destroy(_q->nco_coarse); // coarse NCO // preamble detector_cccf_destroy(_q->frame_detector); windowcf_destroy(_q->buffer); free(_q->preamble_pn); free(_q->preamble_rx); // header packetizer_destroy(_q->p_header); free(_q->header_mod); free(_q->header_enc); free(_q->header_dec); // payload packetizer_destroy(_q->p_payload); free(_q->payload_enc); free(_q->payload_dec); // free main object memory free(_q); }
void ampmodem_destroy(ampmodem _q) { #if DEBUG_AMPMODEM // export output debugging file ampmodem_debug_print(_q, DEBUG_AMPMODEM_FILENAME); // destroy debugging objects windowcf_destroy(_q->debug_x); windowf_destroy(_q->debug_phase_error); windowf_destroy(_q->debug_freq_error); #endif // destroy nco object nco_crcf_destroy(_q->oscillator); // destroy hilbert transform firhilbf_destroy(_q->hilbert); // free main object memory free(_q); }
int main(int argc, char*argv[]) { // options int ftype = LIQUID_FIRFILT_ARKAISER; int ms = LIQUID_MODEM_QPSK; unsigned int k = 2; // samples per symbol unsigned int m = 7; // filter delay (symbols) float beta = 0.20f; // filter excess bandwidth factor unsigned int num_symbols = 4000; // number of data symbols unsigned int hc_len = 4; // channel filter length float noise_floor = -60.0f; // noise floor [dB] float SNRdB = 30.0f; // signal-to-noise ratio [dB] float bandwidth = 0.02f; // loop filter bandwidth float tau = -0.2f; // fractional symbol offset float rate = 1.001f; // sample rate offset float dphi = 0.01f; // carrier frequency offset [radians/sample] float phi = 2.1f; // carrier phase offset [radians] unsigned int nfft = 2400; // spectral periodogram FFT size unsigned int num_samples = 200000; // number of samples int dopt; while ((dopt = getopt(argc,argv,"hk:m:b:s:w:n:t:r:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'b': beta = atof(optarg); break; case 's': SNRdB = atof(optarg); break; case 'w': bandwidth = atof(optarg); break; case 'n': num_symbols = atoi(optarg); break; case 't': tau = atof(optarg); break; case 'r': rate = atof(optarg); break; default: exit(1); } } // validate input if (k < 2) { fprintf(stderr,"error: k (samples/symbol) must be greater than 1\n"); exit(1); } else if (m < 1) { fprintf(stderr,"error: m (filter delay) must be greater than 0\n"); exit(1); } else if (beta <= 0.0f || beta > 1.0f) { fprintf(stderr,"error: beta (excess bandwidth factor) must be in (0,1]\n"); exit(1); } else if (bandwidth <= 0.0f) { fprintf(stderr,"error: timing PLL bandwidth must be greater than 0\n"); exit(1); } else if (num_symbols == 0) { fprintf(stderr,"error: number of symbols must be greater than 0\n"); exit(1); } else if (tau < -1.0f || tau > 1.0f) { fprintf(stderr,"error: timing phase offset must be in [-1,1]\n"); exit(1); } else if (rate > 1.02f || rate < 0.98f) { fprintf(stderr,"error: timing rate offset must be in [1.02,0.98]\n"); exit(1); } unsigned int i; // buffers unsigned int buf_len = 400; // buffer size float complex x [buf_len]; // original signal float complex y [buf_len*2]; // channel output (larger to accommodate resampler) float complex syms[buf_len]; // recovered symbols // window for saving last few symbols windowcf sym_buf = windowcf_create(buf_len); // create stream generator symstreamcf gen = symstreamcf_create_linear(ftype,k,m,beta,ms); // create channel emulator and add impairments channel_cccf channel = channel_cccf_create(); channel_cccf_add_awgn (channel, noise_floor, SNRdB); channel_cccf_add_carrier_offset(channel, dphi, phi); channel_cccf_add_multipath (channel, NULL, hc_len); channel_cccf_add_resamp (channel, 0.0f, rate); // create symbol tracking synchronizer symtrack_cccf symtrack = symtrack_cccf_create(ftype,k,m,beta,ms); symtrack_cccf_set_bandwidth(symtrack,0.05f); // create spectral periodogram for estimating spectrum spgramcf periodogram = spgramcf_create_default(nfft); unsigned int total_samples = 0; unsigned int ny; unsigned int total_symbols = 0; while (total_samples < num_samples) { // write samples to buffer symstreamcf_write_samples(gen, x, buf_len); // apply channel channel_cccf_execute(channel, x, buf_len, y, &ny); // push resulting sample through periodogram spgramcf_write(periodogram, y, ny); // run resulting stream through synchronizer unsigned int num_symbols_sync; symtrack_cccf_execute_block(symtrack, y, ny, syms, &num_symbols_sync); total_symbols += num_symbols_sync; // write resulting symbols to window buffer for plotting windowcf_write(sym_buf, syms, num_symbols_sync); // accumulated samples total_samples += buf_len; } printf("total samples: %u\n", total_samples); printf("total symbols: %u\n", total_symbols); // write accumulated power spectral density estimate float psd[nfft]; spgramcf_get_psd(periodogram, psd); // // export output file // FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s, auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n"); // read buffer and write last symbols to file float complex * rc; windowcf_read(sym_buf, &rc); fprintf(fid,"syms = zeros(1,%u);\n", buf_len); for (i=0; i<buf_len; i++) fprintf(fid,"syms(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(rc[i]), cimagf(rc[i])); // power spectral density estimate fprintf(fid,"nfft = %u;\n", nfft); fprintf(fid,"f=[0:(nfft-1)]/nfft - 0.5;\n"); fprintf(fid,"psd = zeros(1,nfft);\n"); for (i=0; i<nfft; i++) fprintf(fid,"psd(%3u) = %12.8f;\n", i+1, psd[i]); fprintf(fid,"figure('Color','white','position',[500 500 1400 400]);\n"); fprintf(fid,"subplot(1,3,1);\n"); fprintf(fid,"plot(real(syms),imag(syms),'x','MarkerSize',4);\n"); fprintf(fid," axis square;\n"); fprintf(fid," grid on;\n"); fprintf(fid," axis([-1 1 -1 1]*1.6);\n"); fprintf(fid," xlabel('In-phase');\n"); fprintf(fid," ylabel('Quadrature');\n"); fprintf(fid," title('Last %u symbols');\n", buf_len); fprintf(fid,"subplot(1,3,2:3);\n"); fprintf(fid," plot(f, psd, 'LineWidth',1.5,'Color',[0 0.5 0.2]);\n"); fprintf(fid," grid on;\n"); fprintf(fid," pmin = 10*floor(0.1*min(psd - 5));\n"); fprintf(fid," pmax = 10*ceil (0.1*max(psd + 5));\n"); fprintf(fid," axis([-0.5 0.5 pmin pmax]);\n"); fprintf(fid," xlabel('Normalized Frequency [f/F_s]');\n"); fprintf(fid," ylabel('Power Spectral Density [dB]');\n"); fclose(fid); printf("results written to %s.\n", OUTPUT_FILENAME); // destroy objects symstreamcf_destroy (gen); spgramcf_destroy (periodogram); channel_cccf_destroy (channel); symtrack_cccf_destroy(symtrack); windowcf_destroy (sym_buf); // clean it up printf("done.\n"); return 0; }
int main() { // options unsigned int num_channels=64; // must be even number unsigned int num_symbols=16; // number of symbols unsigned int m=3; // filter delay (symbols) float beta = 0.9f; // filter excess bandwidth factor float phi = 0.0f; // carrier phase offset; float dphi = 0.04f; // carrier frequency offset // number of frames (compensate for filter delay) unsigned int num_frames = num_symbols + 2*m; unsigned int num_samples = num_channels * num_frames; unsigned int i; unsigned int j; // create filter prototype unsigned int h_len = 2*num_channels*m + 1; float h[h_len]; float complex hc[h_len]; float complex gc[h_len]; liquid_firdes_rkaiser(num_channels, m, beta, 0.0f, h); unsigned int g_len = 2*num_channels*m; for (i=0; i<g_len; i++) { hc[i] = h[i]; gc[i] = h[g_len-i-1] * cexpf(_Complex_I*dphi*i); } // data arrays float complex s[num_channels]; // input symbols float complex y[num_samples]; // time-domain samples float complex Y0[num_frames][num_channels]; // channelized output float complex Y1[num_frames][num_channels]; // channelized output // create ofdm/oqam generator object and generate data ofdmoqam qs = ofdmoqam_create(num_channels, m, beta, 0.0f, LIQUID_SYNTHESIZER, 0); for (i=0; i<num_frames; i++) { for (j=0; j<num_channels; j++) { if (i<num_symbols) { #if 0 // QPSK on all subcarriers s[j] = (rand() % 2 ? 1.0f : -1.0f) + (rand() % 2 ? 1.0f : -1.0f) * _Complex_I; s[j] *= 1.0f / sqrtf(2.0f); #else // BPSK on even subcarriers s[j] = rand() % 2 ? 1.0f : -1.0f; s[j] *= (j%2)==0 ? 1.0f : 0.0f; #endif } else { s[j] = 0.0f; } } // run synthesizer ofdmoqam_execute(qs, s, &y[i*num_channels]); } ofdmoqam_destroy(qs); // channel for (i=0; i<num_samples; i++) y[i] *= cexpf(_Complex_I*(phi + dphi*i)); // // analysis filterbank (receiver) // // create filterbank manually dotprod_cccf dp[num_channels]; // vector dot products windowcf w[num_channels]; // window buffers #if DEBUG // print coefficients printf("h_prototype:\n"); for (i=0; i<h_len; i++) printf(" h[%3u] = %12.8f\n", i, h[i]); #endif // create objects unsigned int gc_sub_len = 2*m; float complex gc_sub[gc_sub_len]; for (i=0; i<num_channels; i++) { // sub-sample prototype filter, loading coefficients in // reverse order #if 0 for (j=0; j<gc_sub_len; j++) gc_sub[j] = h[j*num_channels+i]; #else for (j=0; j<gc_sub_len; j++) gc_sub[gc_sub_len-j-1] = gc[j*num_channels+i]; #endif // create window buffer and dotprod objects dp[i] = dotprod_cccf_create(gc_sub, gc_sub_len); w[i] = windowcf_create(gc_sub_len); #if DEBUG printf("gc_sub[%u] : \n", i); for (j=0; j<gc_sub_len; j++) printf(" g[%3u] = %12.8f + %12.8f\n", j, crealf(gc_sub[j]), cimagf(gc_sub[j])); #endif } // generate DFT object float complex x[num_channels]; // time-domain buffer float complex X[num_channels]; // freq-domain buffer #if 0 fftplan fft = fft_create_plan(num_channels, X, x, FFT_REVERSE, 0); #else fftplan fft = fft_create_plan(num_channels, X, x, FFT_FORWARD, 0); #endif // // run analysis filter bank // #if 0 unsigned int filter_index = 0; #else unsigned int filter_index = num_channels-1; #endif float complex y_hat; // input sample float complex * r; // read pointer for (i=0; i<num_frames; i++) { // load buffers for (j=0; j<num_channels; j++) { // grab sample y_hat = y[i*num_channels + j]; // push sample into buffer at filter index windowcf_push(w[filter_index], y_hat); // decrement filter index filter_index = (filter_index + num_channels - 1) % num_channels; //filter_index = (filter_index + 1) % num_channels; } // execute filter outputs, reversing order of output (not // sure why this is necessary) for (j=0; j<num_channels; j++) { windowcf_read(w[j], &r); dotprod_cccf_execute(dp[j], r, &X[num_channels-j-1]); } #if 1 // compensate for carrier frequency offset (before transform) for (j=0; j<num_channels; j++) { X[j] *= cexpf(-_Complex_I*(dphi*i*num_channels)); } #endif // execute DFT, store result in buffer 'x' fft_execute(fft); #if 0 // compensate for carrier frequency offset (after transform) for (j=0; j<num_channels; j++) { x[j] *= cexpf(-_Complex_I*(dphi*i*num_channels)); } #endif // move to output array for (j=0; j<num_channels; j++) Y0[i][j] = x[j]; } // destroy objects for (i=0; i<num_channels; i++) { dotprod_cccf_destroy(dp[i]); windowcf_destroy(w[i]); } fft_destroy_plan(fft); #if 0 // print filterbank channelizer printf("\n"); printf("filterbank channelizer:\n"); for (i=0; i<num_symbols; i++) { printf("%3u: ", i); for (j=0; j<num_channels; j++) { printf(" %8.5f+j%8.5f, ", crealf(Y0[i][j]), cimagf(Y0[i][j])); } printf("\n"); } #endif // // export data // FILE*fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s: auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\nclose all;\n\n"); fprintf(fid,"num_channels=%u;\n", num_channels); fprintf(fid,"num_symbols=%u;\n", num_symbols); fprintf(fid,"num_frames = %u;\n", num_frames); fprintf(fid,"num_samples = num_frames*num_channels;\n"); fprintf(fid,"y = zeros(1,%u);\n", num_samples); fprintf(fid,"Y0 = zeros(%u,%u);\n", num_frames, num_channels); fprintf(fid,"Y1 = zeros(%u,%u);\n", num_frames, num_channels); for (i=0; i<num_frames; i++) { for (j=0; j<num_channels; j++) { fprintf(fid,"Y0(%4u,%4u) = %12.4e + j*%12.4e;\n", i+1, j+1, crealf(Y0[i][j]), cimagf(Y0[i][j])); fprintf(fid,"Y1(%4u,%4u) = %12.4e + j*%12.4e;\n", i+1, j+1, crealf(Y1[i][j]), cimagf(Y1[i][j])); } } // plot BPSK results fprintf(fid,"figure;\n"); fprintf(fid,"plot(Y0(:,1:2:end),'x');\n"); fprintf(fid,"axis([-1 1 -1 1]*1.2*sqrt(num_channels));\n"); fprintf(fid,"axis square;\n"); fprintf(fid,"grid on;\n"); fclose(fid); printf("results written to '%s'\n", OUTPUT_FILENAME); printf("done.\n"); return 0; }
int main() { // options unsigned int num_channels=4; // number of channels unsigned int m=5; // filter delay unsigned int num_symbols=12; // number of symbols // derived values unsigned int num_samples = num_channels * num_symbols; unsigned int i; unsigned int j; // generate filter // NOTE : these coefficients can be random; the purpose of this // exercise is to demonstrate mathematical equivalence unsigned int h_len = 2*m*num_channels; float h[h_len]; for (i=0; i<h_len; i++) h[i] = randnf(); //for (i=0; i<h_len; i++) h[i] = 0.1f*i; //for (i=0; i<h_len; i++) h[i] = (i<=m) ? 1.0f : 0.0f; //for (i=0; i<h_len; i++) h[i] = 1.0f; // create filterbank manually dotprod_crcf dp[num_channels]; // vector dot products windowcf w[num_channels]; // window buffers #if DEBUG // print coefficients printf("h_prototype:\n"); for (i=0; i<h_len; i++) printf(" h[%3u] = %12.8f\n", i, h[i]); #endif // create objects unsigned int h_sub_len = 2*m; float h_sub[h_sub_len]; for (i=0; i<num_channels; i++) { // sub-sample prototype filter, loading coefficients in // reverse order #if 0 for (j=0; j<h_sub_len; j++) h_sub[j] = h[j*num_channels+i]; #else for (j=0; j<h_sub_len; j++) h_sub[h_sub_len-j-1] = h[j*num_channels+i]; #endif // create window buffer and dotprod objects dp[i] = dotprod_crcf_create(h_sub, h_sub_len); w[i] = windowcf_create(h_sub_len); #if DEBUG printf("h_sub[%u] : \n", i); for (j=0; j<h_sub_len; j++) printf(" h[%3u] = %12.8f\n", j, h_sub[j]); #endif } // generate DFT object float complex x[num_channels]; // time-domain buffer float complex X[num_channels]; // freq-domain buffer #if 0 fftplan fft = fft_create_plan(num_channels, X, x, LIQUID_FFT_BACKWARD, 0); #else fftplan fft = fft_create_plan(num_channels, X, x, LIQUID_FFT_FORWARD, 0); #endif // generate filter object firfilt_crcf f = firfilt_crcf_create(h, h_len); float complex y[num_samples]; // time-domain input float complex Y0[num_symbols][num_channels]; // channelized output float complex Y1[num_symbols][num_channels]; // channelized output // generate input sequence (complex noise) for (i=0; i<num_samples; i++) y[i] = randnf() * cexpf(_Complex_I*randf()*2*M_PI); // // run analysis filter bank // #if 0 unsigned int filter_index = 0; #else unsigned int filter_index = num_channels-1; #endif float complex y_hat; // input sample float complex * r; // read pointer for (i=0; i<num_symbols; i++) { // load buffers for (j=0; j<num_channels; j++) { // grab sample y_hat = y[i*num_channels + j]; // push sample into buffer at filter index windowcf_push(w[filter_index], y_hat); // decrement filter index filter_index = (filter_index + num_channels - 1) % num_channels; //filter_index = (filter_index + 1) % num_channels; } // execute filter outputs, reversing order of output (not // sure why this is necessary) for (j=0; j<num_channels; j++) { windowcf_read(w[j], &r); dotprod_crcf_execute(dp[j], r, &X[num_channels-j-1]); } // execute DFT, store result in buffer 'x' fft_execute(fft); // move to output array for (j=0; j<num_channels; j++) Y0[i][j] = x[j]; } // // run traditional down-converter (inefficient) // float dphi; // carrier frequency unsigned int n=0; for (i=0; i<num_channels; i++) { // reset filter firfilt_crcf_reset(f); // set center frequency dphi = 2.0f * M_PI * (float)i / (float)num_channels; // reset symbol counter n=0; for (j=0; j<num_samples; j++) { // push down-converted sample into filter firfilt_crcf_push(f, y[j]*cexpf(-_Complex_I*j*dphi)); // compute output at the appropriate sample time assert(n<num_symbols); if ( ((j+1)%num_channels)==0 ) { firfilt_crcf_execute(f, &Y1[n][i]); n++; } } assert(n==num_symbols); } // destroy objects for (i=0; i<num_channels; i++) { dotprod_crcf_destroy(dp[i]); windowcf_destroy(w[i]); } fft_destroy_plan(fft); firfilt_crcf_destroy(f); // print filterbank channelizer printf("\n"); printf("filterbank channelizer:\n"); for (i=0; i<num_symbols; i++) { printf("%3u: ", i); for (j=0; j<num_channels; j++) { printf(" %8.5f+j%8.5f, ", crealf(Y0[i][j]), cimagf(Y0[i][j])); } printf("\n"); } // print traditional channelizer printf("\n"); printf("traditional channelizer:\n"); for (i=0; i<num_symbols; i++) { printf("%3u: ", i); for (j=0; j<num_channels; j++) { printf(" %8.5f+j%8.5f, ", crealf(Y1[i][j]), cimagf(Y1[i][j])); } printf("\n"); } // // compare results // float mse[num_channels]; float complex d; for (i=0; i<num_channels; i++) { mse[i] = 0.0f; for (j=0; j<num_symbols; j++) { d = Y0[j][i] - Y1[j][i]; mse[i] += crealf(d*conjf(d)); } mse[i] /= num_symbols; } printf("\n"); printf("rmse: "); for (i=0; i<num_channels; i++) printf("%12.4e ", sqrt(mse[i])); printf("\n"); printf("done.\n"); return 0; }
void ofdmoqamframe64sync_destroy(ofdmoqamframe64sync _q) { #if DEBUG_OFDMOQAMFRAME64SYNC ofdmoqamframe64sync_debug_print(_q); windowcf_destroy(_q->debug_x); windowcf_destroy(_q->debug_rxx); windowcf_destroy(_q->debug_rxy); windowcf_destroy(_q->debug_framesyms); windowf_destroy(_q->debug_pilotphase); windowf_destroy(_q->debug_pilotphase_hat); windowf_destroy(_q->debug_rssi); #endif // free analysis filter bank memory objects firpfbch_destroy(_q->ca0); firpfbch_destroy(_q->ca1); free(_q->X0); free(_q->X1); free(_q->Y0); free(_q->Y1); // clean up PLCP arrays free(_q->S0); free(_q->S1); free(_q->S2); free(_q->S1a); free(_q->S1b); // free pilot msequence object memory msequence_destroy(_q->ms_pilot); // free agc | signal detection object memory agc_crcf_destroy(_q->sigdet); // free NCO object memory nco_crcf_destroy(_q->nco_rx); // free auto-correlator memory objects autocorr_cccf_destroy(_q->autocorr); // free cross-correlator memory objects firfilt_cccf_destroy(_q->crosscorr); free(_q->hxy); // free gain arrays free(_q->G0); free(_q->G1); free(_q->G); // free data buffer free(_q->data); // free input buffer windowcf_destroy(_q->input_buffer); nco_crcf_destroy(_q->nco_pilot); pll_destroy(_q->pll_pilot); // free main object memory free(_q); }
// compute ISI for entire system // _gt : transmit filter [size: _gt_len x 1] // _hc : channel filter [size: _hc_len x 1] // _gr : receive filter [size: _gr_len x 1] float eqlms_cccf_isi(unsigned int _k, float complex * _gt, unsigned int _gt_len, float complex * _hc, unsigned int _hc_len, float complex * _gr, unsigned int _gr_len) { // generate composite by convolving all filters together unsigned int i; #if 0 printf("\n"); for (i=0; i<_gt_len; i++) printf(" gt(%3u) = %16.12f + j*%16.12f;\n", i+1, crealf(_gt[i]), cimagf(_gt[i])); printf("\n"); for (i=0; i<_hc_len; i++) printf(" hc(%3u) = %16.12f + j*%16.12f;\n", i+1, crealf(_hc[i]), cimagf(_hc[i])); printf("\n"); for (i=0; i<_gr_len; i++) printf(" gr(%3u) = %16.12f + j*%16.12f;\n", i+1, crealf(_gr[i]), cimagf(_gr[i])); printf("\n"); #endif windowcf w; float complex * rc; // start by convolving transmit and channel filters unsigned int gthc_len = _gt_len + _hc_len - 1; float complex gthc[gthc_len]; w = windowcf_create(_gt_len); for (i=0; i<gthc_len; i++) { if (i < _hc_len) windowcf_push(w, conjf(_hc[_hc_len-i-1])); else windowcf_push(w, 0.0f); windowcf_read(w, &rc); dotprod_cccf_run(_gt, rc, _gt_len, >hc[i]); } windowcf_destroy(w); #if 0 printf("composite filter:\n"); for (i=0; i<gthc_len; i++) printf(" gthc(%3u) = %16.12f + j*%16.12f;\n", i+1, crealf(gthc[i]), cimagf(gthc[i])); #endif // convolve result with equalizer unsigned int h_len = gthc_len + _gr_len - 1; float complex h[h_len]; w = windowcf_create(gthc_len); for (i=0; i<h_len; i++) { if (i < _gr_len) windowcf_push(w, conjf(_gr[i])); else windowcf_push(w, 0.0f); windowcf_read(w, &rc); dotprod_cccf_run(gthc, rc, gthc_len, &h[i]); } windowcf_destroy(w); #if 0 printf("composite filter:\n"); for (i=0; i<h_len; i++) printf(" h(%3u) = %16.12f + j*%16.12f;\n", i+1, crealf(h[i]), cimagf(h[i])); #endif // compute resulting ISI unsigned int n0 = (_gt_len + _gr_len + (_gt_len + _gr_len)%2)/2 - 1; float isi = 0.0f; unsigned int n=0; for (i=0; i<h_len; i++) { if (i == n0) continue; else if ( (i%_k)==0 ) { isi += crealf( h[i]*conjf(h[i]) ); n++; } } isi /= crealf( h[n0]*conjf(h[n0]) ); isi = sqrtf(isi / (float)n); return isi; }
// main program int main (int argc, char **argv) { // command-line options int verbose = 1; int ppm_error = 0; int gain = 0; unsigned int nfft = 64; float offset = -65.0f; float scale = 5.0f; float fft_rate = 10.0f; float rx_resamp_rate; float bandwidth = 800e3f; unsigned int logsize = 4096; char filename[256] = "rtl_asgram.dat"; int r, n_read; uint32_t frequency = 100000000; uint32_t samp_rate = DEFAULT_SAMPLE_RATE; uint32_t out_block_size = DEFAULT_BUF_LENGTH; uint8_t *buffer; int dev_index = 0; int dev_given = 0; struct sigaction sigact; normalizer_t *norm; // int d; while ((d = getopt(argc,argv,"hf:b:B:G:n:p:s:o:r:L:F:")) != EOF) { switch (d) { case 'h': usage(); return 0; case 'f': frequency = atof(optarg); break; case 'b': bandwidth = atof(optarg); break; case 'B': out_block_size = (uint32_t)atof(optarg); break; case 'G': gain = (int)(atof(optarg) * 10); break; case 'n': nfft = atoi(optarg); break; case 'o': offset = atof(optarg); break; case 'p': ppm_error = atoi(optarg); break; case 's': samp_rate = (uint32_t)atofs(optarg); break; case 'r': fft_rate = atof(optarg); break; case 'L': logsize = atoi(optarg); break; case 'F': strncpy(filename,optarg,255); break; case 'd': dev_index = verbose_device_search(optarg); dev_given = 1; break; default: usage(); return 1; } } // validate parameters if (fft_rate <= 0.0f || fft_rate > 100.0f) { fprintf(stderr,"error: %s, fft rate must be in (0, 100) Hz\n", argv[0]); exit(1); } if (!dev_given) { dev_index = verbose_device_search("0"); } if (dev_index < 0) { exit(1); } r = rtlsdr_open(&dev, (uint32_t)dev_index); if (r < 0) { fprintf(stderr, "Failed to open rtlsdr device #%d.\n", dev_index); exit(1); } sigact.sa_handler = sighandler; sigemptyset(&sigact.sa_mask); sigact.sa_flags = 0; sigaction(SIGINT, &sigact, NULL); sigaction(SIGTERM, &sigact, NULL); sigaction(SIGQUIT, &sigact, NULL); sigaction(SIGPIPE, &sigact, NULL); /* Set the sample rate */ verbose_set_sample_rate(dev, samp_rate); /* Set the frequency */ verbose_set_frequency(dev, frequency); if (0 == gain) { /* Enable automatic gain */ verbose_auto_gain(dev); } else { /* Enable manual gain */ gain = nearest_gain(dev, gain); verbose_gain_set(dev, gain); } verbose_ppm_set(dev, ppm_error); rx_resamp_rate = bandwidth/samp_rate; printf("frequency : %10.4f [MHz]\n", frequency*1e-6f); printf("bandwidth : %10.4f [kHz]\n", bandwidth*1e-3f); printf("sample rate : %10.4f kHz = %10.4f kHz * %8.6f\n", samp_rate * 1e-3f, bandwidth * 1e-3f, 1.0f / rx_resamp_rate); printf("verbosity : %s\n", (verbose?"enabled":"disabled")); unsigned int i; // add arbitrary resampling component msresamp_crcf resamp = msresamp_crcf_create(rx_resamp_rate, 60.0f); assert(resamp); // create buffer for sample logging windowcf log = windowcf_create(logsize); // create ASCII spectrogram object float maxval; float maxfreq; char ascii[nfft+1]; ascii[nfft] = '\0'; // append null character to end of string asgram q = asgram_create(nfft); asgram_set_scale(q, offset, scale); // assemble footer unsigned int footer_len = nfft + 16; char footer[footer_len+1]; for (i=0; i<footer_len; i++) footer[i] = ' '; footer[1] = '['; footer[nfft/2 + 3] = '+'; footer[nfft + 4] = ']'; sprintf(&footer[nfft+6], "%8.3f MHz", frequency*1e-6f); unsigned int msdelay = 1000 / fft_rate; // create/initialize Hamming window float w[nfft]; for (i=0; i<nfft; i++) w[i] = hamming(i,nfft); //allocate recv buffer buffer = malloc(out_block_size * sizeof(uint8_t)); assert(buffer); // create buffer for arbitrary resamper output int b_len = ((int)(out_block_size * rx_resamp_rate) + 64) >> 1; complex float buffer_resamp[b_len]; debug("resamp_buffer_len: %d", b_len); // timer to control asgram output timer t1 = timer_create(); timer_tic(t1); norm = normalizer_create(); verbose_reset_buffer(dev); while (!do_exit) { // grab data from device r = rtlsdr_read_sync(dev, buffer, out_block_size, &n_read); if (r < 0) { fprintf(stderr, "WARNING: sync read failed.\n"); break; } if ((bytes_to_read > 0) && (bytes_to_read < (uint32_t)n_read)) { n_read = bytes_to_read; do_exit = 1; } // push data through arbitrary resampler and give to frame synchronizer // TODO : apply bandwidth-dependent gain for (i=0; i<n_read/2; i++) { // grab sample from usrp buffer complex float rtlsdr_sample = normalizer_normalize(norm, *((uint16_t*)buffer+i)); // push through resampler (one at a time) unsigned int nw; msresamp_crcf_execute(resamp, &rtlsdr_sample, 1, buffer_resamp, &nw); // push resulting samples into asgram object asgram_push(q, buffer_resamp, nw); // write samples to log windowcf_write(log, buffer_resamp, nw); } if ((uint32_t)n_read < out_block_size) { fprintf(stderr, "Short read, samples lost, exiting!\n"); break; } if (bytes_to_read > 0) bytes_to_read -= n_read; if (timer_toc(t1) > msdelay*1e-3f) { // reset timer timer_tic(t1); // run the spectrogram asgram_execute(q, ascii, &maxval, &maxfreq); // print the spectrogram printf(" > %s < pk%5.1fdB [%5.2f]\n", ascii, maxval, maxfreq); printf("%s\r", footer); fflush(stdout); } } // try to write samples to file FILE * fid = fopen(filename,"w"); if (fid != NULL) { // write header fprintf(fid, "# %s : auto-generated file\n", filename); fprintf(fid, "#\n"); fprintf(fid, "# num_samples : %u\n", logsize); fprintf(fid, "# frequency : %12.8f MHz\n", frequency*1e-6f); fprintf(fid, "# bandwidth : %12.8f kHz\n", bandwidth*1e-3f); // save results to file complex float * rc; // read pointer windowcf_read(log, &rc); for (i=0; i<logsize; i++) fprintf(fid, "%12.4e %12.4e\n", crealf(rc[i]), cimagf(rc[i])); // close it up fclose(fid); printf("results written to '%s'\n", filename); } else { fprintf(stderr,"error: %s, could not open '%s' for writing\n", argv[0], filename); } // destroy objects normalizer_destroy(&norm); msresamp_crcf_destroy(resamp); windowcf_destroy(log); asgram_destroy(q); timer_destroy(t1); rtlsdr_close(dev); free (buffer); return 0; }
int main(int argc, char*argv[]) { // options unsigned int num_channels=6; // number of channels (must be even) unsigned int m=4; // filter delay unsigned int num_symbols=4*m; // number of symbols // validate input if (num_channels%2) { fprintf(stderr,"error: %s, number of channels must be even\n", argv[0]); exit(1); } // derived values unsigned int num_samples = num_channels * num_symbols; unsigned int i; unsigned int j; // generate filter // NOTE : these coefficients can be random; the purpose of this // exercise is to demonstrate mathematical equivalence #if 0 unsigned int h_len = 2*m*num_channels; float h[h_len]; for (i=0; i<h_len; i++) h[i] = randnf(); #else unsigned int h_len = 2*m*num_channels+1; float h[h_len]; // NOTE: 81.29528 dB > beta = 8.00000 (6 channels, m=4) liquid_firdes_kaiser(h_len, 1.0f/(float)num_channels, 81.29528f, 0.0f, h); #endif // normalize float hsum = 0.0f; for (i=0; i<h_len; i++) hsum += h[i]; for (i=0; i<h_len; i++) h[i] = h[i] * num_channels / hsum; // sub-sampled filters for M=6 channels, m=4, beta=8.0 // -3.2069e-19 -6.7542e-04 -1.3201e-03 2.2878e-18 3.7613e-03 5.8033e-03 // -7.2899e-18 -1.2305e-02 -1.7147e-02 1.6510e-17 3.1187e-02 4.0974e-02 // -3.0032e-17 -6.8026e-02 -8.6399e-02 4.6273e-17 1.3732e-01 1.7307e-01 // -6.2097e-17 -2.8265e-01 -3.7403e-01 7.3699e-17 8.0663e-01 1.6438e+00 // 2.0001e+00 1.6438e+00 8.0663e-01 7.3699e-17 -3.7403e-01 -2.8265e-01 // -6.2097e-17 1.7307e-01 1.3732e-01 4.6273e-17 -8.6399e-02 -6.8026e-02 // -3.0032e-17 4.0974e-02 3.1187e-02 1.6510e-17 -1.7147e-02 -1.2305e-02 // -7.2899e-18 5.8033e-03 3.7613e-03 2.2878e-18 -1.3201e-03 -6.7542e-04 // create filterbank manually dotprod_crcf dp[num_channels]; // vector dot products windowcf w[num_channels]; // window buffers #if DEBUG // print coefficients printf("h_prototype:\n"); for (i=0; i<h_len; i++) printf(" h[%3u] = %12.8f\n", i, h[i]); #endif // create objects unsigned int h_sub_len = 2*m; float h_sub[h_sub_len]; for (i=0; i<num_channels; i++) { // sub-sample prototype filter #if 0 for (j=0; j<h_sub_len; j++) h_sub[j] = h[j*num_channels+i]; #else // load coefficients in reverse order for (j=0; j<h_sub_len; j++) h_sub[h_sub_len-j-1] = h[j*num_channels+i]; #endif // create window buffer and dotprod objects dp[i] = dotprod_crcf_create(h_sub, h_sub_len); w[i] = windowcf_create(h_sub_len); #if DEBUG printf("h_sub[%u] : \n", i); for (j=0; j<h_sub_len; j++) printf(" h[%3u] = %12.8f\n", j, h_sub[j]); #endif } // generate DFT object float complex x[num_channels]; // time-domain buffer float complex X[num_channels]; // freq-domain buffer #if 1 fftplan fft = fft_create_plan(num_channels, X, x, LIQUID_FFT_BACKWARD, 0); #else fftplan fft = fft_create_plan(num_channels, X, x, LIQUID_FFT_FORWARD, 0); #endif float complex y[num_samples]; // time-domain input float complex Y0[2*num_symbols][num_channels]; // channelizer output float complex Y1[2*num_symbols][num_channels]; // conventional output // generate input sequence for (i=0; i<num_samples; i++) { //y[i] = randnf() * cexpf(_Complex_I*randf()*2*M_PI); y[i] = (i==0) ? 1.0f : 0.0f; y[i] = cexpf(_Complex_I*sqrtf(2.0f)*i*i); printf("y[%3u] = %12.8f + %12.8fj\n", i, crealf(y[i]), cimagf(y[i])); } // // run analysis filter bank // #if 0 unsigned int filter_index = 0; #else unsigned int filter_index = num_channels/2-1; #endif float complex y_hat; // input sample float complex * r; // buffer read pointer int toggle = 0; // flag indicating buffer/filter alignment // for (i=0; i<2*num_symbols; i++) { // load buffers in blocks of num_channels/2 for (j=0; j<num_channels/2; j++) { // grab sample y_hat = y[i*num_channels/2 + j]; // push sample into buffer at filter index windowcf_push(w[filter_index], y_hat); // decrement filter index filter_index = (filter_index + num_channels - 1) % num_channels; //filter_index = (filter_index + 1) % num_channels; } // execute filter outputs // reversing order of output (not sure why this is necessary) unsigned int offset = toggle ? num_channels/2 : 0; toggle = 1-toggle; for (j=0; j<num_channels; j++) { unsigned int buffer_index = (offset+j)%num_channels; unsigned int dotprod_index = j; windowcf_read(w[buffer_index], &r); //dotprod_crcf_execute(dp[dotprod_index], r, &X[num_channels-j-1]); dotprod_crcf_execute(dp[dotprod_index], r, &X[buffer_index]); } printf("***** i = %u\n", i); for (j=0; j<num_channels; j++) printf(" v2[%4u] = %12.8f + %12.8fj\n", j, crealf(X[j]), cimagf(X[j])); // execute DFT, store result in buffer 'x' fft_execute(fft); // scale fft output for (j=0; j<num_channels; j++) x[j] *= 1.0f / (num_channels); // move to output array for (j=0; j<num_channels; j++) Y0[i][j] = x[j]; } // destroy objects for (i=0; i<num_channels; i++) { dotprod_crcf_destroy(dp[i]); windowcf_destroy(w[i]); } fft_destroy_plan(fft); // // run traditional down-converter (inefficient) // // generate filter object firfilt_crcf f = firfilt_crcf_create(h, h_len); float dphi; // carrier frequency unsigned int n=0; for (i=0; i<num_channels; i++) { // reset filter firfilt_crcf_clear(f); // set center frequency dphi = 2.0f * M_PI * (float)i / (float)num_channels; // reset symbol counter n=0; for (j=0; j<num_samples; j++) { // push down-converted sample into filter firfilt_crcf_push(f, y[j]*cexpf(-_Complex_I*j*dphi)); // compute output at the appropriate sample time assert(n<2*num_symbols); if ( ((j+1)%(num_channels/2))==0 ) { firfilt_crcf_execute(f, &Y1[n][i]); n++; } } assert(n==2*num_symbols); } firfilt_crcf_destroy(f); // print filterbank channelizer printf("\n"); printf("filterbank channelizer:\n"); for (i=0; i<2*num_symbols; i++) { printf("%2u:", i); for (j=0; j<num_channels; j++) { printf("%6.3f+%6.3fj, ", crealf(Y0[i][j]), cimagf(Y0[i][j])); } printf("\n"); } #if 0 // print traditional channelizer printf("\n"); printf("traditional channelizer:\n"); for (i=0; i<2*num_symbols; i++) { printf("%2u:", i); for (j=0; j<num_channels; j++) { printf("%6.3f+%6.3fj, ", crealf(Y1[i][j]), cimagf(Y1[i][j])); } printf("\n"); } // // compare results // float mse[num_channels]; float complex d; for (i=0; i<num_channels; i++) { mse[i] = 0.0f; for (j=0; j<2*num_symbols; j++) { d = Y0[j][i] - Y1[j][i]; mse[i] += crealf(d*conjf(d)); } mse[i] /= num_symbols; } printf("\n"); printf(" e:"); for (i=0; i<num_channels; i++) printf("%12.4e ", sqrt(mse[i])); printf("\n"); #endif printf("done.\n"); return 0; }