1 //
2 // msresamp_crcf_example.c
3 //
4 // Demonstration of the multi-stage arbitrary resampler
5 //
6 
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <complex.h>
10 #include <math.h>
11 #include <getopt.h>
12 
13 #include "liquid.h"
14 
15 #define OUTPUT_FILENAME "msresamp_crcf_example.m"
16 
17 // print usage/help message
usage()18 void usage()
19 {
20     printf("Usage: %s [OPTION]\n", __FILE__);
21     printf("  h     : print help\n");
22     printf("  r     : resampling rate (output/input), default: 0.23175\n");
23     printf("  s     : stop-band attenuation [dB],     default: 60\n");
24     printf("  n     : number of input samples,        default: 400\n");
25     printf("  f     : input signal frequency,         default: 0.017\n");
26 }
27 
main(int argc,char * argv[])28 int main(int argc, char*argv[])
29 {
30     // options
31     float r=0.23175f;       // resampling rate (output/input)
32     float As=60.0f;         // resampling filter stop-band attenuation [dB]
33     unsigned int n=400;     // number of input samples
34     float fc=0.017f;        // complex sinusoid frequency
35 
36     int dopt;
37     while ((dopt = getopt(argc,argv,"hr:s:n:f:")) != EOF) {
38         switch (dopt) {
39         case 'h': usage();                return 0;
40         case 'r': r       = atof(optarg); break;
41         case 's': As      = atof(optarg); break;
42         case 'n': n       = atoi(optarg); break;
43         case 'f': fc      = atof(optarg); break;
44         default:
45             exit(1);
46         }
47     }
48 
49     // validate input
50     if (n == 0) {
51         fprintf(stderr,"error: %s, number of input samples must be greater than zero\n", argv[0]);
52         exit(1);
53     } else if (r <= 0.0f) {
54         fprintf(stderr,"error: %s, resampling rate must be greater than zero\n", argv[0]);
55         exit(1);
56     } else if ( fabsf(log2f(r)) > 10 ) {
57         fprintf(stderr,"error: %s, resampling rate unreasonable\n", argv[0]);
58         exit(1);
59     }
60 
61     unsigned int i;
62 
63     // create multi-stage arbitrary resampler object
64     msresamp_crcf q = msresamp_crcf_create(r,As);
65     msresamp_crcf_print(q);
66     float delay = msresamp_crcf_get_delay(q);
67 
68     // number of input samples (zero-padded)
69     unsigned int nx = n + (int)ceilf(delay) + 10;
70 
71     // output buffer with extra padding for good measure
72     unsigned int ny_alloc = (unsigned int) (2*(float)nx * r);  // allocation for output
73 
74     // allocate memory for arrays
75     float complex x[nx];
76     float complex y[ny_alloc];
77 
78     // generate input signal
79     float wsum = 0.0f;
80     for (i=0; i<nx; i++) {
81         // compute window
82         float w = i < n ? kaiser(i, n, 10.0f, 0.0f) : 0.0f;
83 
84         // apply window to complex sinusoid
85         x[i] = cexpf(_Complex_I*2*M_PI*fc*i) * w;
86 
87         // accumulate window
88         wsum += w;
89     }
90 
91     // run resampler
92     unsigned int ny;
93     msresamp_crcf_execute(q, x, nx, y, &ny);
94 
95     // clean up allocated objects
96     msresamp_crcf_destroy(q);
97 
98 
99     //
100     // analyze resulting signal
101     //
102 
103     // check that the actual resampling rate is close to the target
104     float r_actual = (float)ny / (float)nx;
105     float fy = fc / r;      // expected output frequency
106 
107     // run FFT and ensure that carrier has moved and that image
108     // frequencies and distortion have been adequately suppressed
109     unsigned int nfft = 1 << liquid_nextpow2(ny);
110     float complex yfft[nfft];   // fft input
111     float complex Yfft[nfft];   // fft output
112     for (i=0; i<nfft; i++)
113         yfft[i] = i < ny ? y[i] : 0.0f;
114     fft_run(nfft, yfft, Yfft, LIQUID_FFT_FORWARD, 0);
115     fft_shift(Yfft, nfft);  // run FFT shift
116 
117     // find peak frequency
118     float Ypeak = 0.0f;
119     float fpeak = 0.0f;
120     float max_sidelobe = -1e9f;     // maximum side-lobe [dB]
121     float main_lobe_width = 0.07f;  // TODO: figure this out from Kaiser's equations
122     for (i=0; i<nfft; i++) {
123         // normalized output frequency
124         float f = (float)i/(float)nfft - 0.5f;
125 
126         // scale FFT output appropriately
127         float Ymag = 20*log10f( cabsf(Yfft[i] / (r * wsum)) );
128 
129         // find frequency location of maximum magnitude
130         if (Ymag > Ypeak || i==0) {
131             Ypeak = Ymag;
132             fpeak = f;
133         }
134 
135         // find peak side-lobe value, ignoring frequencies
136         // within a certain range of signal frequency
137         if ( fabsf(f-fy) > main_lobe_width )
138             max_sidelobe = Ymag > max_sidelobe ? Ymag : max_sidelobe;
139     }
140 
141     // print results and check frequency location
142     printf("output results:\n");
143     printf("  output delay              :   %12.8f samples\n", delay);
144     printf("  desired resampling rate   :   %12.8f\n", r);
145     printf("  measured resampling rate  :   %12.8f    (%u/%u)\n", r_actual, ny, nx);
146     printf("  peak spectrum             :   %12.8f dB (expected 0.0 dB)\n", Ypeak);
147     printf("  peak frequency            :   %12.8f    (expected %-12.8f)\n", fpeak, fy);
148     printf("  max sidelobe              :   %12.8f dB (expected at least %.2f dB)\n", max_sidelobe, -As);
149 
150 
151     //
152     // export results
153     //
154     FILE * fid = fopen(OUTPUT_FILENAME,"w");
155     fprintf(fid,"%% %s: auto-generated file\n",OUTPUT_FILENAME);
156     fprintf(fid,"clear all;\n");
157     fprintf(fid,"close all;\n");
158     fprintf(fid,"delay=%f;\n", delay);
159     fprintf(fid,"r=%12.8f;\n", r);
160 
161     fprintf(fid,"nx = %u;\n", nx);
162     fprintf(fid,"x = zeros(1,nx);\n");
163     for (i=0; i<nx; i++)
164         fprintf(fid,"x(%3u) = %12.4e + j*%12.4e;\n", i+1, crealf(x[i]), cimagf(x[i]));
165 
166     fprintf(fid,"ny = %u;\n", ny);
167     fprintf(fid,"y = zeros(1,ny);\n");
168     for (i=0; i<ny; i++)
169         fprintf(fid,"y(%3u) = %12.4e + j*%12.4e;\n", i+1, crealf(y[i]), cimagf(y[i]));
170 
171     // time-domain results
172     fprintf(fid,"\n");
173     fprintf(fid,"%% plot time-domain result\n");
174     fprintf(fid,"tx=[0:(length(x)-1)];\n");
175     fprintf(fid,"ty=[0:(length(y)-1)]/r-delay;\n");
176     fprintf(fid,"tmin = min(tx(1),  ty(1)  );\n");
177     fprintf(fid,"tmax = max(tx(end),ty(end));\n");
178     fprintf(fid,"figure;\n");
179     fprintf(fid,"subplot(2,1,1);\n");
180     fprintf(fid,"  plot(tx,real(x),'-s','Color',[0.5 0.5 0.5],'MarkerSize',1,...\n");
181     fprintf(fid,"       ty,real(y),'-s','Color',[0.5 0 0],    'MarkerSize',1);\n");
182     fprintf(fid,"  legend('original','resampled','location','northeast');");
183     fprintf(fid,"  axis([tmin tmax -1.2 1.2]);\n");
184     fprintf(fid,"  grid on;\n");
185     fprintf(fid,"  xlabel('time');\n");
186     fprintf(fid,"  ylabel('real');\n");
187     fprintf(fid,"subplot(2,1,2);\n");
188     fprintf(fid,"  plot(tx,imag(x),'-s','Color',[0.5 0.5 0.5],'MarkerSize',1,...\n");
189     fprintf(fid,"       ty,imag(y),'-s','Color',[0 0.5 0],    'MarkerSize',1);\n");
190     fprintf(fid,"  legend('original','resampled','location','northeast');");
191     fprintf(fid,"  axis([tmin tmax -1.2 1.2]);\n");
192     fprintf(fid,"  grid on;\n");
193     fprintf(fid,"  xlabel('time');\n");
194     fprintf(fid,"  ylabel('imag');\n");
195 
196     // frequency-domain results
197     fprintf(fid,"\n\n");
198     fprintf(fid,"%% plot frequency-domain result\n");
199     fprintf(fid,"nfft=2^nextpow2(max(nx,ny));\n");
200     fprintf(fid,"%% estimate PSD, normalize by array length\n");
201     fprintf(fid,"X=20*log10(abs(fftshift(fft(x,nfft)/length(x))));\n");
202     fprintf(fid,"Y=20*log10(abs(fftshift(fft(y,nfft)/length(y))));\n");
203     fprintf(fid,"G=max(X);\n");
204     fprintf(fid,"X=X-G;\n");
205     fprintf(fid,"Y=Y-G;\n");
206     fprintf(fid,"f=[0:(nfft-1)]/nfft-0.5;\n");
207     fprintf(fid,"figure;\n");
208     fprintf(fid,"if r>1, fx = f/r; fy = f;   %% interpolated\n");
209     fprintf(fid,"else,   fx = f;   fy = f*r; %% decimated\n");
210     fprintf(fid,"end;\n");
211     fprintf(fid,"plot(fx,X,'LineWidth',1,  'Color',[0.5 0.5 0.5],...\n");
212     fprintf(fid,"     fy,Y,'LineWidth',1.5,'Color',[0.1 0.3 0.5]);\n");
213     fprintf(fid,"grid on;\n");
214     fprintf(fid,"xlabel('normalized frequency');\n");
215     fprintf(fid,"ylabel('PSD [dB]');\n");
216     fprintf(fid,"legend('original','resampled','location','northeast');");
217     fprintf(fid,"axis([-0.5 0.5 -120 20]);\n");
218 
219     fclose(fid);
220     printf("results written to %s\n",OUTPUT_FILENAME);
221 
222     printf("done.\n");
223     return 0;
224 }
225