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 
26 #if defined(HAVE_CONFIG_H)
27 #include "config.h"
28 #endif
29 
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <inttypes.h>
33 #include <string.h>
34 #include <time.h>
35 #include <stdio.h>
36 #include <fcntl.h>
37 #if defined(HAVE_TGMATH_H)
38 #include <tgmath.h>
39 #endif
40 #if defined(HAVE_MATH_H)
41 #define GEN_CONST
42 #include <math.h>
43 #endif
44 #if defined(HAVE_STDBOOL_H)
45 #include <stdbool.h>
46 #else
47 #include "spandsp/stdbool.h"
48 #endif
49 #include "floating_fudge.h"
50 
51 #define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
52 #include "spandsp.h"
53 #include "spandsp-sim.h"
54 #include "spandsp/g168models.h"
55 
56 #if !defined(NULL)
57 #define NULL (void *) 0
58 #endif
59 
60 static const 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 SPAN_DECLARE_DATA const float *line_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 
calc_near_line_filter(one_way_line_model_state_t * s,float v)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.0f;
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 
calc_far_line_filter(one_way_line_model_state_t * s,float v)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.0f;
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 
one_way_line_model(one_way_line_model_state_t * s,int16_t output[],const int16_t input[],int samples)275 SPAN_DECLARE(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         if (s->mains_interference)
332         {
333             tone_gen(&s->mains_tone, amp, 1);
334             out += amp[0];
335         }
336         output[i] = out + s->dc_offset;
337     }
338 }
339 /*- End of function --------------------------------------------------------*/
340 
one_way_line_model_set_dc(one_way_line_model_state_t * s,float dc)341 SPAN_DECLARE(void) one_way_line_model_set_dc(one_way_line_model_state_t *s, float dc)
342 {
343     s->dc_offset = dc;
344 }
345 /*- End of function --------------------------------------------------------*/
346 
one_way_line_model_set_mains_pickup(one_way_line_model_state_t * s,int f,float level)347 SPAN_DECLARE(void) one_way_line_model_set_mains_pickup(one_way_line_model_state_t *s, int f, float level)
348 {
349     tone_gen_descriptor_t mains_tone_desc;
350 
351     if (f)
352     {
353         tone_gen_descriptor_init(&mains_tone_desc, f, (int) (level - 10.0f), f*3, (int) level, 1, 0, 0, 0, true);
354         tone_gen_init(&s->mains_tone, &mains_tone_desc);
355     }
356     s->mains_interference = f;
357 }
358 /*- End of function --------------------------------------------------------*/
359 
both_ways_line_model(both_ways_line_model_state_t * s,int16_t output1[],const int16_t input1[],int16_t output2[],const int16_t input2[],int samples)360 SPAN_DECLARE(void) both_ways_line_model(both_ways_line_model_state_t *s,
361                                         int16_t output1[],
362                                         const int16_t input1[],
363                                         int16_t output2[],
364                                         const int16_t input2[],
365                                         int samples)
366 {
367     int i;
368     float in1;
369     float in2;
370     float out1;
371     float out2;
372     float tmp1;
373     float tmp2;
374     int16_t amp[1];
375 
376     /* The path being modelled is:
377         terminal
378           | < hybrid echo
379           |
380           | < noise and filtering
381           |
382           | < hybrid echo
383          CO
384           |
385           | < A-law distortion + bulk delay
386           |
387          CO
388           | < hybrid echo
389           |
390           | < noise and filtering
391           |
392           | < hybrid echo
393         terminal
394      */
395     for (i = 0;  i < samples;  i++)
396     {
397         in1 = input1[i];
398         in2 = input2[i];
399 
400         /* Near end analogue sections */
401         /* Echo from each terminal's CO hybrid */
402         tmp1 = in1 + s->fout2*s->line1.near_co_hybrid_echo;
403         tmp2 = in2 + s->fout1*s->line2.near_co_hybrid_echo;
404 
405         /* Line model filters & noise */
406         s->fout1 = calc_near_line_filter(&s->line1, tmp1);
407         s->fout2 = calc_near_line_filter(&s->line2, tmp2);
408 
409         /* Long distance digital section */
410 
411         /* Introduce distortion due to A-law or u-law munging. */
412         amp[0] = s->fout1;
413         codec_munge(s->line1.munge, amp, 1);
414         s->fout1 = amp[0];
415 
416         amp[0] = s->fout2;
417         codec_munge(s->line2.munge, amp, 1);
418         s->fout2 = amp[0];
419 
420         /* Introduce the bulk delay of the long distance digital link. */
421         out1 = s->line1.bulk_delay_buf[s->line1.bulk_delay_ptr];
422         s->line1.bulk_delay_buf[s->line1.bulk_delay_ptr] = s->fout1;
423         s->fout1 = out1;
424         if (++s->line1.bulk_delay_ptr >= s->line1.bulk_delay)
425             s->line1.bulk_delay_ptr = 0;
426 
427         out2 = s->line2.bulk_delay_buf[s->line2.bulk_delay_ptr];
428         s->line2.bulk_delay_buf[s->line2.bulk_delay_ptr] = s->fout2;
429         s->fout2 = out2;
430         if (++s->line2.bulk_delay_ptr >= s->line2.bulk_delay)
431             s->line2.bulk_delay_ptr = 0;
432 
433         /* Far end analogue sections */
434 
435         /* Echo from each terminal's own hybrid */
436         out1 += in2*s->line1.far_cpe_hybrid_echo;
437         out2 += in1*s->line2.far_cpe_hybrid_echo;
438 
439         /* Line model filters & noise */
440         out1 = calc_far_line_filter(&s->line1, out1);
441         out2 = calc_far_line_filter(&s->line2, out2);
442 
443         output1[i] = fsaturate(out1 + s->line1.dc_offset);
444         output2[i] = fsaturate(out2 + s->line2.dc_offset);
445     }
446 }
447 /*- End of function --------------------------------------------------------*/
448 
both_ways_line_model_set_dc(both_ways_line_model_state_t * s,float dc1,float dc2)449 SPAN_DECLARE(void) both_ways_line_model_set_dc(both_ways_line_model_state_t *s, float dc1, float dc2)
450 {
451     s->line1.dc_offset = dc1;
452     s->line2.dc_offset = dc2;
453 }
454 /*- End of function --------------------------------------------------------*/
455 
both_ways_line_model_set_mains_pickup(both_ways_line_model_state_t * s,int f,float level1,float level2)456 SPAN_DECLARE(void) both_ways_line_model_set_mains_pickup(both_ways_line_model_state_t *s, int f, float level1, float level2)
457 {
458     tone_gen_descriptor_t mains_tone_desc;
459 
460     if (f)
461     {
462         tone_gen_descriptor_init(&mains_tone_desc, f, (int) (level1 - 10.0f), f*3, (int) level1, 1, 0, 0, 0, true);
463         tone_gen_init(&s->line1.mains_tone, &mains_tone_desc);
464         tone_gen_descriptor_init(&mains_tone_desc, f, (int) (level2 - 10.0f), f*3, (int) level2, 1, 0, 0, 0, true);
465         tone_gen_init(&s->line2.mains_tone, &mains_tone_desc);
466     }
467     s->line1.mains_interference = f;
468     s->line2.mains_interference = f;
469 }
470 /*- End of function --------------------------------------------------------*/
471 
one_way_line_model_init(int model,float noise,int codec,int rbs_pattern)472 SPAN_DECLARE(one_way_line_model_state_t *) one_way_line_model_init(int model, float noise, int codec, int rbs_pattern)
473 {
474     one_way_line_model_state_t *s;
475 
476     if ((s = (one_way_line_model_state_t *) malloc(sizeof(*s))) == NULL)
477         return NULL;
478     memset(s, 0, sizeof(*s));
479 
480     s->bulk_delay = 8;
481     s->bulk_delay_ptr = 0;
482 
483     s->munge = codec_munge_init(codec, rbs_pattern);
484 
485     s->near_filter = line_models[model];
486     s->near_filter_len = 129;
487 
488     s->far_filter = line_models[model];
489     s->far_filter_len = 129;
490 
491     /* Put half the noise in each analogue section */
492     awgn_init_dbm0(&s->near_noise, 1234567, noise - 3.02f);
493     awgn_init_dbm0(&s->far_noise, 1234567, noise - 3.02f);
494 
495     s->dc_offset = 0.0f;
496     s->mains_interference = 0;
497 
498     return s;
499 }
500 /*- End of function --------------------------------------------------------*/
501 
one_way_line_model_free(one_way_line_model_state_t * s)502 SPAN_DECLARE(int) one_way_line_model_free(one_way_line_model_state_t *s)
503 {
504     codec_munge_free(s->munge);
505     free(s);
506     return 0;
507 }
508 /*- End of function --------------------------------------------------------*/
509 
both_ways_line_model_init(int model1,float noise1,float echo_level_cpe1,float echo_level_co1,int model2,float noise2,float echo_level_cpe2,float echo_level_co2,int codec,int rbs_pattern)510 SPAN_DECLARE(both_ways_line_model_state_t *) both_ways_line_model_init(int model1,
511                                                                        float noise1,
512                                                                        float echo_level_cpe1,
513                                                                        float echo_level_co1,
514                                                                        int model2,
515                                                                        float noise2,
516                                                                        float echo_level_cpe2,
517                                                                        float echo_level_co2,
518                                                                        int codec,
519                                                                        int rbs_pattern)
520 {
521     both_ways_line_model_state_t *s;
522 
523     if ((s = (both_ways_line_model_state_t *) malloc(sizeof(*s))) == NULL)
524         return NULL;
525     memset(s, 0, sizeof(*s));
526 
527     s->line1.munge = codec_munge_init(codec, rbs_pattern);
528     s->line2.munge = codec_munge_init(codec, rbs_pattern);
529 
530     s->line1.bulk_delay = 8;
531     s->line2.bulk_delay = 8;
532 
533     s->line1.bulk_delay_ptr = 0;
534     s->line2.bulk_delay_ptr = 0;
535 
536     s->line1.near_filter = line_models[model1];
537     s->line1.near_filter_len = 129;
538     s->line2.near_filter = line_models[model2];
539     s->line2.near_filter_len = 129;
540 
541     s->line1.far_filter = line_models[model1];
542     s->line1.far_filter_len = 129;
543     s->line2.far_filter = line_models[model2];
544     s->line2.far_filter_len = 129;
545 
546     /* Put half the noise in each analogue section */
547     awgn_init_dbm0(&s->line1.near_noise, 1234567, noise1 - 3.02f);
548     awgn_init_dbm0(&s->line2.near_noise, 7654321, noise2 - 3.02f);
549 
550     awgn_init_dbm0(&s->line1.far_noise, 1234567, noise1 - 3.02f);
551     awgn_init_dbm0(&s->line2.far_noise, 7654321, noise2 - 3.02f);
552 
553     s->line1.dc_offset = 0.0f;
554     s->line2.dc_offset = 0.0f;
555     s->line1.mains_interference = 0;
556     s->line2.mains_interference = 0;
557 
558     /* Echos */
559     s->line1.near_co_hybrid_echo = pow(10, echo_level_co1/20.0f);
560     s->line2.near_co_hybrid_echo = pow(10, echo_level_co2/20.0f);
561     s->line1.near_cpe_hybrid_echo = pow(10, echo_level_cpe1/20.0f);
562     s->line2.near_cpe_hybrid_echo = pow(10, echo_level_cpe2/20.0f);
563 
564     return s;
565 }
566 /*- End of function --------------------------------------------------------*/
567 
both_ways_line_model_free(both_ways_line_model_state_t * s)568 SPAN_DECLARE(int) both_ways_line_model_free(both_ways_line_model_state_t *s)
569 {
570     codec_munge_free(s->line1.munge);
571     codec_munge_free(s->line2.munge);
572     free(s);
573     return 0;
574 }
575 /*- End of function --------------------------------------------------------*/
576 /*- End of file ------------------------------------------------------------*/
577