Mercurial > hg > audiostuff
comparison spandsp-0.0.6pre17/src/make_modem_filter.c @ 4:26cd8f1ef0b1
import spandsp-0.0.6pre17
author | Peter Meerwald <pmeerw@cosy.sbg.ac.at> |
---|---|
date | Fri, 25 Jun 2010 15:50:58 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
3:c6c5a16ce2f2 | 4:26cd8f1ef0b1 |
---|---|
1 /* | |
2 * SpanDSP - a series of DSP components for telephony | |
3 * | |
4 * make_modem_filter.c - Create coefficient sets for pulse shaping | |
5 * various modem rx and tx signals. | |
6 * | |
7 * Written by Steve Underwood <steveu@coppice.org> | |
8 * | |
9 * Copyright (C) 2008 Steve Underwood | |
10 * | |
11 * All rights reserved. | |
12 * | |
13 * This program is free software; you can redistribute it and/or modify | |
14 * it under the terms of the GNU General Public License version 2, as | |
15 * published by the Free Software Foundation. | |
16 * | |
17 * This program is distributed in the hope that it will be useful, | |
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 * GNU General Public License for more details. | |
21 * | |
22 * You should have received a copy of the GNU General Public License | |
23 * along with this program; if not, write to the Free Software | |
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
25 * | |
26 * $Id: make_modem_filter.c,v 1.17.4.1 2009/12/28 12:20:46 steveu Exp $ | |
27 */ | |
28 | |
29 #if defined(HAVE_CONFIG_H) | |
30 #include "config.h" | |
31 #endif | |
32 | |
33 #include <inttypes.h> | |
34 #include <stdlib.h> | |
35 #include <unistd.h> | |
36 #if defined(HAVE_TGMATH_H) | |
37 #include <tgmath.h> | |
38 #endif | |
39 #if defined(HAVE_MATH_H) | |
40 #include <math.h> | |
41 #endif | |
42 #include "floating_fudge.h" | |
43 #include <string.h> | |
44 #include <stdio.h> | |
45 #include <time.h> | |
46 #include <fcntl.h> | |
47 #if defined(__sunos) || defined(__solaris) || defined(__sun) | |
48 #include <getopt.h> | |
49 #endif | |
50 | |
51 #include "spandsp/telephony.h" | |
52 #include "spandsp/complex.h" | |
53 #include "filter_tools.h" | |
54 | |
55 #if !defined(FALSE) | |
56 #define FALSE 0 | |
57 #endif | |
58 #if !defined(TRUE) | |
59 #define TRUE (!FALSE) | |
60 #endif | |
61 | |
62 //#define SAMPLE_RATE 8000.0 | |
63 #define MAX_COEFFS_PER_FILTER 128 | |
64 #define MAX_COEFF_SETS 384 | |
65 | |
66 static void make_tx_filter(int coeff_sets, | |
67 int coeffs_per_filter, | |
68 double carrier, | |
69 double baud_rate, | |
70 double excess_bandwidth, | |
71 int fixed_point, | |
72 const char *tag) | |
73 { | |
74 int i; | |
75 int j; | |
76 int x; | |
77 int total_coeffs; | |
78 double alpha; | |
79 double beta; | |
80 double gain; | |
81 double scaling; | |
82 double peak; | |
83 double coeffs[MAX_COEFF_SETS*MAX_COEFFS_PER_FILTER + 1]; | |
84 | |
85 total_coeffs = coeff_sets*coeffs_per_filter + 1; | |
86 alpha = baud_rate/(2.0*(double) (coeff_sets*baud_rate)); | |
87 beta = excess_bandwidth; | |
88 | |
89 compute_raised_cosine_filter(coeffs, total_coeffs, TRUE, FALSE, alpha, beta); | |
90 | |
91 /* Find the DC gain of the filter, and adjust the filter to unity gain. */ | |
92 gain = 0.0; | |
93 for (i = coeff_sets/2; i < total_coeffs; i += coeff_sets) | |
94 gain += coeffs[i]; | |
95 /* Normalise the gain to 1.0 */ | |
96 for (i = 0; i < total_coeffs; i++) | |
97 coeffs[i] /= gain; | |
98 gain = 1.0; | |
99 | |
100 if (fixed_point) | |
101 { | |
102 peak = -1.0; | |
103 for (i = 0; i < total_coeffs; i++) | |
104 { | |
105 if (fabs(coeffs[i]) > peak) | |
106 peak = fabs(coeffs[i]); | |
107 } | |
108 scaling = 32767.0; | |
109 if (peak >= 1.0) | |
110 { | |
111 scaling /= peak; | |
112 gain = 1.0/peak; | |
113 } | |
114 for (i = 0; i < total_coeffs; i++) | |
115 coeffs[i] *= scaling; | |
116 } | |
117 | |
118 /* Churn out the data as a C source code header file, which can be directly included by the | |
119 modem code. */ | |
120 printf("#define TX_PULSESHAPER%s_GAIN %ff\n", tag, gain); | |
121 printf("#define TX_PULSESHAPER%s_COEFF_SETS %d\n", tag, coeff_sets); | |
122 printf("static const %s tx_pulseshaper%s[TX_PULSESHAPER%s_COEFF_SETS][%d] =\n", | |
123 (fixed_point) ? "int16_t" : "float", | |
124 tag, | |
125 tag, | |
126 coeffs_per_filter); | |
127 printf("{\n"); | |
128 for (j = 0; j < coeff_sets; j++) | |
129 { | |
130 x = j; | |
131 printf(" {\n"); | |
132 if (fixed_point) | |
133 printf(" %8d, /* Filter %d */\n", (int) coeffs[x], j); | |
134 else | |
135 printf(" %15.10ff, /* Filter %d */\n", coeffs[x], j); | |
136 for (i = 1; i < coeffs_per_filter - 1; i++) | |
137 { | |
138 x = i*coeff_sets + j; | |
139 if (fixed_point) | |
140 printf(" %8d,\n", (int) coeffs[x]); | |
141 else | |
142 printf(" %15.10ff,\n", coeffs[x]); | |
143 } | |
144 x = i*coeff_sets + j; | |
145 if (fixed_point) | |
146 printf(" %8d\n", (int) coeffs[x]); | |
147 else | |
148 printf(" %15.10ff\n", coeffs[x]); | |
149 if (j < coeff_sets - 1) | |
150 printf(" },\n"); | |
151 else | |
152 printf(" }\n"); | |
153 } | |
154 printf("};\n"); | |
155 } | |
156 /*- End of function --------------------------------------------------------*/ | |
157 | |
158 static void make_rx_filter(int coeff_sets, | |
159 int coeffs_per_filter, | |
160 double carrier, | |
161 double baud_rate, | |
162 double excess_bandwidth, | |
163 int fixed_point, | |
164 const char *tag) | |
165 { | |
166 int i; | |
167 int j; | |
168 int k; | |
169 int m; | |
170 int x; | |
171 int total_coeffs; | |
172 double alpha; | |
173 double beta; | |
174 double gain; | |
175 double peak; | |
176 double coeffs[MAX_COEFF_SETS*MAX_COEFFS_PER_FILTER + 1]; | |
177 #if 0 | |
178 complex_t co[MAX_COEFFS_PER_FILTER]; | |
179 #else | |
180 double cox[MAX_COEFFS_PER_FILTER]; | |
181 #endif | |
182 | |
183 total_coeffs = coeff_sets*coeffs_per_filter + 1; | |
184 alpha = baud_rate/(2.0*(double) (coeff_sets*SAMPLE_RATE)); | |
185 beta = excess_bandwidth; | |
186 carrier *= 2.0*3.1415926535/SAMPLE_RATE; | |
187 | |
188 compute_raised_cosine_filter(coeffs, total_coeffs, TRUE, FALSE, alpha, beta); | |
189 | |
190 /* Find the DC gain of the filter, and adjust the filter to unity gain. */ | |
191 gain = 0.0; | |
192 for (i = coeff_sets/2; i < total_coeffs; i += coeff_sets) | |
193 gain += coeffs[i]; | |
194 /* Normalise the gain to 1.0 */ | |
195 for (i = 0; i < total_coeffs; i++) | |
196 coeffs[i] /= gain; | |
197 gain = 1.0; | |
198 | |
199 if (fixed_point) | |
200 { | |
201 peak = -1.0; | |
202 for (i = 0; i < total_coeffs; i++) | |
203 { | |
204 if (fabs(coeffs[i]) > peak) | |
205 peak = fabs(coeffs[i]); | |
206 } | |
207 gain = 32767.0; | |
208 if (peak >= 1.0) | |
209 gain /= peak; | |
210 for (i = 0; i < total_coeffs; i++) | |
211 coeffs[i] *= gain; | |
212 } | |
213 | |
214 /* Churn out the data as a C source code header file, which can be directly included by the | |
215 modem code. */ | |
216 printf("#define RX_PULSESHAPER%s_GAIN %ff\n", tag, gain); | |
217 printf("#define RX_PULSESHAPER%s_COEFF_SETS %d\n", tag, coeff_sets); | |
218 #if 0 | |
219 printf("static const %s rx_pulseshaper%s[RX_PULSESHAPER%s_COEFF_SETS][%d] =\n", | |
220 (fixed_point) ? "complexi16_t" : "complexf_t", | |
221 tag, | |
222 tag, | |
223 coeffs_per_filter); | |
224 printf("{\n"); | |
225 for (j = 0; j < coeff_sets; j++) | |
226 { | |
227 /* Complex modulate the filter, to make it a complex pulse shaping bandpass filter | |
228 centred at the nominal carrier frequency. Use the same phase for all the coefficient | |
229 sets. This means the modem can step the carrier in whole samples, and not worry about | |
230 the fractional sample shift caused by selecting amongst the various coefficient sets. */ | |
231 for (i = 0; i < coeffs_per_filter; i++) | |
232 { | |
233 m = i - (coeffs_per_filter >> 1); | |
234 x = i*coeff_sets + j; | |
235 co[i].re = coeffs[x]*cos(carrier*m); | |
236 co[i].im = coeffs[x]*sin(carrier*m); | |
237 } | |
238 printf(" {\n"); | |
239 if (fixed_point) | |
240 printf(" {%8d, %8d}, /* Filter %d */\n", (int) co[i].re, (int) co[i].im, j); | |
241 else | |
242 printf(" {%15.10ff, %15.10ff}, /* Filter %d */\n", co[0].re, co[0].im, j); | |
243 for (i = 1; i < coeffs_per_filter - 1; i++) | |
244 { | |
245 if (fixed_point) | |
246 printf(" {%8d, %8d},\n", (int) co[i].re, (int) co[i].im); | |
247 else | |
248 printf(" {%15.10ff, %15.10ff},\n", co[i].re, co[i].im); | |
249 } | |
250 if (fixed_point) | |
251 printf(" {%8d, %8d}\n", (int) co[i].re, (int) co[i].im); | |
252 else | |
253 printf(" {%15.10ff, %15.10ff}\n", co[i].re, co[i].im); | |
254 if (j < coeff_sets - 1) | |
255 printf(" },\n"); | |
256 else | |
257 printf(" }\n"); | |
258 } | |
259 printf("};\n"); | |
260 #else | |
261 for (k = 0; k < 2; k++) | |
262 { | |
263 printf("static const %s rx_pulseshaper%s_%s[RX_PULSESHAPER%s_COEFF_SETS][%d] =\n", | |
264 (fixed_point) ? "int16_t" : "float", | |
265 tag, | |
266 (k == 0) ? "re" : "im", | |
267 tag, | |
268 coeffs_per_filter); | |
269 printf("{\n"); | |
270 for (j = 0; j < coeff_sets; j++) | |
271 { | |
272 /* Complex modulate the filter, to make it a complex pulse shaping bandpass filter | |
273 centred at the nominal carrier frequency. Use the same phase for all the coefficient | |
274 sets. This means the modem can step the carrier in whole samples, and not worry about | |
275 the fractional sample shift caused by selecting amongst the various coefficient sets. */ | |
276 for (i = 0; i < coeffs_per_filter; i++) | |
277 { | |
278 m = i - (coeffs_per_filter >> 1); | |
279 x = i*coeff_sets + j; | |
280 if (k == 0) | |
281 cox[i] = coeffs[x]*cos(carrier*m); | |
282 else | |
283 cox[i] = coeffs[x]*sin(carrier*m); | |
284 } | |
285 printf(" {\n"); | |
286 if (fixed_point) | |
287 printf(" %8d, /* Filter %d */\n", (int) cox[0], j); | |
288 else | |
289 printf(" %15.10ff, /* Filter %d */\n", cox[0], j); | |
290 for (i = 1; i < coeffs_per_filter - 1; i++) | |
291 { | |
292 if (fixed_point) | |
293 printf(" %8d,\n", (int) cox[i]); | |
294 else | |
295 printf(" %15.10ff,\n", cox[i]); | |
296 } | |
297 if (fixed_point) | |
298 printf(" %8d\n", (int) cox[i]); | |
299 else | |
300 printf(" %15.10ff\n", cox[i]); | |
301 if (j < coeff_sets - 1) | |
302 printf(" },\n"); | |
303 else | |
304 printf(" }\n"); | |
305 } | |
306 printf("};\n"); | |
307 } | |
308 #endif | |
309 } | |
310 /*- End of function --------------------------------------------------------*/ | |
311 | |
312 static void usage(void) | |
313 { | |
314 fprintf(stderr, "Usage: make_modem_rx_filter -m <V.17 | V.22bis | V.22bis1200 | V.22bis2400 | V.27ter2400 | V.27ter4800 | V.29> [-i] [-r] [-t]\n"); | |
315 } | |
316 /*- End of function --------------------------------------------------------*/ | |
317 | |
318 int main(int argc, char **argv) | |
319 { | |
320 int rx_coeff_sets; | |
321 int rx_coeffs_per_filter; | |
322 int tx_coeff_sets; | |
323 int tx_coeffs_per_filter; | |
324 int opt; | |
325 int transmit_modem; | |
326 int fixed_point; | |
327 double carrier; | |
328 double baud_rate; | |
329 double rx_excess_bandwidth; | |
330 double tx_excess_bandwidth; | |
331 const char *tag; | |
332 const char *modem; | |
333 | |
334 fixed_point = FALSE; | |
335 transmit_modem = FALSE; | |
336 modem = ""; | |
337 while ((opt = getopt(argc, argv, "im:rt")) != -1) | |
338 { | |
339 switch (opt) | |
340 { | |
341 case 'i': | |
342 fixed_point = TRUE; | |
343 break; | |
344 case 'm': | |
345 modem = optarg; | |
346 break; | |
347 case 'r': | |
348 transmit_modem = FALSE; | |
349 break; | |
350 case 't': | |
351 transmit_modem = TRUE; | |
352 break; | |
353 default: | |
354 usage(); | |
355 exit(2); | |
356 break; | |
357 } | |
358 } | |
359 if (strcmp(modem, "V.17") == 0 || strcmp(modem, "V.32bis") == 0) | |
360 { | |
361 /* This applies to V.32bis as well as V.17 */ | |
362 rx_coeff_sets = 192; | |
363 rx_coeffs_per_filter = 27; | |
364 rx_excess_bandwidth = 0.5; | |
365 tx_coeff_sets = 10; | |
366 tx_coeffs_per_filter = 9; | |
367 tx_excess_bandwidth = 0.25; | |
368 carrier = 1800.0; | |
369 baud_rate = 2400.0; | |
370 tag = ""; | |
371 } | |
372 else if (strcmp(modem, "V.22bis") == 0) | |
373 { | |
374 /* This is only intended to apply to transmit. */ | |
375 rx_coeff_sets = 12; | |
376 rx_coeffs_per_filter = 37; | |
377 rx_excess_bandwidth = 0.75; | |
378 tx_coeff_sets = 40; | |
379 tx_coeffs_per_filter = 9; | |
380 tx_excess_bandwidth = 0.75; | |
381 carrier = 1200.0; | |
382 baud_rate = 600.0; | |
383 tag = ""; | |
384 } | |
385 else if (strcmp(modem, "V.22bis1200") == 0) | |
386 { | |
387 /* This is only intended to apply to receive. */ | |
388 rx_coeff_sets = 12; | |
389 rx_coeffs_per_filter = 37; | |
390 rx_excess_bandwidth = 0.75; | |
391 tx_coeff_sets = 40; | |
392 tx_coeffs_per_filter = 9; | |
393 tx_excess_bandwidth = 0.75; | |
394 carrier = 1200.0; | |
395 baud_rate = 600.0; | |
396 tag = "_1200"; | |
397 } | |
398 else if (strcmp(modem, "V.22bis2400") == 0) | |
399 { | |
400 /* This is only intended to apply to receive. */ | |
401 rx_coeff_sets = 12; | |
402 rx_coeffs_per_filter = 37; | |
403 rx_excess_bandwidth = 0.75; | |
404 tx_coeff_sets = 40; | |
405 tx_coeffs_per_filter = 9; | |
406 tx_excess_bandwidth = 0.75; | |
407 carrier = 2400.0; | |
408 baud_rate = 600.0; | |
409 tag = "_2400"; | |
410 } | |
411 else if (strcmp(modem, "V.27ter4800") == 0) | |
412 { | |
413 rx_coeff_sets = 8; | |
414 rx_coeffs_per_filter = 27; | |
415 rx_excess_bandwidth = 0.5; | |
416 tx_coeff_sets = 5; | |
417 tx_coeffs_per_filter = 9; | |
418 tx_excess_bandwidth = 0.5; | |
419 carrier = 1800.0; | |
420 baud_rate = 1600.0; | |
421 tag = "_4800"; | |
422 } | |
423 else if (strcmp(modem, "V.27ter2400") == 0) | |
424 { | |
425 rx_coeff_sets = 12; | |
426 rx_coeffs_per_filter = 27; | |
427 rx_excess_bandwidth = 0.5; | |
428 tx_coeff_sets = 20; | |
429 tx_coeffs_per_filter = 9; | |
430 tx_excess_bandwidth = 0.5; | |
431 carrier = 1800.0; | |
432 baud_rate = 1200.0; | |
433 tag = "_2400"; | |
434 } | |
435 else if (strcmp(modem, "V.29") == 0) | |
436 { | |
437 rx_coeff_sets = 48; | |
438 rx_coeffs_per_filter = 27; | |
439 rx_excess_bandwidth = 0.5; | |
440 tx_coeff_sets = 10; | |
441 tx_coeffs_per_filter = 9; | |
442 tx_excess_bandwidth = 0.25; | |
443 carrier = 1700.0; | |
444 baud_rate = 2400.0; | |
445 tag = ""; | |
446 } | |
447 else | |
448 { | |
449 usage(); | |
450 exit(2); | |
451 } | |
452 if (transmit_modem) | |
453 { | |
454 make_tx_filter(tx_coeff_sets, | |
455 tx_coeffs_per_filter, | |
456 carrier, | |
457 baud_rate, | |
458 tx_excess_bandwidth, | |
459 fixed_point, | |
460 tag); | |
461 } | |
462 else | |
463 { | |
464 make_rx_filter(rx_coeff_sets, | |
465 rx_coeffs_per_filter, | |
466 carrier, | |
467 baud_rate, | |
468 rx_excess_bandwidth, | |
469 fixed_point, | |
470 tag); | |
471 } | |
472 return 0; | |
473 } | |
474 /*- End of function --------------------------------------------------------*/ | |
475 /*- End of file ------------------------------------------------------------*/ |