// Help function to keep code base small // _kf : modulation factor // _type : demodulation type {LIQUID_FREQDEM_DELAYCONJ, LIQUID_FREQDEM_PLL} void freqmodem_test(float _kf, liquid_freqdem_type _type) { // options unsigned int num_samples = 1024; //float tol = 1e-2f; unsigned int i; // create mod/demod objects freqmod mod = freqmod_create(_kf); // modulator freqdem dem = freqdem_create(_kf,_type); // demodulator // allocate arrays float m[num_samples]; // message signal float complex r[num_samples]; // received signal (complex baseband) float y[num_samples]; // demodulator output // generate message signal (single-frequency sine) for (i=0; i<num_samples; i++) m[i] = 0.7f*cosf(2*M_PI*0.013f*i + 0.0f); // modulate/demodulate signal for (i=0; i<num_samples; i++) { // modulate freqmod_modulate(mod, m[i], &r[i]); // demodulate freqdem_demodulate(dem, r[i], &y[i]); } // delete modem objects freqmod_destroy(mod); freqdem_destroy(dem); #if 0 // compute power spectral densities and compare float complex mcf[num_samples]; float complex ycf[num_samples]; float complex M[num_samples]; float complex Y[num_samples]; for (i=0; i<num_samples; i++) { mcf[i] = m[i] * hamming(i,num_samples); ycf[i] = y[i] * hamming(i,num_samples); } fft_run(num_samples, mcf, M, LIQUID_FFT_FORWARD, 0); fft_run(num_samples, ycf, Y, LIQUID_FFT_FORWARD, 0); // run test: compare spectral magnitude for (i=0; i<num_samples; i++) CONTEND_DELTA( cabsf(Y[i]), cabsf(M[i]), tol ); #endif }
// main program int main (int argc, char **argv) { // command-line options int verbose = 1; int ppm_error = 0; int gain = 0; float rx_resamp_rate; float bandwidth = 800e3f; 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; complex float *buffer_norm; int dev_index = 0; int dev_given = 0; struct sigaction sigact; normalizer_t *norm; float kf = 0.1f; // modulation factor liquid_freqdem_type type = LIQUID_FREQDEM_DELAYCONJ; // int d; while ((d = getopt(argc,argv,"hf:b:B:G:p:s:")) != 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 'p': ppm_error = atoi(optarg); break; case 's': samp_rate = (uint32_t)atofs(optarg); break; case 'd': dev_index = verbose_device_search(optarg); dev_given = 1; break; default: usage(); return 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,j; // add arbitrary resampling component msresamp_crcf resamp = msresamp_crcf_create(rx_resamp_rate, 60.0f); assert(resamp); //allocate recv buffer buffer = malloc(out_block_size * sizeof(uint8_t)); assert(buffer); buffer_norm = malloc(out_block_size * sizeof(complex float)); assert(buffer_norm); // create buffer for arbitrary resamper output int b_len = ((int)(out_block_size * rx_resamp_rate) + 64) >> 1; complex float buffer_resamp[b_len]; int16_t buffer_demod[b_len]; debug("resamp_buffer_len: %d\n", b_len); norm = normalizer_create(); verbose_reset_buffer(dev); freqdem dem = freqdem_create(kf,type); 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 buffer_norm[i] = normalizer_normalize(norm, *((uint16_t*)buffer+i)); } // push through resampler (one at a time) unsigned int nw; float demod; msresamp_crcf_execute(resamp, buffer_norm, n_read/2, buffer_resamp, &nw); for(j=0;j<nw;j++) { freqdem_demodulate(dem, buffer_resamp[j], &demod); buffer_demod[j] = to_int16(demod); } if (fwrite(buffer_demod, 2, nw, stdout) != (size_t)nw) { fprintf(stderr, "Short write, samples lost, exiting!\n"); break; } 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; } // destroy objects freqdem_destroy(dem); normalizer_destroy(&norm); msresamp_crcf_destroy(resamp); rtlsdr_close(dev); free (buffer); return 0; }
// frequency demodulator benchmark void benchmark_freqdem(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations) { // create demodulator float kf = 0.05f; // modulation index freqdem dem = freqdem_create(kf); float complex r[20]; // modulated signal float m[20]; // message signal unsigned long int i; // generate modulated signal for (i=0; i<20; i++) r[i] = 0.3f*cexpf(_Complex_I*2*M_PI*i/20.0f); // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { freqdem_demodulate(dem, r[ 0], &m[ 0]); freqdem_demodulate(dem, r[ 1], &m[ 1]); freqdem_demodulate(dem, r[ 2], &m[ 2]); freqdem_demodulate(dem, r[ 3], &m[ 3]); freqdem_demodulate(dem, r[ 4], &m[ 4]); freqdem_demodulate(dem, r[ 5], &m[ 5]); freqdem_demodulate(dem, r[ 6], &m[ 6]); freqdem_demodulate(dem, r[ 7], &m[ 7]); freqdem_demodulate(dem, r[ 8], &m[ 8]); freqdem_demodulate(dem, r[ 9], &m[ 9]); freqdem_demodulate(dem, r[10], &m[10]); freqdem_demodulate(dem, r[11], &m[11]); freqdem_demodulate(dem, r[12], &m[12]); freqdem_demodulate(dem, r[13], &m[13]); freqdem_demodulate(dem, r[14], &m[14]); freqdem_demodulate(dem, r[15], &m[15]); freqdem_demodulate(dem, r[16], &m[16]); freqdem_demodulate(dem, r[17], &m[17]); freqdem_demodulate(dem, r[18], &m[18]); freqdem_demodulate(dem, r[19], &m[19]); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 20; // destroy demodulator freqdem_destroy(dem); }