comparison spandsp-0.0.3/spandsp-0.0.3/tests/line_model.c @ 5:f762bf195c4b

import spandsp-0.0.3
author Peter Meerwald <pmeerw@cosy.sbg.ac.at>
date Fri, 25 Jun 2010 16:00:21 +0200
parents
children
comparison
equal deleted inserted replaced
4:26cd8f1ef0b1 5:f762bf195c4b
1 /*
2 * SpanDSP - a series of DSP components for telephony
3 *
4 * line_model.c - Model a telephone line.
5 *
6 * Written by Steve Underwood <steveu@coppice.org>
7 *
8 * Copyright (C) 2004 Steve Underwood
9 *
10 * All rights reserved.
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2, as
14 * published by the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 * $Id: line_model.c,v 1.21 2006/11/19 14:07:27 steveu Exp $
26 */
27
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <inttypes.h>
35 #include <string.h>
36 #include <time.h>
37 #include <stdio.h>
38 #include <fcntl.h>
39 #include <audiofile.h>
40 #include <tiffio.h>
41 #if defined(HAVE_TGMATH_H)
42 #include <tgmath.h>
43 #endif
44 #if defined(HAVE_MATH_H)
45 #define GEN_CONST
46 #include <math.h>
47 #endif
48
49 #include "spandsp.h"
50 #include "spandsp/g168models.h"
51
52 #include "test_utils.h"
53 #include "line_model.h"
54 #include "line_models.h"
55
56 #if !defined(NULL)
57 #define NULL (void *) 0
58 #endif
59
60 float null_line_model[] =
61 {
62 0.0,
63 0.0,
64 0.0,
65 0.0,
66 0.0,
67 0.0,
68 0.0,
69 0.0,
70 0.0,
71 0.0,
72 0.0,
73 0.0,
74 0.0,
75 0.0,
76 0.0,
77 0.0,
78 0.0,
79 0.0,
80 0.0,
81 0.0,
82 0.0,
83 0.0,
84 0.0,
85 0.0,
86 0.0,
87 0.0,
88 0.0,
89 0.0,
90 0.0,
91 0.0,
92 0.0,
93 0.0,
94 0.0,
95 0.0,
96 0.0,
97 0.0,
98 0.0,
99 0.0,
100 0.0,
101 0.0,
102 0.0,
103 0.0,
104 0.0,
105 0.0,
106 0.0,
107 0.0,
108 0.0,
109 0.0,
110 0.0,
111 0.0,
112 0.0,
113 0.0,
114 0.0,
115 0.0,
116 0.0,
117 0.0,
118 0.0,
119 0.0,
120 0.0,
121 0.0,
122 0.0,
123 0.0,
124 0.0,
125 0.0,
126 0.0,
127 0.0,
128 0.0,
129 0.0,
130 0.0,
131 0.0,
132 0.0,
133 0.0,
134 0.0,
135 0.0,
136 0.0,
137 0.0,
138 0.0,
139 0.0,
140 0.0,
141 0.0,
142 0.0,
143 0.0,
144 0.0,
145 0.0,
146 0.0,
147 0.0,
148 0.0,
149 0.0,
150 0.0,
151 0.0,
152 0.0,
153 0.0,
154 0.0,
155 0.0,
156 0.0,
157 0.0,
158 0.0,
159 0.0,
160 0.0,
161 0.0,
162 0.0,
163 0.0,
164 0.0,
165 0.0,
166 0.0,
167 0.0,
168 0.0,
169 0.0,
170 0.0,
171 0.0,
172 0.0,
173 0.0,
174 0.0,
175 0.0,
176 0.0,
177 0.0,
178 0.0,
179 0.0,
180 0.0,
181 0.0,
182 0.0,
183 0.0,
184 0.0,
185 0.0,
186 0.0,
187 0.0,
188 0.0,
189 0.0,
190 1.0
191 };
192
193 static float *models[] =
194 {
195 null_line_model, /* 0 */
196 proakis_line_model,
197 ad_1_edd_1_model,
198 ad_1_edd_2_model,
199 ad_1_edd_3_model,
200 ad_5_edd_1_model, /* 5 */
201 ad_5_edd_2_model,
202 ad_5_edd_3_model,
203 ad_6_edd_1_model,
204 ad_6_edd_2_model,
205 ad_6_edd_3_model, /* 10 */
206 ad_7_edd_1_model,
207 ad_7_edd_2_model,
208 ad_7_edd_3_model,
209 ad_8_edd_1_model,
210 ad_8_edd_2_model, /* 15 */
211 ad_8_edd_3_model,
212 ad_9_edd_1_model,
213 ad_9_edd_2_model,
214 ad_9_edd_3_model
215 };
216
217 static float calc_near_line_filter(one_way_line_model_state_t *s, float v)
218 {
219 float sum;
220 int j;
221 int p;
222
223 /* Add the sample in the filter buffer */
224 p = s->near_buf_ptr;
225 s->near_buf[p] = v;
226 if (++p == s->near_filter_len)
227 p = 0;
228 s->near_buf_ptr = p;
229
230 /* Apply the filter */
231 sum = 0;
232 for (j = 0; j < s->near_filter_len; j++)
233 {
234 sum += s->near_filter[j]*s->near_buf[p];
235 if (++p >= s->near_filter_len)
236 p = 0;
237 }
238
239 /* Add noise */
240 sum += awgn(&s->near_noise);
241
242 return sum;
243 }
244 /*- End of function --------------------------------------------------------*/
245
246 static float calc_far_line_filter(one_way_line_model_state_t *s, float v)
247 {
248 float sum;
249 int j;
250 int p;
251
252 /* Add the sample in the filter buffer */
253 p = s->far_buf_ptr;
254 s->far_buf[p] = v;
255 if (++p == s->far_filter_len)
256 p = 0;
257 s->far_buf_ptr = p;
258
259 /* Apply the filter */
260 sum = 0;
261 for (j = 0; j < s->far_filter_len; j++)
262 {
263 sum += s->far_filter[j]*s->far_buf[p];
264 if (++p >= s->far_filter_len)
265 p = 0;
266 }
267
268 /* Add noise */
269 sum += awgn(&s->far_noise);
270
271 return sum;
272 }
273 /*- End of function --------------------------------------------------------*/
274
275 void one_way_line_model(one_way_line_model_state_t *s,
276 int16_t *output,
277 const int16_t *input,
278 int samples)
279 {
280 int i;
281 float in;
282 float out;
283 float out1;
284 int16_t amp[1];
285
286 /* The path being modelled is:
287 terminal
288 | < hybrid
289 |
290 | < noise and filtering
291 |
292 | < hybrid
293 CO
294 |
295 | < A-law distortion + bulk delay
296 |
297 CO
298 | < hybrid
299 |
300 | < noise and filtering
301 |
302 | < hybrid
303 terminal
304 */
305 for (i = 0; i < samples; i++)
306 {
307 in = input[i];
308
309 /* Near end analogue section */
310
311 /* Line model filters & noise */
312 out = calc_near_line_filter(s, in);
313
314 /* Long distance digital section */
315
316 amp[0] = out;
317 codec_munge(s->munge, amp, 1);
318 out = amp[0];
319 /* Introduce the bulk delay of the long distance link. */
320 out1 = s->bulk_delay_buf[s->bulk_delay_ptr];
321 s->bulk_delay_buf[s->bulk_delay_ptr] = out;
322 out = out1;
323 if (++s->bulk_delay_ptr >= s->bulk_delay)
324 s->bulk_delay_ptr = 0;
325
326 /* Far end analogue section */
327
328 /* Line model filters & noise */
329 out = calc_far_line_filter(s, out);
330
331 output[i] = out;
332 }
333 }
334 /*- End of function --------------------------------------------------------*/
335
336 void both_ways_line_model(both_ways_line_model_state_t *s,
337 int16_t *output1,
338 const int16_t *input1,
339 int16_t *output2,
340 const int16_t *input2,
341 int samples)
342 {
343 int i;
344 float in1;
345 float in2;
346 float out1;
347 float out2;
348 float tmp1;
349 float tmp2;
350 int16_t amp[1];
351
352 /* The path being modelled is:
353 terminal
354 | < hybrid echo
355 |
356 | < noise and filtering
357 |
358 | < hybrid echo
359 CO
360 |
361 | < A-law distortion + bulk delay
362 |
363 CO
364 | < hybrid echo
365 |
366 | < noise and filtering
367 |
368 | < hybrid echo
369 terminal
370 */
371 for (i = 0; i < samples; i++)
372 {
373 in1 = input1[i];
374 in2 = input2[i];
375
376 /* Near end analogue sections */
377 /* Echo from each terminal's CO hybrid */
378 tmp1 = in1 + s->fout2*s->line1.near_co_hybrid_echo;
379 tmp2 = in2 + s->fout1*s->line2.near_co_hybrid_echo;
380
381 /* Line model filters & noise */
382 s->fout1 = calc_near_line_filter(&s->line1, tmp1);
383 s->fout2 = calc_near_line_filter(&s->line2, tmp2);
384
385 /* Long distance digital section */
386
387 /* Introduce distortion due to A-law or u-law munging. */
388 amp[0] = s->fout1;
389 codec_munge(s->line1.munge, amp, 1);
390 s->fout1 = amp[0];
391
392 amp[0] = s->fout2;
393 codec_munge(s->line2.munge, amp, 1);
394 s->fout2 = amp[0];
395
396 /* Introduce the bulk delay of the long distance digital link. */
397 out1 = s->line1.bulk_delay_buf[s->line1.bulk_delay_ptr];
398 s->line1.bulk_delay_buf[s->line1.bulk_delay_ptr] = s->fout1;
399 s->fout1 = out1;
400 if (++s->line1.bulk_delay_ptr >= s->line1.bulk_delay)
401 s->line1.bulk_delay_ptr = 0;
402
403 out2 = s->line2.bulk_delay_buf[s->line2.bulk_delay_ptr];
404 s->line2.bulk_delay_buf[s->line2.bulk_delay_ptr] = s->fout2;
405 s->fout2 = out2;
406 if (++s->line2.bulk_delay_ptr >= s->line2.bulk_delay)
407 s->line2.bulk_delay_ptr = 0;
408
409 /* Far end analogue sections */
410
411 /* Echo from each terminal's own hybrid */
412 out1 += in2*s->line1.far_cpe_hybrid_echo;
413 out2 += in1*s->line2.far_cpe_hybrid_echo;
414
415 /* Line model filters & noise */
416 out1 = calc_far_line_filter(&s->line1, out1);
417 out2 = calc_far_line_filter(&s->line2, out2);
418
419 output1[i] = fsaturate(out1);
420 output2[i] = fsaturate(out2);
421 }
422 }
423 /*- End of function --------------------------------------------------------*/
424
425 one_way_line_model_state_t *one_way_line_model_init(int model, float noise, int codec)
426 {
427 one_way_line_model_state_t *s;
428
429 if ((s = (one_way_line_model_state_t *) malloc(sizeof(*s))) == NULL)
430 return NULL;
431 memset(s, 0, sizeof(*s));
432
433 s->bulk_delay = 8;
434 s->bulk_delay_ptr = 0;
435
436 s->munge = codec_munge_init(codec);
437
438 s->near_filter = models[model];
439 s->near_filter_len = 129;
440
441 s->far_filter = models[model];
442 s->far_filter_len = 129;
443
444 awgn_init_dbm0(&s->near_noise, 1234567, noise);
445 awgn_init_dbm0(&s->far_noise, 1234567, noise);
446 return s;
447 }
448 /*- End of function --------------------------------------------------------*/
449
450 int one_way_line_model_release(one_way_line_model_state_t *s)
451 {
452 free(s);
453 return 0;
454 }
455 /*- End of function --------------------------------------------------------*/
456
457 both_ways_line_model_state_t *both_ways_line_model_init(int model1,
458 float noise1,
459 int model2,
460 float noise2,
461 int codec)
462 {
463 float echo_level;
464 both_ways_line_model_state_t *s;
465
466 if ((s = (both_ways_line_model_state_t *) malloc(sizeof(*s))) == NULL)
467 return NULL;
468 memset(s, 0, sizeof(*s));
469
470 s->line1.munge = codec_munge_init(codec);
471 s->line2.munge = codec_munge_init(codec);
472
473 s->line1.bulk_delay = 8;
474 s->line2.bulk_delay = 8;
475
476 s->line1.bulk_delay_ptr = 0;
477 s->line2.bulk_delay_ptr = 0;
478
479 s->line1.near_filter = models[model1];
480 s->line1.near_filter_len = 129;
481 s->line2.near_filter = models[model2];
482 s->line2.near_filter_len = 129;
483
484 s->line1.far_filter = models[model1];
485 s->line1.far_filter_len = 129;
486 s->line2.far_filter = models[model2];
487 s->line2.far_filter_len = 129;
488
489 awgn_init_dbm0(&s->line1.near_noise, 1234567, noise1);
490 awgn_init_dbm0(&s->line2.near_noise, 7654321, noise2);
491
492 awgn_init_dbm0(&s->line1.far_noise, 1234567, noise1);
493 awgn_init_dbm0(&s->line2.far_noise, 7654321, noise2);
494
495 /* Echos */
496 echo_level = -15; /* in dB */
497 s->line1.near_co_hybrid_echo = pow(10, echo_level/20.0);
498 s->line2.near_co_hybrid_echo = pow(10, echo_level/20.0);
499 s->line1.near_cpe_hybrid_echo = pow(10, echo_level/20.0);
500 s->line2.near_cpe_hybrid_echo = pow(10, echo_level/20.0);
501
502 return s;
503 }
504 /*- End of function --------------------------------------------------------*/
505
506 int both_ways_line_model_release(both_ways_line_model_state_t *s)
507 {
508 free(s);
509 return 0;
510 }
511 /*- End of function --------------------------------------------------------*/
512 /*- End of file ------------------------------------------------------------*/

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