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