comparison spandsp-0.0.6pre17/src/modem_echo.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 * modem_echo.c - An echo cancellor, suitable for electrical echos in GSTN modems
5 *
6 * Written by Steve Underwood <steveu@coppice.org>
7 *
8 * Copyright (C) 2001, 2003, 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 Lesser General Public License version 2.1,
14 * as 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 Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 * $Id: modem_echo.c,v 1.26 2009/09/22 13:11:04 steveu Exp $
26 */
27
28 /*! \file */
29
30 /* The FIR taps must be adapted as 32 bit values, to get the necessary finesse
31 in the adaption process. However, they are applied as 16 bit values (bits 30-15
32 of the 32 bit values) in the FIR. For the working 16 bit values, we need 4 sets.
33 */
34
35 #if defined(HAVE_CONFIG_H)
36 #include "config.h"
37 #endif
38
39 #include <stdlib.h>
40 #include <inttypes.h>
41 #include <string.h>
42 #include <stdio.h>
43 #if defined(HAVE_TGMATH_H)
44 #include <tgmath.h>
45 #endif
46 #if defined(HAVE_MATH_H)
47 #include <math.h>
48 #endif
49 #include "floating_fudge.h"
50
51 #include "spandsp/telephony.h"
52 #include "spandsp/bit_operations.h"
53 #include "spandsp/dc_restore.h"
54 #include "spandsp/modem_echo.h"
55
56 #include "spandsp/private/modem_echo.h"
57
58 SPAN_DECLARE(modem_echo_can_state_t *) modem_echo_can_create(int len)
59 {
60 modem_echo_can_state_t *ec;
61
62 if ((ec = (modem_echo_can_state_t *) malloc(sizeof(*ec))) == NULL)
63 return NULL;
64 memset(ec, 0, sizeof(*ec));
65 ec->taps = len;
66 ec->curr_pos = ec->taps - 1;
67 if ((ec->fir_taps32 = (int32_t *) malloc(ec->taps*sizeof(int32_t))) == NULL)
68 {
69 free(ec);
70 return NULL;
71 }
72 memset(ec->fir_taps32, 0, ec->taps*sizeof(int32_t));
73 if ((ec->fir_taps16 = (int16_t *) malloc(ec->taps*sizeof(int16_t))) == NULL)
74 {
75 free(ec->fir_taps32);
76 free(ec);
77 return NULL;
78 }
79 memset(ec->fir_taps16, 0, ec->taps*sizeof(int16_t));
80 if (fir16_create(&ec->fir_state, ec->fir_taps16, ec->taps) == NULL)
81 {
82 free(ec->fir_taps16);
83 free(ec->fir_taps32);
84 free(ec);
85 return NULL;
86 }
87 return ec;
88 }
89 /*- End of function --------------------------------------------------------*/
90
91 SPAN_DECLARE(void) modem_echo_can_free(modem_echo_can_state_t *ec)
92 {
93 fir16_free(&ec->fir_state);
94 free(ec->fir_taps32);
95 free(ec->fir_taps16);
96 free(ec);
97 }
98 /*- End of function --------------------------------------------------------*/
99
100 SPAN_DECLARE(void) modem_echo_can_flush(modem_echo_can_state_t *ec)
101 {
102 ec->tx_power = 0;
103
104 fir16_flush(&ec->fir_state);
105 ec->fir_state.curr_pos = ec->taps - 1;
106 memset(ec->fir_taps32, 0, ec->taps*sizeof(int32_t));
107 memset(ec->fir_taps16, 0, ec->taps*sizeof(int16_t));
108 ec->curr_pos = ec->taps - 1;
109 }
110 /*- End of function --------------------------------------------------------*/
111
112 SPAN_DECLARE(void) modem_echo_can_adaption_mode(modem_echo_can_state_t *ec, int adapt)
113 {
114 ec->adapt = adapt;
115 }
116 /*- End of function --------------------------------------------------------*/
117
118 SPAN_DECLARE(int16_t) modem_echo_can_update(modem_echo_can_state_t *ec, int16_t tx, int16_t rx)
119 {
120 int32_t echo_value;
121 int clean_rx;
122 int shift;
123 int i;
124 int offset1;
125 int offset2;
126
127 /* Evaluate the echo - i.e. apply the FIR filter */
128 /* Assume the gain of the FIR does not exceed unity. Exceeding unity
129 would seem like a rather poor thing for an echo cancellor to do :)
130 This means we can compute the result with a total disregard for
131 overflows. 16bits x 16bits -> 31bits, so no overflow can occur in
132 any multiply. While accumulating we may overflow and underflow the
133 32 bit scale often. However, if the gain does not exceed unity,
134 everything should work itself out, and the final result will be
135 OK, without any saturation logic. */
136 /* Overflow is very much possible here, and we do nothing about it because
137 of the compute costs */
138 echo_value = fir16(&ec->fir_state, tx);
139
140 /* And the answer is..... */
141 clean_rx = rx - echo_value;
142 //printf("%8d %8d %8d %8d\n", tx, rx, echo_value, clean_rx);
143 if (ec->adapt)
144 {
145 /* Calculate short term power levels using very simple single pole IIRs */
146 /* TODO: Is the nasty modulus approach the fastest, or would a real
147 tx*tx power calculation actually be faster? Using the squares
148 makes the numbers grow a lot! */
149 ec->tx_power += ((tx*tx - ec->tx_power) >> 5);
150
151 shift = 1;
152 /* Update the FIR taps */
153 offset2 = ec->curr_pos;
154 offset1 = ec->taps - offset2;
155 for (i = ec->taps - 1; i >= offset1; i--)
156 {
157 /* Leak to avoid the coefficients drifting beyond the ability of the
158 adaption process to bring them back under control. */
159 ec->fir_taps32[i] -= (ec->fir_taps32[i] >> 23);
160 ec->fir_taps32[i] += (ec->fir_state.history[i - offset1]*clean_rx) >> shift;
161 ec->fir_taps16[i] = (int16_t) (ec->fir_taps32[i] >> 15);
162 }
163 for ( ; i >= 0; i--)
164 {
165 ec->fir_taps32[i] -= (ec->fir_taps32[i] >> 23);
166 ec->fir_taps32[i] += (ec->fir_state.history[i + offset2]*clean_rx) >> shift;
167 ec->fir_taps16[i] = (int16_t) (ec->fir_taps32[i] >> 15);
168 }
169 }
170
171 /* Roll around the rolling buffer */
172 if (ec->curr_pos <= 0)
173 ec->curr_pos = ec->taps;
174 ec->curr_pos--;
175 return (int16_t) clean_rx;
176 }
177 /*- End of function --------------------------------------------------------*/
178 /*- End of file ------------------------------------------------------------*/

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