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 ------------------------------------------------------------*/

Repositories maintained by Peter Meerwald, pmeerw@pmeerw.net.