// // test phase-locked loop // _type : NCO type (e.g. LIQUID_NCO) // _phase_offset : initial phase offset // _freq_offset : initial frequency offset // _pll_bandwidth : bandwidth of phase-locked loop // _num_iterations : number of iterations to run // _tol : error tolerance void nco_crcf_pll_test(int _type, float _phase_offset, float _freq_offset, float _pll_bandwidth, unsigned int _num_iterations, float _tol) { // objects nco_crcf nco_tx = nco_crcf_create(_type); nco_crcf nco_rx = nco_crcf_create(_type); // initialize objects nco_crcf_set_phase(nco_tx, _phase_offset); nco_crcf_set_frequency(nco_tx, _freq_offset); nco_crcf_pll_set_bandwidth(nco_rx, _pll_bandwidth); // run loop unsigned int i; float phase_error; float complex r, v; for (i=0; i<_num_iterations; i++) { // received complex signal nco_crcf_cexpf(nco_tx,&r); nco_crcf_cexpf(nco_rx,&v); // error estimation phase_error = cargf(r*conjf(v)); // update pll nco_crcf_pll_step(nco_rx, phase_error); // update nco objects nco_crcf_step(nco_tx); nco_crcf_step(nco_rx); } // ensure phase of oscillators is locked float nco_tx_phase = nco_crcf_get_phase(nco_tx); float nco_rx_phase = nco_crcf_get_phase(nco_rx); CONTEND_DELTA(nco_tx_phase, nco_rx_phase, _tol); // ensure frequency of oscillators is locked float nco_tx_freq = nco_crcf_get_frequency(nco_tx); float nco_rx_freq = nco_crcf_get_frequency(nco_rx); CONTEND_DELTA(nco_tx_freq, nco_rx_freq, _tol); // clean it up nco_crcf_destroy(nco_tx); nco_crcf_destroy(nco_rx); }
// modulate sample // _q : frequency modulator object // _s : input symbol // _y : output sample array [size: _k x 1] void fskmod_modulate(fskmod _q, unsigned int _s, float complex * _y) { // validate input if (_s >= _q->M) { fprintf(stderr,"warning: fskmod_modulate(), input symbol (%u) exceeds maximum (%u)\n", _s, _q->M); _s = 0; } // compute appropriate frequency float dphi = ((float)_s - _q->M2) * 2 * M_PI * _q->bandwidth / _q->M2; // set frequency appropriately nco_crcf_set_frequency(_q->oscillator, dphi); // generate output tone unsigned int i; for (i=0; i<_q->k; i++) { // compute complex output nco_crcf_cexpf(_q->oscillator, &_y[i]); // step oscillator nco_crcf_step(_q->oscillator); } }
int main() { // options unsigned int num_channels=8; // number of channels unsigned int m=2; // filter delay float As=-60; // stop-band attenuation unsigned int num_frames=25; // number of frames // create objects firpfbch_crcf c = firpfbch_crcf_create_kaiser(LIQUID_ANALYZER, num_channels, m, As); //firpfbch_crcf_print(c); 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_frames=%u;\n", num_frames); fprintf(fid,"x = zeros(1,%u);\n", num_channels * num_frames); fprintf(fid,"y = zeros(%u,%u);\n", num_channels, num_frames); unsigned int i, j, n=0; float complex x[num_channels]; // time-domain input float complex y[num_channels]; // channelized output // create nco: sweeps entire range of frequencies over the evaluation interval nco_crcf nco_tx = nco_crcf_create(LIQUID_VCO); nco_crcf_set_frequency(nco_tx, 0.0f); float df = 2*M_PI/(num_channels*num_frames); printf("fr/ch:"); for (j=0; j<num_channels; j++) printf("%3u",j); printf("\n"); for (i=0; i<num_frames; i++) { // generate frame of data for (j=0; j<num_channels; j++) { nco_crcf_cexpf(nco_tx, &x[j]); nco_crcf_adjust_frequency(nco_tx, df); nco_crcf_step(nco_tx); } // execute analysis filter bank firpfbch_crcf_analyzer_execute(c, x, y); printf("%4u : ", i); for (j=0; j<num_channels; j++) { if (cabsf(y[j]) > num_channels / 4) printf(" x "); else printf(" . "); } printf("\n"); // write output to file for (j=0; j<num_channels; j++) { // frequency data fprintf(fid,"y(%4u,%4u) = %12.4e + j*%12.4e;\n", j+1, i+1, crealf(y[j]), cimagf(y[j])); // time data fprintf(fid,"x(%4u) = %12.4e + j*%12.4e;\n", n+1, crealf(x[j]), cimag(x[j])); n++; } } // destroy objects nco_crcf_destroy(nco_tx); firpfbch_crcf_destroy(c); // plot results fprintf(fid,"\n\n"); fprintf(fid,"figure;\n"); fprintf(fid,"subplot(2,1,1);\n"); fprintf(fid," plot(1:length(x),real(x),1:length(x),imag(x));\n"); fprintf(fid," xlabel('time');\n"); fprintf(fid," ylabel('signal');\n"); fprintf(fid,"subplot(2,1,2);\n"); fprintf(fid," plot(20*log10(abs(y.')/num_channels));\n"); fprintf(fid," xlabel('time (decimated)');\n"); fprintf(fid," ylabel('channelized energy [dB]');\n"); fprintf(fid,"n=min(num_channels,8);\n"); fprintf(fid,"figure;\n"); fprintf(fid,"for i=1:n\n"); fprintf(fid," subplot(n,1,i);\n"); fprintf(fid," plot(1:num_frames,real(y(i,:)),1:num_frames,imag(y(i,:)));\n"); fprintf(fid," axis off;\n"); fprintf(fid," ylabel(num2str(i));\n"); fprintf(fid,"end;\n"); fclose(fid); printf("results written to %s\n", OUTPUT_FILENAME); printf("done.\n"); return 0; }
int main() { // spectral periodogram options unsigned int nfft=256; // spectral periodogram FFT size unsigned int num_samples = 2001; // number of samples float beta = 10.0f; // Kaiser-Bessel window parameter // allocate memory for data arrays float complex x[num_samples]; // input signal float complex X[nfft]; // output spectrum float psd[nfft]; // power spectral density unsigned int ramp = num_samples/20 < 10 ? 10 : num_samples/20; // create spectral periodogram unsigned int window_size = nfft/2; // spgram window size unsigned int delay = nfft/8; // samples between transforms spgram q = spgram_create_kaiser(nfft, window_size, beta); unsigned int i; // generate signal nco_crcf nco = nco_crcf_create(LIQUID_VCO); for (i=0; i<num_samples; i++) { nco_crcf_set_frequency(nco, 0.1f*(1.2f+sinf(0.007f*i)) ); nco_crcf_cexpf(nco, &x[i]); nco_crcf_step(nco); } nco_crcf_destroy(nco); // add soft ramping functions for (i=0; i<ramp; i++) { x[i] *= 0.5f - 0.5f*cosf(M_PI*(float)i / (float)ramp); x[num_samples-ramp+i-1] *= 0.5f - 0.5f*cosf(M_PI*(float)(ramp-i-1) / (float)ramp); } // // export output file(s) // FILE * fid; // // export time-doman data // fid = fopen(OUTPUT_FILENAME_TIME,"w"); fprintf(fid,"# %s : auto-generated file\n", OUTPUT_FILENAME_TIME); for (i=0; i<num_samples; i++) fprintf(fid,"%12u %12.8f %12.8f\n", i, crealf(x[i]), cimagf(x[i])); fclose(fid); printf("results written to %s.\n", OUTPUT_FILENAME_TIME); // // export freq-doman data // fid = fopen(OUTPUT_FILENAME_FREQ,"w"); fprintf(fid,"# %s : auto-generated file\n", OUTPUT_FILENAME_FREQ); unsigned int t=0; for (i=0; i<num_samples; i++) { // push sample into periodogram spgram_push(q, &x[i], 1); if ( ((i+1)%delay)==0 ) { // compute spectral periodogram output spgram_execute(q, X); unsigned int k; // compute PSD and FFT shift for (k=0; k<nfft; k++) psd[k] = 20*log10f( cabsf(X[(k+nfft/2)%nfft]) ); #if 1 for (k=0; k<nfft; k++) fprintf(fid,"%12u %12.8f %12.8f\n", t, (float)k/(float)nfft - 0.5f, psd[k]); #else for (k=0; k<nfft; k++) fprintf(fid,"%12.8f ", psd[k]); #endif fprintf(fid,"\n"); t++; } } // destroy spectral periodogram object spgram_destroy(q); fclose(fid); printf("results written to %s.\n", OUTPUT_FILENAME_FREQ); printf("done.\n"); return 0; }
void ModemFMStereo::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInput *audioOut) { ModemKitFMStereo *fmkit = (ModemKitFMStereo *)kit; size_t bufSize = input->data.size(); liquid_float_complex u, v, w, x, y; double audio_resample_ratio = fmkit->audioResampleRatio; if (demodOutputData.size() != bufSize) { if (demodOutputData.capacity() < bufSize) { demodOutputData.reserve(bufSize); } demodOutputData.resize(bufSize); } size_t audio_out_size = (size_t)ceil((double) (bufSize) * audio_resample_ratio) + 512; freqdem_demodulate_block(demodFM, &input->data[0], bufSize, &demodOutputData[0]); if (resampledOutputData.size() != audio_out_size) { if (resampledOutputData.capacity() < audio_out_size) { resampledOutputData.reserve(audio_out_size); } resampledOutputData.resize(audio_out_size); } unsigned int numAudioWritten; msresamp_rrrf_execute(fmkit->audioResampler, &demodOutputData[0], bufSize, &resampledOutputData[0], &numAudioWritten); if (demodStereoData.size() != bufSize) { if (demodStereoData.capacity() < bufSize) { demodStereoData.reserve(bufSize); } demodStereoData.resize(bufSize); } float phase_error = 0; for (size_t i = 0; i < bufSize; i++) { // real -> complex firhilbf_r2c_execute(fmkit->firStereoR2C, demodOutputData[i], &x); // 19khz pilot band-pass iirfilt_crcf_execute(fmkit->iirStereoPilot, x, &v); nco_crcf_cexpf(fmkit->stereoPilot, &w); w.imag = -w.imag; // conjf(w) // multiply u = v * conjf(w) u.real = v.real * w.real - v.imag * w.imag; u.imag = v.real * w.imag + v.imag * w.real; // cargf(u) phase_error = atan2f(u.imag,u.real); // step pll nco_crcf_pll_step(fmkit->stereoPilot, phase_error); nco_crcf_step(fmkit->stereoPilot); // 38khz down-mix nco_crcf_mix_down(fmkit->stereoPilot, x, &y); nco_crcf_mix_down(fmkit->stereoPilot, y, &x); // complex -> real firhilbf_c2r_execute(fmkit->firStereoC2R, x, &demodStereoData[i]); } // std::cout << "[PLL] phase error: " << phase_error; // std::cout << " freq:" << (((nco_crcf_get_frequency(stereoPilot) / (2.0 * M_PI)) * inp->sampleRate)) << std::endl; if (audio_out_size != resampledStereoData.size()) { if (resampledStereoData.capacity() < audio_out_size) { resampledStereoData.reserve(audio_out_size); } resampledStereoData.resize(audio_out_size); } msresamp_rrrf_execute(fmkit->stereoResampler, &demodStereoData[0], bufSize, &resampledStereoData[0], &numAudioWritten); audioOut->channels = 2; if (audioOut->data.capacity() < (numAudioWritten * 2)) { audioOut->data.reserve(numAudioWritten * 2); } audioOut->data.resize(numAudioWritten * 2); for (size_t i = 0; i < numAudioWritten; i++) { float l, r; float ld, rd; if (fmkit->demph) { iirfilt_rrrf_execute(fmkit->iirDemphL, 0.568f * (resampledOutputData[i] - (resampledStereoData[i])), &ld); iirfilt_rrrf_execute(fmkit->iirDemphR, 0.568f * (resampledOutputData[i] + (resampledStereoData[i])), &rd); firfilt_rrrf_push(fmkit->firStereoLeft, ld); firfilt_rrrf_execute(fmkit->firStereoLeft, &l); firfilt_rrrf_push(fmkit->firStereoRight, rd); firfilt_rrrf_execute(fmkit->firStereoRight, &r); } else { firfilt_rrrf_push(fmkit->firStereoLeft, 0.568f * (resampledOutputData[i] - (resampledStereoData[i]))); firfilt_rrrf_execute(fmkit->firStereoLeft, &l); firfilt_rrrf_push(fmkit->firStereoRight, 0.568f * (resampledOutputData[i] + (resampledStereoData[i]))); firfilt_rrrf_execute(fmkit->firStereoRight, &r); } audioOut->data[i * 2] = l; audioOut->data[i * 2 + 1] = r; } }
int main(int argc, char*argv[]) { // set random seed srand( time(NULL) ); // parameters float phase_offset = 0.0f; // initial phase offset float frequency_offset = 0.40f; // initial frequency offset float pll_bandwidth = 0.003f; // phase-locked loop bandwidth unsigned int n = 512; // number of iterations int dopt; while ((dopt = getopt(argc,argv,"uhb:n:p:f:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 'b': pll_bandwidth = atof(optarg); break; case 'n': n = atoi(optarg); break; case 'p': phase_offset = atof(optarg); break; case 'f': frequency_offset= atof(optarg); break; default: exit(1); } } // objects nco_crcf nco_tx = nco_crcf_create(LIQUID_VCO); nco_crcf nco_rx = nco_crcf_create(LIQUID_VCO); // initialize objects nco_crcf_set_phase(nco_tx, phase_offset); nco_crcf_set_frequency(nco_tx, frequency_offset); nco_crcf_pll_set_bandwidth(nco_rx, pll_bandwidth); // generate input float complex x[n]; float complex y[n]; float phase_error[n]; unsigned int i; for (i=0; i<n; i++) { // generate complex sinusoid nco_crcf_cexpf(nco_tx, &x[i]); // update nco nco_crcf_step(nco_tx); } // run loop for (i=0; i<n; i++) { #if 0 // test resetting bandwidth in middle of acquisition if (i == 100) nco_pll_set_bandwidth(nco_rx, pll_bandwidth*0.2f); #endif // generate input nco_crcf_cexpf(nco_rx, &y[i]); // update rx nco object nco_crcf_step(nco_rx); // compute phase error phase_error[i] = cargf(x[i]*conjf(y[i])); // update pll nco_crcf_pll_step(nco_rx, phase_error[i]); // print phase error if ( (i+1)%50 == 0 || i==n-1 || i==0) printf("%4u : phase error = %12.8f\n", i+1, phase_error[i]); } nco_crcf_destroy(nco_tx); nco_crcf_destroy(nco_rx); // write 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"); fprintf(fid,"n = %u;\n", n); fprintf(fid,"x = zeros(1,n);\n"); fprintf(fid,"y = zeros(1,n);\n"); for (i=0; i<n; i++) { fprintf(fid,"x(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(x[i]), cimagf(x[i])); fprintf(fid,"y(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(y[i]), cimagf(y[i])); fprintf(fid,"e(%4u) = %12.4e;\n", i+1, phase_error[i]); } fprintf(fid,"t=0:(n-1);\n"); fprintf(fid,"figure;\n"); fprintf(fid,"subplot(3,1,1);\n"); fprintf(fid," hold on;\n"); fprintf(fid," plot(t,real(x),'Color',[1 1 1]*0.8);\n"); fprintf(fid," plot(t,real(y),'Color',[0 0.2 0.5]);\n"); fprintf(fid," hold off;\n"); fprintf(fid," xlabel('time');\n"); fprintf(fid," ylabel('real');\n"); fprintf(fid," axis([0 n -1.2 1.2]);\n"); fprintf(fid," grid on;\n"); fprintf(fid,"subplot(3,1,2);\n"); fprintf(fid," hold on;\n"); fprintf(fid," plot(t,imag(x),'Color',[1 1 1]*0.8);\n"); fprintf(fid," plot(t,imag(y),'Color',[0 0.5 0.2]);\n"); fprintf(fid," hold off;\n"); fprintf(fid," xlabel('time');\n"); fprintf(fid," ylabel('imag');\n"); fprintf(fid," axis([0 n -1.2 1.2]);\n"); fprintf(fid," grid on;\n"); fprintf(fid,"subplot(3,1,3);\n"); fprintf(fid," plot(t,e,'Color',[0.5 0 0]);\n"); fprintf(fid," xlabel('time');\n"); fprintf(fid," ylabel('phase error');\n"); fprintf(fid," axis([0 n -pi pi]);\n"); fprintf(fid," grid on;\n"); fclose(fid); printf("results written to %s.\n",OUTPUT_FILENAME); printf("done.\n"); return 0; }
int main() { unsigned int h_len=20; // filter length float beta = 0.3f; // stop-band attenuation unsigned int num_samples=64; // number of samples // derived values unsigned int n = num_samples + h_len; // extend length of analysis to // incorporate filter delay // create filterbank qmfb_crcf q = qmfb_crcf_create(h_len, beta, LIQUID_QMFB_ANALYZER); qmfb_crcf_print(q); FILE*fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\nclose all;\n\n"); fprintf(fid,"n=%u;\n", n); fprintf(fid,"x = zeros(1,%u);\n", 2*n); fprintf(fid,"y = zeros(2,%u);\n", n); unsigned int i; float complex x[2*n], y[2][n]; // generate time-domain signal (windowed sinusoidal pulses) nco_crcf nco_0 = nco_crcf_create(LIQUID_VCO); nco_crcf nco_1 = nco_crcf_create(LIQUID_VCO); nco_crcf_set_frequency(nco_0, 0.122*M_PI); nco_crcf_set_frequency(nco_1, 0.779*M_PI); float complex x0,x1; for (i=0; i<2*num_samples; i++) { nco_crcf_cexpf(nco_0, &x0); nco_crcf_cexpf(nco_1, &x1); x[i] = (x0 + x1) * kaiser(i,2*num_samples,10.0f,0.0f); nco_crcf_step(nco_0); nco_crcf_step(nco_1); } // pad end with zeros for (i=2*num_samples; i<2*n; i++) x[i] = 0.0f; // compute QMF sub-channel output for (i=0; i<n; i++) { qmfb_crcf_execute(q, x[2*i+0], x[2*i+1], y[0]+i, y[1]+i); } // write results to output file for (i=0; i<n; i++) { fprintf(fid,"x(%3u) = %8.4f + j*%8.4f;\n", 2*i+1, crealf(x[2*i+0]), cimagf(x[2*i+0])); fprintf(fid,"x(%3u) = %8.4f + j*%8.4f;\n", 2*i+2, crealf(x[2*i+1]), cimagf(x[2*i+1])); fprintf(fid,"y(1,%3u) = %8.4f + j*%8.4f;\n", i+1, crealf(y[0][i]), cimagf(y[0][i])); fprintf(fid,"y(2,%3u) = %8.4f + j*%8.4f;\n", i+1, crealf(y[1][i]), cimagf(y[1][i])); } // plot time-domain results fprintf(fid,"t0=0:(2*n-1);\n"); fprintf(fid,"t1=0:(n-1);\n"); fprintf(fid,"figure;\n"); fprintf(fid,"subplot(3,1,1); plot(t0,real(x),t0,imag(x)); ylabel('x(t)');\n"); fprintf(fid,"subplot(3,1,2); plot(t1,real(y(1,:)),t1,imag(y(1,:))); ylabel('y_0(t)');\n"); fprintf(fid,"subplot(3,1,3); plot(t1,real(y(2,:)),t1,imag(y(2,:))); ylabel('y_1(t)');\n"); // plot freq-domain results fprintf(fid,"nfft=512; %% must be even number\n"); fprintf(fid,"X=20*log10(abs(fftshift(fft(x/n,nfft))));\n"); fprintf(fid,"Y0=20*log10(abs(fftshift(fft(y(1,:)/n,nfft))));\n"); fprintf(fid,"Y1=20*log10(abs(fftshift(fft(y(2,:)/n,nfft))));\n"); // Y1 needs to be split into two regions fprintf(fid,"f=[0:(nfft-1)]/nfft - 0.5;\n"); fprintf(fid,"t0 = [1]:[nfft/2];\n"); fprintf(fid,"t1 = [nfft/2+1]:[nfft];\n"); fprintf(fid,"figure;\n"); fprintf(fid,"hold on;\n"); fprintf(fid," plot(f,X,'Color',[0.5 0.5 0.5]);\n"); fprintf(fid," plot(f/2,Y0,'LineWidth',2,'Color',[0 0.5 0]);\n"); fprintf(fid," plot(f(t0)/2+0.5,Y1(t0),'LineWidth',2,'Color',[0.5 0 0]);\n"); fprintf(fid," plot(f(t1)/2-0.5,Y1(t1),'LineWidth',2,'Color',[0.5 0 0]);\n"); fprintf(fid,"hold off;\n"); fprintf(fid,"grid on;\nxlabel('normalized frequency');\nylabel('PSD [dB]');\n"); fprintf(fid,"legend('original','Y_0','Y_1',1);"); fprintf(fid,"axis([-0.5 0.5 -140 20]);\n"); fclose(fid); printf("results written to %s\n", OUTPUT_FILENAME); qmfb_crcf_destroy(q); nco_crcf_destroy(nco_0); nco_crcf_destroy(nco_1); printf("done.\n"); return 0; }