1 /*
2 * Copyright (c) 2007 - 2015 Joseph Gaeddert
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23 //
24 // Windowing functions
25 //
26 // References:
27 // [Kaiser:1980] James F. Kaiser and Ronald W. Schafer, "On
28 // the Use of I0-Sinh Window for Spectrum Analysis,"
29 // IEEE Transactions on Acoustics, Speech, and Signal
30 // Processing, vol. ASSP-28, no. 1, pp. 105--107,
31 // February, 1980.
32 // [harris:1978] frederic j. harris, "On the Use of Windows for Harmonic
33 // Analysis with the Discrete Fourier Transform," Proceedings of the
34 // IEEE, vol. 66, no. 1, January, 1978.
35 // [Nuttall:1981] Albert H. Nuttall, "Some Windows with Very Good Sidelobe
36 // Behavior," IEEE Transactions on Acoustics, Speech, and Signal
37 // Processing, vol. ASSP-29, no. 1, pp. 84-91, February, 1981.
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <math.h>
43
44 #include "liquid.internal.h"
45
46 const char * liquid_window_str[LIQUID_WINDOW_NUM_FUNCTIONS][2] = {
47 // short name, long name
48 {"unknown", "unknown" },
49 {"hamming", "Hamming" },
50 {"hann", "Hann" },
51 {"blackmanharris", "Blackman-harris (4-term)" },
52 {"blackmanharris7", "Blackman-harris (7-term)" },
53 {"kaiser", "Kaiser-Bessel" },
54 {"flattop", "flat top" },
55 {"triangular", "triangular" },
56 {"rcostaper", "raised-cosine taper" },
57 {"kbd", "Kaiser-Bessel derived" },
58 };
59
60 // Print compact list of existing and available windowing functions
liquid_print_windows()61 void liquid_print_windows()
62 {
63 unsigned int i;
64 unsigned int len = 10;
65
66 // print all available MOD schemes
67 printf(" ");
68 for (i=0; i<LIQUID_WINDOW_NUM_FUNCTIONS; i++) {
69 printf("%s", liquid_window_str[i][0]);
70
71 if (i != LIQUID_WINDOW_NUM_FUNCTIONS-1)
72 printf(", ");
73
74 len += strlen(liquid_window_str[i][0]);
75 if (len > 48 && i != LIQUID_WINDOW_NUM_FUNCTIONS-1) {
76 len = 10;
77 printf("\n ");
78 }
79 }
80 printf("\n");
81 }
82
83 // returns modulation_scheme based on input string
liquid_getopt_str2window(const char * _str)84 liquid_window_type liquid_getopt_str2window(const char * _str)
85 {
86 // compare each string to short name
87 unsigned int i;
88 for (i=0; i<LIQUID_WINDOW_NUM_FUNCTIONS; i++) {
89 if (strcmp(_str,liquid_window_str[i][0])==0) {
90 return i;
91 }
92 }
93
94 fprintf(stderr,"warning: liquid_getopt_str2window(), unknown/unsupported window scheme : %s\n", _str);
95 return LIQUID_WINDOW_UNKNOWN;
96 }
97
98 // Kaiser-Bessel derived window
liquid_kbd(unsigned int _n,unsigned int _N,float _beta)99 float liquid_kbd(unsigned int _n,
100 unsigned int _N,
101 float _beta)
102 {
103 // TODO add reference
104
105 // validate input
106 if (_n >= _N) {
107 fprintf(stderr,"error: liquid_kbd(), index exceeds maximum\n");
108 exit(1);
109 } else if (_N == 0) {
110 fprintf(stderr,"error: liquid_kbd(), window length must be greater than zero\n");
111 exit(1);
112 } else if ( _N % 2 ) {
113 fprintf(stderr,"error: liquid_kbd(), window length must be odd\n");
114 exit(1);
115 }
116
117 unsigned int M = _N / 2;
118 if (_n >= M)
119 return liquid_kbd(_N-_n-1,_N,_beta);
120
121 float w0 = 0.0f;
122 float w1 = 0.0f;
123 float w;
124 unsigned int i;
125 for (i=0; i<=M; i++) {
126 // compute Kaiser window
127 w = kaiser(i,M+1,_beta,0.0f);
128
129 // accumulate window sums
130 w1 += w;
131 if (i <= _n) w0 += w;
132 }
133 //printf("%12.8f / %12.8f = %12.8f\n", w0, w1, w0/w1);
134
135 return sqrtf(w0 / w1);
136 }
137
138
139 // Kaiser-Bessel derived window (full window function)
liquid_kbd_window(unsigned int _n,float _beta,float * _w)140 void liquid_kbd_window(unsigned int _n,
141 float _beta,
142 float * _w)
143 {
144 unsigned int i;
145 // TODO add reference
146
147 // validate input
148 if (_n == 0) {
149 fprintf(stderr,"error: liquid_kbd_window(), window length must be greater than zero\n");
150 exit(1);
151 } else if ( _n % 2 ) {
152 fprintf(stderr,"error: liquid_kbd_window(), window length must be odd\n");
153 exit(1);
154 } else if ( _beta < 0.0f ) {
155 fprintf(stderr,"error: liquid_kbd_window(), _beta must be positive\n");
156 exit(1);
157 }
158
159 // compute half length
160 unsigned int M = _n / 2;
161
162 // generate regular Kaiser window, length M+1
163 float w_kaiser[M+1];
164 for (i=0; i<=M; i++)
165 w_kaiser[i] = kaiser(i,M+1,_beta,0.0f);
166
167 // compute sum(wk[])
168 float w_sum = 0.0f;
169 for (i=0; i<=M; i++)
170 w_sum += w_kaiser[i];
171
172 // accumulate window
173 float w_acc = 0.0f;
174 for (i=0; i<M; i++) {
175 w_acc += w_kaiser[i];
176 _w[i] = sqrtf(w_acc / w_sum);
177 }
178
179 // window has even symmetry; flip around index M
180 for (i=0; i<M; i++)
181 _w[_n-i-1] = _w[i];
182 }
183
184
185 // Kaiser window [Kaiser:1980]
186 // _n : sample index
187 // _N : window length (samples)
188 // _beta : window taper parameter
189 // _mu : fractional sample offset
kaiser(unsigned int _n,unsigned int _N,float _beta,float _mu)190 float kaiser(unsigned int _n,
191 unsigned int _N,
192 float _beta,
193 float _mu)
194 {
195 // validate input
196 if (_n > _N) {
197 fprintf(stderr,"error: kaiser(), sample index must not exceed window length\n");
198 exit(1);
199 } else if (_beta < 0) {
200 fprintf(stderr,"error: kaiser(), beta must be greater than or equal to zero\n");
201 exit(1);
202 } else if (_mu < -0.5 || _mu > 0.5) {
203 fprintf(stderr,"error: kaiser(), fractional sample offset must be in [-0.5,0.5]\n");
204 exit(1);
205 }
206
207 float t = (float)_n - (float)(_N-1)/2 + _mu;
208 float r = 2.0f*t/(float)(_N);
209 float a = liquid_besseli0f(_beta*sqrtf(1-r*r));
210 float b = liquid_besseli0f(_beta);
211 return a / b;
212 }
213
214 // Hamming window [Nuttall:1981]
hamming(unsigned int _n,unsigned int _N)215 float hamming(unsigned int _n,
216 unsigned int _N)
217 {
218 // validate input
219 if (_n > _N) {
220 fprintf(stderr,"error: hamming(), sample index must not exceed window length\n");
221 exit(1);
222 }
223
224 return 0.53836 - 0.46164*cosf( (2*M_PI*(float)_n) / ((float)(_N-1)) );
225 }
226
227 // Hann window
hann(unsigned int _n,unsigned int _N)228 float hann(unsigned int _n,
229 unsigned int _N)
230 {
231 // validate input
232 if (_n > _N) {
233 fprintf(stderr,"error: hann(), sample index must not exceed window length\n");
234 exit(1);
235 }
236
237 // TODO test this function
238 // TODO add reference
239 return 0.5f - 0.5f*cosf( (2*M_PI*(float)_n) / ((float)(_N-1)) );
240 }
241
242 // Blackman-harris window [harris:1978]
blackmanharris(unsigned int _n,unsigned int _N)243 float blackmanharris(unsigned int _n,
244 unsigned int _N)
245 {
246 // validate input
247 if (_n > _N) {
248 fprintf(stderr,"error: blackmanharris(), sample index must not exceed window length\n");
249 exit(1);
250 }
251
252 // TODO test this function
253 // TODO add reference
254 float a0 = 0.35875f;
255 float a1 = 0.48829f;
256 float a2 = 0.14128f;
257 float a3 = 0.01168f;
258 float t = 2*M_PI*(float)_n / ((float)(_N-1));
259
260 return a0 - a1*cosf(t) + a2*cosf(2*t) - a3*cosf(3*t);
261 }
262
263 // 7th-order Blackman-harris window
blackmanharris7(unsigned int _n,unsigned int _N)264 float blackmanharris7(unsigned int _n, unsigned int _N)
265 {
266 // validate input
267 if (_n > _N) {
268 fprintf(stderr,"error: blackmanharris7(), sample index must not exceed window length\n");
269 exit(1);
270 }
271
272 float a0 = 0.27105f;
273 float a1 = 0.43329f;
274 float a2 = 0.21812f;
275 float a3 = 0.06592f;
276 float a4 = 0.01081f;
277 float a5 = 0.00077f;
278 float a6 = 0.00001f;
279 float t = 2*M_PI*(float)_n / ((float)(_N-1));
280
281 return a0 - a1*cosf( t) + a2*cosf(2*t) - a3*cosf(3*t)
282 + a4*cosf(4*t) - a5*cosf(5*t) + a6*cosf(6*t);
283 }
284
285 // Flat-top window
flattop(unsigned int _n,unsigned int _N)286 float flattop(unsigned int _n, unsigned int _N)
287 {
288 // validate input
289 if (_n > _N) {
290 fprintf(stderr,"error: flattop(), sample index must not exceed window length\n");
291 exit(1);
292 }
293
294 float a0 = 1.000f;
295 float a1 = 1.930f;
296 float a2 = 1.290f;
297 float a3 = 0.388f;
298 float a4 = 0.028f;
299 float t = 2*M_PI*(float)_n / ((float)(_N-1));
300
301 return a0 - a1*cosf(t) + a2*cosf(2*t) - a3*cosf(3*t) + a4*cosf(4*t);
302 }
303
304 // Triangular window
triangular(unsigned int _n,unsigned int _N,unsigned int _L)305 float triangular(unsigned int _n,
306 unsigned int _N,
307 unsigned int _L)
308 {
309 // validate input
310 if (_n > _N) {
311 fprintf(stderr,"error: triangular(), sample index must not exceed window length\n");
312 exit(1);
313 } else if (_L != _N-1 && _L != _N && _L != _N+1) {
314 fprintf(stderr,"error: triangular(), sub-length must be in _N+{-1,0,1}\n");
315 exit(1);
316 } else if (_L == 0) {
317 fprintf(stderr,"error: triangular(), sub-length must be greater than zero\n");
318 exit(1);
319 }
320
321 float _num = (float)_n - (float)((_N-1)/2.0f);
322 float _denom = ((float)_L)/2.0f;
323 return 1.0 - fabsf(_num / _denom);
324 }
325
326 // raised-cosine tapering window
327 // _n : window index
328 // _t : taper length
329 // _N : full window length
liquid_rcostaper_windowf(unsigned int _n,unsigned int _t,unsigned int _N)330 float liquid_rcostaper_windowf(unsigned int _n,
331 unsigned int _t,
332 unsigned int _N)
333 {
334 // validate input
335 if (_n > _N) {
336 fprintf(stderr,"error: liquid_rcostaper_windowf(), sample index must not exceed window length\n");
337 exit(1);
338 } else if (_t > _N/2) {
339 fprintf(stderr,"error: liquid_rcostaper_windowf(), taper length cannot exceed half window length\n");
340 exit(1);
341 }
342
343 // reverse time for ramp-down section
344 if (_n > _N - _t - 1)
345 _n = _N - _n - 1;
346
347 // return ramp or flat component
348 return (_n < _t) ? 0.5f - 0.5f*cosf(M_PI*((float)_n + 0.5f) / (float)_t) : 1.0f;
349 }
350
351
352