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