// // AUTOTEST: check RMSE for CVSD // void autotest_cvsd_rmse_sine() { unsigned int n=256; unsigned int nbits=3; float zeta=1.5f; float alpha=0.90f; // create cvsd codecs cvsd cvsd_encoder = cvsd_create(nbits,zeta,alpha); cvsd cvsd_decoder = cvsd_create(nbits,zeta,alpha); float phi=0.0f; float dphi=0.1f; unsigned int i; unsigned char b; float x,y; float rmse=0.0f; for (i=0; i<n; i++) { x = 0.5f*sinf(phi); b = cvsd_encode(cvsd_encoder, x); y = cvsd_decode(cvsd_decoder, b); rmse += (x-y)*(x-y); phi += dphi; } rmse = 10*log10f(rmse/n); if (liquid_autotest_verbose) printf("cvsd rmse : %8.2f dB\n", rmse); CONTEND_LESS_THAN(rmse, -20.0f); // destroy cvsd codecs cvsd_destroy(cvsd_encoder); cvsd_destroy(cvsd_decoder); }
// // AUTOTEST: Gamma // void autotest_gamma() { // error tolerance float tol = 1e-5f; // test vectors float v[12][2] = { {0.0001f, 9999.42288323161f }, {0.001f, 999.423772484595f }, {0.01f, 99.4325851191505f }, {0.1f, 9.51350769866873f }, {0.2f, 4.59084371199880f }, {0.5f, 1.77245385090552f }, {1.5f, 0.886226925452758f }, {2.5f, 1.329340388179140f }, {3.2f, 2.42396547993537f }, {4.1f, 6.81262286301667f }, {5.3f, 38.0779764499523f }, {12.0f, 39916800.0000000f }}; unsigned int i; for (i=0; i<12; i++) { // extract test vector float z = v[i][0]; float g = v[i][1]; // compute gamma float gamma = liquid_gammaf(z); // compute relative error float error = fabsf(gamma-g) / fabsf(g); // print results if (liquid_autotest_verbose) printf(" gamma(%12.4e) = %12.4e (expected %12.4e) %12.4e\n", z, gamma, g, error); // run test CONTEND_LESS_THAN(error, tol); } }
// // AUTOTEST : test multi-stage arbitrary resampler // void autotest_msresamp_crcf() { // options unsigned int m = 13; // filter semi-length (filter delay) float r=0.127115323f; // resampling rate (output/input) float As=60.0f; // resampling filter stop-band attenuation [dB] unsigned int n=1200; // number of input samples float fx=0.0254230646f; // complex input sinusoid frequency (0.2*r) //float bw=0.45f; // resampling filter bandwidth //unsigned int npfb=64; // number of filters in bank (timing resolution) unsigned int i; // number of input samples (zero-padded) unsigned int nx = n + m; // output buffer with extra padding for good measure unsigned int y_len = (unsigned int) ceilf(1.1 * nx * r) + 4; // arrays float complex x[nx]; float complex y[y_len]; // create resampler msresamp_crcf q = msresamp_crcf_create(r,As); // generate input signal float wsum = 0.0f; for (i=0; i<nx; i++) { // compute window float w = i < n ? kaiser(i, n, 10.0f, 0.0f) : 0.0f; // apply window to complex sinusoid x[i] = cexpf(_Complex_I*2*M_PI*fx*i) * w; // accumulate window wsum += w; } // resample unsigned int ny=0; unsigned int nw; for (i=0; i<nx; i++) { // execute resampler, storing in output buffer msresamp_crcf_execute(q, &x[i], 1, &y[ny], &nw); // increment output size ny += nw; } // clean up allocated objects msresamp_crcf_destroy(q); // // analyze resulting signal // // check that the actual resampling rate is close to the target float r_actual = (float)ny / (float)nx; float fy = fx / r; // expected output frequency // run FFT and ensure that carrier has moved and that image // frequencies and distortion have been adequately suppressed unsigned int nfft = 1 << liquid_nextpow2(ny); float complex yfft[nfft]; // fft input float complex Yfft[nfft]; // fft output for (i=0; i<nfft; i++) yfft[i] = i < ny ? y[i] : 0.0f; fft_run(nfft, yfft, Yfft, LIQUID_FFT_FORWARD, 0); fft_shift(Yfft, nfft); // run FFT shift // find peak frequency float Ypeak = 0.0f; float fpeak = 0.0f; float max_sidelobe = -1e9f; // maximum side-lobe [dB] float main_lobe_width = 0.07f; // TODO: figure this out from Kaiser's equations for (i=0; i<nfft; i++) { // normalized output frequency float f = (float)i/(float)nfft - 0.5f; // scale FFT output appropriately Yfft[i] /= (r * wsum); float Ymag = 20*log10f( cabsf(Yfft[i]) ); // find frequency location of maximum magnitude if (Ymag > Ypeak || i==0) { Ypeak = Ymag; fpeak = f; } // find peak side-lobe value, ignoring frequencies // within a certain range of signal frequency if ( fabsf(f-fy) > main_lobe_width ) max_sidelobe = Ymag > max_sidelobe ? Ymag : max_sidelobe; } if (liquid_autotest_verbose) { // print results printf(" desired resampling rate : %12.8f\n", r); printf(" measured resampling rate : %12.8f (%u/%u)\n", r_actual, ny, nx); printf(" peak spectrum : %12.8f dB (expected 0.0 dB)\n", Ypeak); printf(" peak frequency : %12.8f (expected %-12.8f)\n", fpeak, fy); printf(" max sidelobe : %12.8f dB (expected at least %.2f dB)\n", max_sidelobe, -As); } CONTEND_DELTA( r_actual, r, 0.01f ); // check actual output sample rate CONTEND_DELTA( Ypeak, 0.0f, 0.25f ); // peak should be about 0 dB CONTEND_DELTA( fpeak, fy, 0.01f ); // peak frequency should be nearly 0.2 CONTEND_LESS_THAN( max_sidelobe, -As ); // maximum side-lobe should be sufficiently low #if 0 // export results for debugging char filename[] = "msresamp_crcf_autotest.m"; FILE*fid = fopen(filename,"w"); fprintf(fid,"%% %s: auto-generated file\n",filename); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n"); fprintf(fid,"r = %12.8f;\n", r); fprintf(fid,"nx = %u;\n", nx); fprintf(fid,"ny = %u;\n", ny); fprintf(fid,"nfft = %u;\n", nfft); fprintf(fid,"Y = zeros(1,nfft);\n"); for (i=0; i<nfft; i++) fprintf(fid,"Y(%3u) = %12.4e + j*%12.4e;\n", i+1, crealf(Yfft[i]), cimagf(Yfft[i])); fprintf(fid,"\n\n"); fprintf(fid,"%% plot frequency-domain result\n"); fprintf(fid,"f=[0:(nfft-1)]/nfft-0.5;\n"); fprintf(fid,"figure;\n"); fprintf(fid,"plot(f,20*log10(abs(Y)),'Color',[0.25 0.5 0.0],'LineWidth',2);\n"); fprintf(fid,"grid on;\n"); fprintf(fid,"xlabel('normalized frequency');\n"); fprintf(fid,"ylabel('PSD [dB]');\n"); fprintf(fid,"axis([-0.5 0.5 -120 20]);\n"); fclose(fid); printf("results written to %s\n",filename); #endif }