ModemKit *ModemFMStereo::buildKit(long long sampleRate, int audioSampleRate) { ModemKitFMStereo *kit = new ModemKitFMStereo; kit->audioResampleRatio = double(audioSampleRate) / double(sampleRate); kit->sampleRate = sampleRate; kit->audioSampleRate = audioSampleRate; float As = 60.0f; // stop-band attenuation [dB] kit->audioResampler = msresamp_rrrf_create(kit->audioResampleRatio, As); kit->stereoResampler = msresamp_rrrf_create(kit->audioResampleRatio, As); // Stereo filters / shifters double firStereoCutoff = 16000.0 / double(audioSampleRate); // filter transition float ft = 1000.0f / double(audioSampleRate); // fractional timing offset float mu = 0.0f; if (firStereoCutoff < 0) { firStereoCutoff = 0; } if (firStereoCutoff > 0.5) { firStereoCutoff = 0.5; } unsigned int h_len = estimate_req_filter_len(ft, As); float *h = new float[h_len]; liquid_firdes_kaiser(h_len, firStereoCutoff, As, mu, h); kit->firStereoLeft = firfilt_rrrf_create(h, h_len); kit->firStereoRight = firfilt_rrrf_create(h, h_len); // stereo pilot filter float bw = float(sampleRate); if (bw < 100000.0) { bw = 100000.0; } unsigned int order = 5; // filter order float f0 = ((float) 19000 / bw); float fc = ((float) 19500 / bw); float Ap = 1.0f; kit->iirStereoPilot = iirfilt_crcf_create_prototype(LIQUID_IIRDES_CHEBY2, LIQUID_IIRDES_BANDPASS, LIQUID_IIRDES_SOS, order, fc, f0, Ap, As); kit->firStereoR2C = firhilbf_create(5, 60.0f); kit->firStereoC2R = firhilbf_create(5, 60.0f); kit->stereoPilot = nco_crcf_create(LIQUID_VCO); nco_crcf_reset(kit->stereoPilot); nco_crcf_pll_set_bandwidth(kit->stereoPilot, 0.25f); return kit; }
void DemodulatorPreThread::initialize() { initialized = false; iqResampleRatio = (double) (params.bandwidth) / (double) params.sampleRate; audioResampleRatio = (double) (params.audioSampleRate) / (double) params.bandwidth; float As = 120.0f; // stop-band attenuation [dB] iqResampler = msresamp_crcf_create(iqResampleRatio, As); audioResampler = msresamp_rrrf_create(audioResampleRatio, As); stereoResampler = msresamp_rrrf_create(audioResampleRatio, As); // Stereo filters / shifters double firStereoCutoff = ((double) 16000 / (double) params.audioSampleRate); float ft = ((double) 1000 / (double) params.audioSampleRate); // filter transition float mu = 0.0f; // fractional timing offset if (firStereoCutoff < 0) { firStereoCutoff = 0; } if (firStereoCutoff > 0.5) { firStereoCutoff = 0.5; } unsigned int h_len = estimate_req_filter_len(ft, As); float *h = new float[h_len]; liquid_firdes_kaiser(h_len, firStereoCutoff, As, mu, h); firStereoLeft = firfilt_rrrf_create(h, h_len); firStereoRight = firfilt_rrrf_create(h, h_len); // stereo pilot filter float bw = params.bandwidth; if (bw < 100000.0) { bw = 100000.0; } unsigned int order = 5; // filter order float f0 = ((double) 19000 / bw); float fc = ((double) 19500 / bw); float Ap = 1.0f; As = 60.0f; iirStereoPilot = iirfilt_crcf_create_prototype(LIQUID_IIRDES_CHEBY2, LIQUID_IIRDES_BANDPASS, LIQUID_IIRDES_SOS, order, fc, f0, Ap, As); initialized = true; lastParams = params; }
// create gmskdem object // _k : samples/symbol // _m : filter delay (symbols) // _BT : excess bandwidth factor gmskdem gmskdem_create(unsigned int _k, unsigned int _m, float _BT) { if (_k < 2) { fprintf(stderr,"error: gmskdem_create(), samples/symbol must be at least 2\n"); exit(1); } else if (_m < 1) { fprintf(stderr,"error: gmskdem_create(), symbol delay must be at least 1\n"); exit(1); } else if (_BT <= 0.0f || _BT >= 1.0f) { fprintf(stderr,"error: gmskdem_create(), bandwidth/time product must be in (0,1)\n"); exit(1); } // allocate memory for main object gmskdem q = (gmskdem)malloc(sizeof(struct gmskdem_s)); // set properties q->k = _k; q->m = _m; q->BT = _BT; // allocate memory for filter taps q->h_len = 2*(q->k)*(q->m)+1; q->h = (float*) malloc(q->h_len * sizeof(float)); // compute filter coefficients liquid_firdes_gmskrx(q->k, q->m, q->BT, 0.0f, q->h); #if GMSKDEM_USE_EQUALIZER // receiver matched filter/equalizer q->eq = eqlms_rrrf_create_rnyquist(LIQUID_RNYQUIST_GMSKRX, q->k, q->m, q->BT, 0.0f); eqlms_rrrf_set_bw(q->eq, 0.01f); q->k_inv = 1.0f / (float)(q->k); #else // create filter object q->filter = firfilt_rrrf_create(q->h, q->h_len); #endif // reset modem state gmskdem_reset(q); #if DEBUG_GMSKDEM q->debug_mfout = windowf_create(DEBUG_BUFFER_LEN); #endif // return modem object return q; }
// // AUTOTEST : fir group delay, n=3 // void autotest_fir_groupdelay_n3() { // create coefficients array float h[3] = {0.1, 0.2, 0.4}; float tol = 1e-3f; unsigned int i; // create testing vectors float fc[4] = { 0.000, 0.125, 0.250, 0.375}; float g0[4] = { 1.42857142857143, 1.54756605839643, 2.15384615384615, 2.56861651421767}; // run tests float g; for (i=0; i<4; i++) { g = fir_group_delay(h, 3, fc[i]); CONTEND_DELTA( g, g0[i], tol ); } // create filter firfilt_rrrf filter = firfilt_rrrf_create(h,3); // run tests again for (i=0; i<4; i++) { g = firfilt_rrrf_groupdelay(filter, fc[i]); CONTEND_DELTA( g, g0[i], tol ); } // destroy filter firfilt_rrrf_destroy(filter); }
int main() { // options unsigned int h_len=17; // filter length float fc=0.2f; // filter cutoff float As=30.0f; // stop-band attenuation [dB] float mu=0.0f; // timing offset unsigned int n=64; // number of random input samples // derived values unsigned int num_samples = n + h_len; // arrays float x[num_samples]; // filter input float y[num_samples]; // filter output unsigned int i; float h[h_len]; liquid_firdes_kaiser(h_len,fc,As,mu,h); firfilt_rrrf f = firfilt_rrrf_create(h,h_len); firfilt_rrrf_print(f); for (i=0; i<num_samples; i++) { // generate noise x[i] = (i<n) ? randnf()/sqrtf(n/2) : 0.0f; firfilt_rrrf_push(f, x[i]); firfilt_rrrf_execute(f, &y[i]); printf("x[%4u] = %12.8f, y[%4u] = %12.8f;\n", i, x[i], i, y[i]); } // destroy filter object firfilt_rrrf_destroy(f); // // export results // FILE*fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% firfilt_rrrf_example.m: auto-generated file\n\n"); fprintf(fid,"clear all;\nclose all;\n\n"); fprintf(fid,"h_len=%u;\nn=%u;\n", h_len, n); for (i=0; i<h_len; i++) fprintf(fid,"h(%4u) = %12.4e;\n", i+1, h[i]); for (i=0; i<num_samples; i++) fprintf(fid,"x(%4u) = %12.4e; y(%4u) = %12.4e;\n", i+1, x[i], i+1, y[i]); fprintf(fid,"nfft=512;\n"); fprintf(fid,"H=20*log10(abs(fftshift(fft(h,nfft))));\n"); fprintf(fid,"X=20*log10(abs(fftshift(fft(x,nfft))));\n"); fprintf(fid,"Y=20*log10(abs(fftshift(fft(y,nfft))));\n"); fprintf(fid,"f=[0:(nfft-1)]/nfft-0.5;\n"); fprintf(fid,"figure;\n"); fprintf(fid,"plot(f,X,'Color',[0.3 0.3 0.3],...\n"); fprintf(fid," f,Y,'LineWidth',2,...\n"); fprintf(fid," f,H,'-b','LineWidth',2);\n"); fprintf(fid,"axis([-0.5 0.5 -80 40]);\n"); fprintf(fid,"grid on;\nxlabel('normalized frequency');\nylabel('PSD [dB]');\n"); fprintf(fid,"legend('noise','filtered noise','filter prototype',1);"); fclose(fid); printf("results written to %s\n", OUTPUT_FILENAME); printf("done.\n"); return 0; }
int main(int argc, char*argv[]) { // options unsigned int h_len=19; // filter length unsigned int p=5; // polynomial order float fc=0.45f; // filter cutoff float As=60.0f; // stop-band attenuation [dB] float mu=0.1f; // fractional sample delay unsigned int num_samples=60; // number of samples to evaluate int verbose = 0; // verbose output? int dopt; while ((dopt = getopt(argc,argv,"hvt:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'v': verbose = 1; break; case 't': mu = atof(optarg); break; default: exit(1); } } // data arrays float x[num_samples]; // input data array float y[num_samples]; // output data array // create and initialize Farrow filter object firfarrow_rrrf f = firfarrow_rrrf_create(h_len, p, fc, As); firfarrow_rrrf_set_delay(f, mu); unsigned int i; // generate input (filtered noise) float hx[21]; liquid_firdes_kaiser(15, 0.1, 60, 0, hx); firfilt_rrrf fx = firfilt_rrrf_create(hx, 15); for (i=0; i<num_samples; i++) { firfilt_rrrf_push(fx, i < 40 ? randnf() : 0.0f); firfilt_rrrf_execute(fx, &x[i]); } firfilt_rrrf_destroy(fx); // push input through filter for (i=0; i<num_samples; i++) { firfarrow_rrrf_push(f, x[i]); firfarrow_rrrf_execute(f, &y[i]); } // destroy Farrow filter object firfarrow_rrrf_destroy(f); 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,"h_len = %u;\n", h_len); fprintf(fid,"mu = %f;\n", mu); fprintf(fid,"num_samples = %u;\n", num_samples); for (i=0; i<num_samples; i++) { fprintf(fid,"x(%4u) = %12.4e; y(%4u) = %12.4e;\n", i+1, x[i], i+1, y[i]); } // plot the results fprintf(fid,"\n\n"); fprintf(fid,"figure;\n"); fprintf(fid,"tx = 0:(num_samples-1); %% input time scale\n"); fprintf(fid,"ty = tx - (h_len-1)/2 + mu; %% output time scale\n"); fprintf(fid,"plot(tx, x,'-s','MarkerSize',3, ...\n"); fprintf(fid," ty, y,'-s','MarkerSize',3);\n"); fprintf(fid,"legend('input','output',0);\n"); fclose(fid); printf("results written to %s\n", OUTPUT_FILENAME); printf("done.\n"); return 0; }
int main() { // spectral periodogram options unsigned int nfft = 1024; // spectral periodogram FFT size unsigned int num_samples = 4000; // number of samples float beta = 10.0f; // Kaiser-Bessel window parameter float noise_floor = -60.0f; // noise floor [dB] float alpha = 0.1f; // PSD estimate bandwidth unsigned int i; // derived values float nstd = powf(10.0f, noise_floor/20.0f); // create spectral periodogram unsigned int window_size = nfft/2; // spgramf window size spgramf q = spgramf_create_kaiser(nfft, window_size, beta); // generate signal (filter with frequency offset) unsigned int h_len = 91; // filter length float fc = 0.07f; // filter cut-off frequency float f0 = 0.20f; // filter center frequency float As = 60.0f; // filter stop-band attenuation float h[h_len]; // filter coefficients liquid_firdes_kaiser(h_len, fc, As, 0, h); // add frequency offset for (i=0; i<h_len; i++) h[i] *= cosf(2*M_PI*f0*i); firfilt_rrrf filter = firfilt_rrrf_create(h, h_len); firfilt_rrrf_set_scale(filter, 2.0f*fc); for (i=0; i<num_samples; i++) { // generate random sample float x = randnf(); // filter float y = 0; firfilt_rrrf_push(filter, x); firfilt_rrrf_execute(filter, &y); // add noise y += nstd * randnf(); // push resulting sample through periodogram spgramf_accumulate_psd(q, &y, alpha, 1); } // compute power spectral density output float psd[nfft]; spgramf_write_accumulation(q, psd); // destroy objects firfilt_rrrf_destroy(filter); spgramf_destroy(q); // // export output file // FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n\n"); fprintf(fid,"nfft = %u;\n", nfft); fprintf(fid,"f = [0:(nfft-1)]/nfft - 0.5;\n"); fprintf(fid,"H = zeros(1,nfft);\n"); fprintf(fid,"noise_floor = %12.6f;\n", noise_floor); for (i=0; i<nfft; i++) fprintf(fid,"H(%6u) = %12.4e;\n", i+1, psd[i]); fprintf(fid,"figure;\n"); fprintf(fid,"plot(f, H, '-', 'LineWidth',1.5);\n"); fprintf(fid,"xlabel('Normalized Frequency [f/F_s]');\n"); fprintf(fid,"ylabel('Power Spectral Density [dB]');\n"); fprintf(fid,"grid on;\n"); fprintf(fid,"ymin = 10*floor([noise_floor-20]/10);\n"); fprintf(fid,"ymax = 10*floor([noise_floor+80]/10);\n"); fprintf(fid,"axis([-0.5 0.5 ymin ymax]);\n"); fclose(fid); printf("results written to %s.\n", OUTPUT_FILENAME); printf("done.\n"); return 0; }
void DemodulatorWorkerThread::threadMain() { std::cout << "Demodulator worker thread started.." << std::endl; while (!terminated) { bool filterChanged = false; DemodulatorWorkerThreadCommand filterCommand; DemodulatorWorkerThreadCommand command; bool done = false; while (!done) { commandQueue->pop(command); switch (command.cmd) { case DemodulatorWorkerThreadCommand::DEMOD_WORKER_THREAD_CMD_BUILD_FILTERS: filterChanged = true; filterCommand = command; break; default: break; } done = commandQueue->empty(); } if (filterChanged && !terminated) { DemodulatorWorkerThreadResult result(DemodulatorWorkerThreadResult::DEMOD_WORKER_THREAD_RESULT_FILTERS); float As = 60.0f; // stop-band attenuation [dB] if (filterCommand.sampleRate && filterCommand.bandwidth) { result.iqResampleRatio = (double) (filterCommand.bandwidth) / (double) filterCommand.sampleRate; result.iqResampler = msresamp_crcf_create(result.iqResampleRatio, As); } if (filterCommand.bandwidth && filterCommand.audioSampleRate) { result.audioResamplerRatio = (double) (filterCommand.audioSampleRate) / (double) filterCommand.bandwidth; result.audioResampler = msresamp_rrrf_create(result.audioResamplerRatio, As); result.stereoResampler = msresamp_rrrf_create(result.audioResamplerRatio, As); result.audioSampleRate = filterCommand.audioSampleRate; // Stereo filters / shifters double firStereoCutoff = ((double) 16000 / (double) filterCommand.audioSampleRate); float ft = ((double) 1000 / (double) filterCommand.audioSampleRate); // filter transition float mu = 0.0f; // fractional timing offset if (firStereoCutoff < 0) { firStereoCutoff = 0; } if (firStereoCutoff > 0.5) { firStereoCutoff = 0.5; } unsigned int h_len = estimate_req_filter_len(ft, As); float *h = new float[h_len]; liquid_firdes_kaiser(h_len, firStereoCutoff, As, mu, h); result.firStereoLeft = firfilt_rrrf_create(h, h_len); result.firStereoRight = firfilt_rrrf_create(h, h_len); float bw = filterCommand.bandwidth; if (bw < 100000.0) { bw = 100000.0; } // stereo pilot filter unsigned int order = 5; // filter order float f0 = ((double) 19000 / bw); float fc = ((double) 19500 / bw); float Ap = 1.0f; As = 60.0f; result.iirStereoPilot = iirfilt_crcf_create_prototype(LIQUID_IIRDES_CHEBY2, LIQUID_IIRDES_BANDPASS, LIQUID_IIRDES_SOS, order, fc, f0, Ap, As); } if (filterCommand.bandwidth) { result.bandwidth = filterCommand.bandwidth; } if (filterCommand.sampleRate) { result.sampleRate = filterCommand.sampleRate; } resultQueue->push(result); } } std::cout << "Demodulator worker thread done." << std::endl; }