// 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); }
// create WLAN framing synchronizer object // _callback : user-defined callback function // _userdata : user-defined data structure wlanframesync wlanframesync_create(wlanframesync_callback _callback, void * _userdata) { // allocate main object memory wlanframesync q = (wlanframesync) malloc(sizeof(struct wlanframesync_s)); // set callback data q->callback = _callback; q->userdata = _userdata; // create transform object q->X = (float complex*) malloc(64*sizeof(float complex)); q->x = (float complex*) malloc(64*sizeof(float complex)); q->fft = FFT_CREATE_PLAN(64, q->x, q->X, FFT_DIR_FORWARD, FFT_METHOD); // create input buffer the length of the transform q->input_buffer = windowcf_create(80); // synchronizer objects q->nco_rx = nco_crcf_create(LIQUID_VCO); q->ms_pilot = wlan_lfsr_create(7, 0x91, 0x7f); q->mod_scheme = WLAN_MODEM_BPSK; // set initial properties q->rate = WLANFRAME_RATE_6; q->length = 100; q->seed = 0x5d; // allocate memory for encoded message q->enc_msg_len = wlan_packet_compute_enc_msg_len(q->rate, q->length); q->msg_enc = (unsigned char*) malloc(q->enc_msg_len*sizeof(unsigned char)); // allocate memory for decoded message q->dec_msg_len = 1; q->msg_dec = (unsigned char*) malloc(q->dec_msg_len*sizeof(unsigned char)); // reset object wlanframesync_reset(q); #if DEBUG_WLANFRAMESYNC // debugging structures q->debug_enabled = 0; q->agc_rx = NULL; q->debug_x = NULL; q->debug_rssi = NULL; q->debug_framesyms = NULL; #endif // return object return q; }
int main (int argc, char ** argv) { w=windowcf_create(SPECTRUM_FFT_LENGTH); wchA = windowcf_create(TRACK_LENGTH); wchB = windowcf_create(TRACK_LENGTH); wchC = windowcf_create(TRACK_LENGTH); wchA_filtered = windowcf_create(TRACK_LENGTH); wchB_filtered = windowcf_create(TRACK_LENGTH); wchC_filtered = windowcf_create(TRACK_LENGTH); wmag_buffer = windowf_create(TRACK_LENGTH); nco = nco_crcf_create(LIQUID_NCO); std::cout << "hydromath daemon is beginning..." << std::endl; std::cout << "NOTE: if this is symhydromath you must pass in a matfile" << std::endl; std::cout << argv[1] << std::endl; shm_init(); shm_getg(hydrophones_results_track, shm_results_track); shm_getg(hydrophones_results_spectrum, shm_results_spectrum); //shm_results_track.tracked_ping_count=0; shm_results_track.tracked_ping_time=0; if (argc > 1) { udp_init(argv[1]); } else { udp_init(""); } //std::thread track_thread(direction_loop); // //std::thread spectrum_thread(spectrum_loop); track_sample_idx = 0; while (loop(&spt) == 0) { shm_getg(hydrophones_settings, shm_settings); for (int i = 0; i < 3*CHANNEL_DEPTH; i+=3) { windowcf_push(w, std::complex<float>(spt.data[i+1],0)); //This uses channel B windowcf_push(wchA, std::complex<float>(spt.data[i],0)); windowcf_push(wchB, std::complex<float>(spt.data[i+1],0)); windowcf_push(wchC, std::complex<float>(spt.data[i+2],0)); } current_sample_count+=CHANNEL_DEPTH; do_spectrum(); do_track(); } printf("loop done %li =ci\n",current_sample_count/CHANNEL_DEPTH); return 0; }
void wlanframesync_debug_enable(wlanframesync _q) { // create debugging objects if necessary #if DEBUG_WLANFRAMESYNC // agc, rssi if (_q->agc_rx == NULL) _q->agc_rx = agc_crcf_create(); agc_crcf_set_bandwidth(_q->agc_rx, 1e-2f); agc_crcf_set_gain_limits(_q->agc_rx, 1.0f, 1e7f); if (_q->debug_x == NULL) _q->debug_x = windowcf_create(DEBUG_WLANFRAMESYNC_BUFFER_LEN); if (_q->debug_rssi == NULL) _q->debug_rssi = windowf_create(DEBUG_WLANFRAMESYNC_BUFFER_LEN); if (_q->debug_framesyms == NULL) _q->debug_framesyms = windowcf_create(DEBUG_WLANFRAMESYNC_BUFFER_LEN); _q->debug_enabled = 1; #else fprintf(stderr,"wlanframesync_debug_enable(): compile-time debugging disabled\n"); #endif }
// enable debugging void ofdmframesync_debug_enable(ofdmframesync _q) { // create debugging objects if necessary #if DEBUG_OFDMFRAMESYNC if (_q->debug_objects_created) return; _q->debug_x = windowcf_create(DEBUG_OFDMFRAMESYNC_BUFFER_LEN); _q->debug_rssi = windowf_create(DEBUG_OFDMFRAMESYNC_BUFFER_LEN); _q->debug_framesyms = windowcf_create(DEBUG_OFDMFRAMESYNC_BUFFER_LEN); _q->G_hat = (float complex*) malloc((_q->M)*sizeof(float complex)); _q->px = (float*) malloc((_q->M_pilot)*sizeof(float)); _q->py = (float*) malloc((_q->M_pilot)*sizeof(float)); _q->debug_pilot_0 = windowf_create(DEBUG_OFDMFRAMESYNC_BUFFER_LEN); _q->debug_pilot_1 = windowf_create(DEBUG_OFDMFRAMESYNC_BUFFER_LEN); _q->debug_enabled = 1; _q->debug_objects_created = 1; #else fprintf(stderr,"ofdmframesync_debug_enable(): compile-time debugging disabled\n"); #endif }
// enable debugging void flexframesync_debug_enable(flexframesync _q) { // create debugging objects if necessary #if DEBUG_FLEXFRAMESYNC if (_q->debug_objects_created) return; // create debugging objects _q->debug_x = windowcf_create(DEBUG_BUFFER_LEN); // set debugging flags _q->debug_enabled = 1; _q->debug_objects_created = 1; #else fprintf(stderr,"flexframesync_debug_enable(): compile-time debugging disabled\n"); #endif }
void gmskframesync_debug_enable(gmskframesync _q) { // create debugging objects if necessary #if DEBUG_GMSKFRAMESYNC if (!_q->debug_objects_created) { _q->debug_x = windowcf_create(DEBUG_GMSKFRAMESYNC_BUFFER_LEN); _q->debug_fi = windowf_create(DEBUG_GMSKFRAMESYNC_BUFFER_LEN); _q->debug_mf = windowf_create(DEBUG_GMSKFRAMESYNC_BUFFER_LEN); _q->debug_framesyms = windowf_create(DEBUG_GMSKFRAMESYNC_BUFFER_LEN); } // set debugging flags _q->debug_enabled = 1; _q->debug_objects_created = 1; #else fprintf(stderr,"gmskframesync_debug_enable(): compile-time debugging disabled\n"); #endif }
// create ampmodem object // _m : modulation index // _fc : carrier frequency // _type : AM type (e.g. LIQUID_AMPMODEM_DSB) // _suppressed_carrier : carrier suppression flag ampmodem ampmodem_create(float _m, float _fc, liquid_ampmodem_type _type, int _suppressed_carrier) { ampmodem q = (ampmodem) malloc(sizeof(struct ampmodem_s)); q->type = _type; q->m = _m; q->fc = _fc; q->suppressed_carrier = (_suppressed_carrier == 0) ? 0 : 1; // create nco, pll objects q->oscillator = nco_crcf_create(LIQUID_NCO); nco_crcf_set_frequency(q->oscillator, 2*M_PI*q->fc); nco_crcf_pll_set_bandwidth(q->oscillator,0.05f); // suppressed carrier q->ssb_alpha = 0.01f; q->ssb_q_hat = 0.0f; // single side-band q->hilbert = firhilbf_create(9, 60.0f); // double side-band ampmodem_reset(q); // debugging #if DEBUG_AMPMODEM q->debug_x = windowcf_create(DEBUG_AMPMODEM_BUFFER_LEN); q->debug_phase_error = windowf_create(DEBUG_AMPMODEM_BUFFER_LEN); q->debug_freq_error = windowf_create(DEBUG_AMPMODEM_BUFFER_LEN); #endif return 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; }
// 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; }
// create flexframesync object // _callback : callback function invoked when frame is received // _userdata : user-defined data object passed to callback flexframesync flexframesync_create(framesync_callback _callback, void * _userdata) { flexframesync q = (flexframesync) malloc(sizeof(struct flexframesync_s)); q->callback = _callback; q->userdata = _userdata; unsigned int i; // generate p/n sequence msequence ms = msequence_create(6, 0x005b, 1); for (i=0; i<64; i++) q->preamble_pn[i] = (msequence_advance(ms)) ? 1.0f : -1.0f; msequence_destroy(ms); // interpolate p/n sequence with matched filter q->k = 2; // samples/symbol q->m = 7; // filter delay (symbols) q->beta = 0.25f; // excess bandwidth factor float complex seq[q->k*64]; firinterp_crcf interp = firinterp_crcf_create_rnyquist(LIQUID_FIRFILT_ARKAISER,q->k,q->m,q->beta,0); for (i=0; i<64+q->m; i++) { // compensate for filter delay if (i < q->m) firinterp_crcf_execute(interp, q->preamble_pn[i], &seq[0]); else firinterp_crcf_execute(interp, q->preamble_pn[i%64], &seq[q->k*(i-q->m)]); } firinterp_crcf_destroy(interp); // create frame detector float threshold = 0.4f; // detection threshold float dphi_max = 0.05f; // maximum carrier offset allowable q->frame_detector = detector_cccf_create(seq, q->k*64, threshold, dphi_max); q->buffer = windowcf_create(q->k*(64+q->m)); // create symbol timing recovery filters q->npfb = 32; // number of filters in the bank q->mf = firpfb_crcf_create_rnyquist(LIQUID_FIRFILT_ARKAISER, q->npfb,q->k,q->m,q->beta); q->dmf = firpfb_crcf_create_drnyquist(LIQUID_FIRFILT_ARKAISER,q->npfb,q->k,q->m,q->beta); // create down-coverters for carrier phase tracking q->nco_coarse = nco_crcf_create(LIQUID_NCO); q->nco_fine = nco_crcf_create(LIQUID_VCO); nco_crcf_pll_set_bandwidth(q->nco_fine, 0.05f); // create header objects q->demod_header = modem_create(LIQUID_MODEM_BPSK); q->p_header = packetizer_create(FLEXFRAME_H_DEC, FLEXFRAME_H_CRC, FLEXFRAME_H_FEC0, FLEXFRAME_H_FEC1); assert(packetizer_get_enc_msg_len(q->p_header)==FLEXFRAME_H_ENC); // frame properties (default values to be overwritten when frame // header is received and properly decoded) q->ms_payload = LIQUID_MODEM_QPSK; q->bps_payload = 2; q->payload_dec_len = 1; q->check = LIQUID_CRC_NONE; q->fec0 = LIQUID_FEC_NONE; q->fec1 = LIQUID_FEC_NONE; // create payload objects (overridden by received properties) q->demod_payload = modem_create(LIQUID_MODEM_QPSK); q->p_payload = packetizer_create(q->payload_dec_len, q->check, q->fec0, q->fec1); q->payload_enc_len = packetizer_get_enc_msg_len(q->p_payload); q->payload_mod_len = 4 * q->payload_enc_len; q->payload_mod = (unsigned char*) malloc(q->payload_mod_len*sizeof(unsigned char)); q->payload_enc = (unsigned char*) malloc(q->payload_enc_len*sizeof(unsigned char)); q->payload_dec = (unsigned char*) malloc(q->payload_dec_len*sizeof(unsigned char)); #if DEBUG_FLEXFRAMESYNC // set debugging flags, objects to NULL q->debug_enabled = 0; q->debug_objects_created = 0; q->debug_x = NULL; #endif // reset state flexframesync_reset(q); return q; }
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; }
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; }
// 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; }
// create GMSK frame synchronizer // _callback : callback function // _userdata : user data pointer passed to callback function gmskframesync gmskframesync_create(framesync_callback _callback, void * _userdata) { gmskframesync q = (gmskframesync) malloc(sizeof(struct gmskframesync_s)); q->callback = _callback; q->userdata = _userdata; q->k = 2; // samples/symbol q->m = 3; // filter delay (symbols) q->BT = 0.5f; // filter bandwidth-time product #if GMSKFRAMESYNC_PREFILTER // create default low-pass Butterworth filter q->prefilter = iirfilt_crcf_create_lowpass(3, 0.5f*(1 + q->BT) / (float)(q->k)); #endif unsigned int i; // frame detector q->preamble_len = 63; q->preamble_pn = (float*)malloc(q->preamble_len*sizeof(float)); q->preamble_rx = (float*)malloc(q->preamble_len*sizeof(float)); float complex preamble_samples[q->preamble_len*q->k]; msequence ms = msequence_create(6, 0x6d, 1); gmskmod mod = gmskmod_create(q->k, q->m, q->BT); for (i=0; i<q->preamble_len + q->m; i++) { unsigned char bit = msequence_advance(ms); // save p/n sequence if (i < q->preamble_len) q->preamble_pn[i] = bit ? 1.0f : -1.0f; // modulate/interpolate if (i < q->m) gmskmod_modulate(mod, bit, &preamble_samples[0]); else gmskmod_modulate(mod, bit, &preamble_samples[(i-q->m)*q->k]); } gmskmod_destroy(mod); msequence_destroy(ms); #if 0 // print sequence for (i=0; i<q->preamble_len*q->k; i++) printf("preamble(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(preamble_samples[i]), cimagf(preamble_samples[i])); #endif // create frame detector float threshold = 0.5f; // detection threshold float dphi_max = 0.05f; // maximum carrier offset allowable q->frame_detector = detector_cccf_create(preamble_samples, q->preamble_len*q->k, threshold, dphi_max); q->buffer = windowcf_create(q->k*(q->preamble_len+q->m)); // create symbol timing recovery filters q->npfb = 32; // number of filters in the bank q->mf = firpfb_rrrf_create_rnyquist( LIQUID_FIRFILT_GMSKRX,q->npfb,q->k,q->m,q->BT); q->dmf = firpfb_rrrf_create_drnyquist(LIQUID_FIRFILT_GMSKRX,q->npfb,q->k,q->m,q->BT); // create down-coverters for carrier phase tracking q->nco_coarse = nco_crcf_create(LIQUID_NCO); // create/allocate header objects/arrays q->header_mod = (unsigned char*)malloc(GMSKFRAME_H_SYM*sizeof(unsigned char)); q->header_enc = (unsigned char*)malloc(GMSKFRAME_H_ENC*sizeof(unsigned char)); q->header_dec = (unsigned char*)malloc(GMSKFRAME_H_DEC*sizeof(unsigned char)); q->p_header = packetizer_create(GMSKFRAME_H_DEC, GMSKFRAME_H_CRC, GMSKFRAME_H_FEC, LIQUID_FEC_NONE); // create/allocate payload objects/arrays q->payload_dec_len = 1; q->check = LIQUID_CRC_32; q->fec0 = LIQUID_FEC_NONE; q->fec1 = LIQUID_FEC_NONE; q->p_payload = packetizer_create(q->payload_dec_len, q->check, q->fec0, q->fec1); q->payload_enc_len = packetizer_get_enc_msg_len(q->p_payload); q->payload_dec = (unsigned char*) malloc(q->payload_dec_len*sizeof(unsigned char)); q->payload_enc = (unsigned char*) malloc(q->payload_enc_len*sizeof(unsigned char)); #if DEBUG_GMSKFRAMESYNC // debugging structures q->debug_enabled = 0; q->debug_objects_created = 0; q->debug_x = NULL; q->debug_fi = NULL; q->debug_mf = NULL; q->debug_framesyms = NULL; #endif // reset synchronizer gmskframesync_reset(q); // return synchronizer object return 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; }
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; }