comparison spandsp-0.0.6pre17/spandsp-sim/line_model.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 * 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.14 2009/09/23 16:02:59 steveu Exp $
26 */
27
28 #if defined(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 #if defined(HAVE_TGMATH_H)
40 #include <tgmath.h>
41 #endif
42 #if defined(HAVE_MATH_H)
43 #define GEN_CONST
44 #include <math.h>
45 #endif
46 #include "floating_fudge.h"
47
48 #define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
49 #include "spandsp.h"
50 #include "spandsp-sim.h"
51 #include "spandsp/g168models.h"
52
53 #if !defined(NULL)
54 #define NULL (void *) 0
55 #endif
56
57 static const float null_line_model[] =
58 {
59 0.0,
60 0.0,
61 0.0,
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 1.0
188 };
189
190 SPAN_DECLARE_DATA const float *line_models[] =
191 {
192 null_line_model, /* 0 */
193 proakis_line_model,
194 ad_1_edd_1_model,
195 ad_1_edd_2_model,
196 ad_1_edd_3_model,
197 ad_5_edd_1_model, /* 5 */
198 ad_5_edd_2_model,
199 ad_5_edd_3_model,
200 ad_6_edd_1_model,
201 ad_6_edd_2_model,
202 ad_6_edd_3_model, /* 10 */
203 ad_7_edd_1_model,
204 ad_7_edd_2_model,
205 ad_7_edd_3_model,
206 ad_8_edd_1_model,
207 ad_8_edd_2_model, /* 15 */
208 ad_8_edd_3_model,
209 ad_9_edd_1_model,
210 ad_9_edd_2_model,
211 ad_9_edd_3_model
212 };
213
214 static float calc_near_line_filter(one_way_line_model_state_t *s, float v)
215 {
216 float sum;
217 int j;
218 int p;
219
220 /* Add the sample in the filter buffer */
221 p = s->near_buf_ptr;
222 s->near_buf[p] = v;
223 if (++p == s->near_filter_len)
224 p = 0;
225 s->near_buf_ptr = p;
226
227 /* Apply the filter */
228 sum = 0.0f;
229 for (j = 0; j < s->near_filter_len; j++)
230 {
231 sum += s->near_filter[j]*s->near_buf[p];
232 if (++p >= s->near_filter_len)
233 p = 0;
234 }
235
236 /* Add noise */
237 sum += awgn(&s->near_noise);
238
239 return sum;
240 }
241 /*- End of function --------------------------------------------------------*/
242
243 static float calc_far_line_filter(one_way_line_model_state_t *s, float v)
244 {
245 float sum;
246 int j;
247 int p;
248
249 /* Add the sample in the filter buffer */
250 p = s->far_buf_ptr;
251 s->far_buf[p] = v;
252 if (++p == s->far_filter_len)
253 p = 0;
254 s->far_buf_ptr = p;
255
256 /* Apply the filter */
257 sum = 0.0f;
258 for (j = 0; j < s->far_filter_len; j++)
259 {
260 sum += s->far_filter[j]*s->far_buf[p];
261 if (++p >= s->far_filter_len)
262 p = 0;
263 }
264
265 /* Add noise */
266 sum += awgn(&s->far_noise);
267
268 return sum;
269 }
270 /*- End of function --------------------------------------------------------*/
271
272 SPAN_DECLARE(void) one_way_line_model(one_way_line_model_state_t *s,
273 int16_t output[],
274 const int16_t input[],
275 int samples)
276 {
277 int i;
278 float in;
279 float out;
280 float out1;
281 int16_t amp[1];
282
283 /* The path being modelled is:
284 terminal
285 | < hybrid
286 |
287 | < noise and filtering
288 |
289 | < hybrid
290 CO
291 |
292 | < A-law distortion + bulk delay
293 |
294 CO
295 | < hybrid
296 |
297 | < noise and filtering
298 |
299 | < hybrid
300 terminal
301 */
302 for (i = 0; i < samples; i++)
303 {
304 in = input[i];
305
306 /* Near end analogue section */
307
308 /* Line model filters & noise */
309 out = calc_near_line_filter(s, in);
310
311 /* Long distance digital section */
312
313 amp[0] = out;
314 codec_munge(s->munge, amp, 1);
315 out = amp[0];
316 /* Introduce the bulk delay of the long distance link. */
317 out1 = s->bulk_delay_buf[s->bulk_delay_ptr];
318 s->bulk_delay_buf[s->bulk_delay_ptr] = out;
319 out = out1;
320 if (++s->bulk_delay_ptr >= s->bulk_delay)
321 s->bulk_delay_ptr = 0;
322
323 /* Far end analogue section */
324
325 /* Line model filters & noise */
326 out = calc_far_line_filter(s, out);
327
328 if (s->mains_interference)
329 {
330 tone_gen(&s->mains_tone, amp, 1);
331 out += amp[0];
332 }
333 output[i] = out + s->dc_offset;
334 }
335 }
336 /*- End of function --------------------------------------------------------*/
337
338 SPAN_DECLARE(void) one_way_line_model_set_dc(one_way_line_model_state_t *s, float dc)
339 {
340 s->dc_offset = dc;
341 }
342 /*- End of function --------------------------------------------------------*/
343
344 SPAN_DECLARE(void) one_way_line_model_set_mains_pickup(one_way_line_model_state_t *s, int f, float level)
345 {
346 tone_gen_descriptor_t mains_tone_desc;
347
348 if (f)
349 {
350 make_tone_gen_descriptor(&mains_tone_desc, f, (int) (level - 10.0f), f*3, (int) level, 1, 0, 0, 0, TRUE);
351 tone_gen_init(&s->mains_tone, &mains_tone_desc);
352 }
353 s->mains_interference = f;
354 }
355 /*- End of function --------------------------------------------------------*/
356
357 SPAN_DECLARE(void) both_ways_line_model(both_ways_line_model_state_t *s,
358 int16_t output1[],
359 const int16_t input1[],
360 int16_t output2[],
361 const int16_t input2[],
362 int samples)
363 {
364 int i;
365 float in1;
366 float in2;
367 float out1;
368 float out2;
369 float tmp1;
370 float tmp2;
371 int16_t amp[1];
372
373 /* The path being modelled is:
374 terminal
375 | < hybrid echo
376 |
377 | < noise and filtering
378 |
379 | < hybrid echo
380 CO
381 |
382 | < A-law distortion + bulk delay
383 |
384 CO
385 | < hybrid echo
386 |
387 | < noise and filtering
388 |
389 | < hybrid echo
390 terminal
391 */
392 for (i = 0; i < samples; i++)
393 {
394 in1 = input1[i];
395 in2 = input2[i];
396
397 /* Near end analogue sections */
398 /* Echo from each terminal's CO hybrid */
399 tmp1 = in1 + s->fout2*s->line1.near_co_hybrid_echo;
400 tmp2 = in2 + s->fout1*s->line2.near_co_hybrid_echo;
401
402 /* Line model filters & noise */
403 s->fout1 = calc_near_line_filter(&s->line1, tmp1);
404 s->fout2 = calc_near_line_filter(&s->line2, tmp2);
405
406 /* Long distance digital section */
407
408 /* Introduce distortion due to A-law or u-law munging. */
409 amp[0] = s->fout1;
410 codec_munge(s->line1.munge, amp, 1);
411 s->fout1 = amp[0];
412
413 amp[0] = s->fout2;
414 codec_munge(s->line2.munge, amp, 1);
415 s->fout2 = amp[0];
416
417 /* Introduce the bulk delay of the long distance digital link. */
418 out1 = s->line1.bulk_delay_buf[s->line1.bulk_delay_ptr];
419 s->line1.bulk_delay_buf[s->line1.bulk_delay_ptr] = s->fout1;
420 s->fout1 = out1;
421 if (++s->line1.bulk_delay_ptr >= s->line1.bulk_delay)
422 s->line1.bulk_delay_ptr = 0;
423
424 out2 = s->line2.bulk_delay_buf[s->line2.bulk_delay_ptr];
425 s->line2.bulk_delay_buf[s->line2.bulk_delay_ptr] = s->fout2;
426 s->fout2 = out2;
427 if (++s->line2.bulk_delay_ptr >= s->line2.bulk_delay)
428 s->line2.bulk_delay_ptr = 0;
429
430 /* Far end analogue sections */
431
432 /* Echo from each terminal's own hybrid */
433 out1 += in2*s->line1.far_cpe_hybrid_echo;
434 out2 += in1*s->line2.far_cpe_hybrid_echo;
435
436 /* Line model filters & noise */
437 out1 = calc_far_line_filter(&s->line1, out1);
438 out2 = calc_far_line_filter(&s->line2, out2);
439
440 output1[i] = fsaturate(out1 + s->line1.dc_offset);
441 output2[i] = fsaturate(out2 + s->line2.dc_offset);
442 }
443 }
444 /*- End of function --------------------------------------------------------*/
445
446 SPAN_DECLARE(void) both_ways_line_model_set_dc(both_ways_line_model_state_t *s, float dc1, float dc2)
447 {
448 s->line1.dc_offset = dc1;
449 s->line2.dc_offset = dc2;
450 }
451 /*- End of function --------------------------------------------------------*/
452
453 SPAN_DECLARE(void) both_ways_line_model_set_mains_pickup(both_ways_line_model_state_t *s, int f, float level1, float level2)
454 {
455 tone_gen_descriptor_t mains_tone_desc;
456
457 if (f)
458 {
459 make_tone_gen_descriptor(&mains_tone_desc, f, (int) (level1 - 10.0f), f*3, (int) level1, 1, 0, 0, 0, TRUE);
460 tone_gen_init(&s->line1.mains_tone, &mains_tone_desc);
461 make_tone_gen_descriptor(&mains_tone_desc, f, (int) (level2 - 10.0f), f*3, (int) level2, 1, 0, 0, 0, TRUE);
462 tone_gen_init(&s->line2.mains_tone, &mains_tone_desc);
463 }
464 s->line1.mains_interference = f;
465 s->line2.mains_interference = f;
466 }
467 /*- End of function --------------------------------------------------------*/
468
469 SPAN_DECLARE(one_way_line_model_state_t *) one_way_line_model_init(int model, float noise, int codec, int rbs_pattern)
470 {
471 one_way_line_model_state_t *s;
472
473 if ((s = (one_way_line_model_state_t *) malloc(sizeof(*s))) == NULL)
474 return NULL;
475 memset(s, 0, sizeof(*s));
476
477 s->bulk_delay = 8;
478 s->bulk_delay_ptr = 0;
479
480 s->munge = codec_munge_init(codec, rbs_pattern);
481
482 s->near_filter = line_models[model];
483 s->near_filter_len = 129;
484
485 s->far_filter = line_models[model];
486 s->far_filter_len = 129;
487
488 /* Put half the noise in each analogue section */
489 awgn_init_dbm0(&s->near_noise, 1234567, noise - 3.02f);
490 awgn_init_dbm0(&s->far_noise, 1234567, noise - 3.02f);
491
492 s->dc_offset = 0.0f;
493 s->mains_interference = 0;
494
495 return s;
496 }
497 /*- End of function --------------------------------------------------------*/
498
499 SPAN_DECLARE(int) one_way_line_model_release(one_way_line_model_state_t *s)
500 {
501 free(s);
502 return 0;
503 }
504 /*- End of function --------------------------------------------------------*/
505
506 SPAN_DECLARE(both_ways_line_model_state_t *) both_ways_line_model_init(int model1,
507 float noise1,
508 int model2,
509 float noise2,
510 int codec,
511 int rbs_pattern)
512 {
513 float echo_level;
514 both_ways_line_model_state_t *s;
515
516 if ((s = (both_ways_line_model_state_t *) malloc(sizeof(*s))) == NULL)
517 return NULL;
518 memset(s, 0, sizeof(*s));
519
520 s->line1.munge = codec_munge_init(codec, rbs_pattern);
521 s->line2.munge = codec_munge_init(codec, rbs_pattern);
522
523 s->line1.bulk_delay = 8;
524 s->line2.bulk_delay = 8;
525
526 s->line1.bulk_delay_ptr = 0;
527 s->line2.bulk_delay_ptr = 0;
528
529 s->line1.near_filter = line_models[model1];
530 s->line1.near_filter_len = 129;
531 s->line2.near_filter = line_models[model2];
532 s->line2.near_filter_len = 129;
533
534 s->line1.far_filter = line_models[model1];
535 s->line1.far_filter_len = 129;
536 s->line2.far_filter = line_models[model2];
537 s->line2.far_filter_len = 129;
538
539 /* Put half the noise in each analogue section */
540 awgn_init_dbm0(&s->line1.near_noise, 1234567, noise1 - 3.02f);
541 awgn_init_dbm0(&s->line2.near_noise, 7654321, noise2 - 3.02f);
542
543 awgn_init_dbm0(&s->line1.far_noise, 1234567, noise1 - 3.02f);
544 awgn_init_dbm0(&s->line2.far_noise, 7654321, noise2 - 3.02f);
545
546 s->line1.dc_offset = 0.0f;
547 s->line2.dc_offset = 0.0f;
548 s->line1.mains_interference = 0;
549 s->line2.mains_interference = 0;
550
551 /* Echos */
552 echo_level = -15; /* in dB */
553 s->line1.near_co_hybrid_echo = pow(10, echo_level/20.0f);
554 s->line2.near_co_hybrid_echo = pow(10, echo_level/20.0f);
555 s->line1.near_cpe_hybrid_echo = pow(10, echo_level/20.0f);
556 s->line2.near_cpe_hybrid_echo = pow(10, echo_level/20.0f);
557
558 return s;
559 }
560 /*- End of function --------------------------------------------------------*/
561
562 SPAN_DECLARE(int) both_ways_line_model_release(both_ways_line_model_state_t *s)
563 {
564 free(s);
565 return 0;
566 }
567 /*- End of function --------------------------------------------------------*/
568 /*- End of file ------------------------------------------------------------*/

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