Commit | Line | Data |
---|---|---|
10602db8 DR |
1 | /* |
2 | * SpanDSP - a series of DSP components for telephony | |
3 | * | |
4 | * echo.c - A line echo canceller. This code is being developed | |
5 | * against and partially complies with G168. | |
6 | * | |
7 | * Written by Steve Underwood <steveu@coppice.org> | |
8 | * and David Rowe <david_at_rowetel_dot_com> | |
9 | * | |
10 | * Copyright (C) 2001 Steve Underwood and 2007 David Rowe | |
11 | * | |
12 | * All rights reserved. | |
13 | * | |
14 | * This program is free software; you can redistribute it and/or modify | |
15 | * it under the terms of the GNU General Public License version 2, as | |
16 | * published by the Free Software Foundation. | |
17 | * | |
18 | * This program is distributed in the hope that it will be useful, | |
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
21 | * GNU General Public License for more details. | |
22 | * | |
23 | * You should have received a copy of the GNU General Public License | |
24 | * along with this program; if not, write to the Free Software | |
25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
10602db8 DR |
26 | */ |
27 | ||
28 | #ifndef __ECHO_H | |
29 | #define __ECHO_H | |
30 | ||
56791f0a GKH |
31 | /* |
32 | Line echo cancellation for voice | |
33 | ||
34 | What does it do? | |
10602db8 | 35 | |
10602db8 DR |
36 | This module aims to provide G.168-2002 compliant echo cancellation, to remove |
37 | electrical echoes (e.g. from 2-4 wire hybrids) from voice calls. | |
38 | ||
56791f0a GKH |
39 | |
40 | How does it work? | |
41 | ||
10602db8 DR |
42 | The heart of the echo cancellor is FIR filter. This is adapted to match the |
43 | echo impulse response of the telephone line. It must be long enough to | |
44 | adequately cover the duration of that impulse response. The signal transmitted | |
45 | to the telephone line is passed through the FIR filter. Once the FIR is | |
46 | properly adapted, the resulting output is an estimate of the echo signal | |
47 | received from the line. This is subtracted from the received signal. The result | |
48 | is an estimate of the signal which originated at the far end of the line, free | |
49 | from echos of our own transmitted signal. | |
50 | ||
51 | The least mean squares (LMS) algorithm is attributed to Widrow and Hoff, and | |
52 | was introduced in 1960. It is the commonest form of filter adaption used in | |
53 | things like modem line equalisers and line echo cancellers. There it works very | |
54 | well. However, it only works well for signals of constant amplitude. It works | |
55 | very poorly for things like speech echo cancellation, where the signal level | |
56 | varies widely. This is quite easy to fix. If the signal level is normalised - | |
57 | similar to applying AGC - LMS can work as well for a signal of varying | |
58 | amplitude as it does for a modem signal. This normalised least mean squares | |
59 | (NLMS) algorithm is the commonest one used for speech echo cancellation. Many | |
60 | other algorithms exist - e.g. RLS (essentially the same as Kalman filtering), | |
61 | FAP, etc. Some perform significantly better than NLMS. However, factors such | |
62 | as computational complexity and patents favour the use of NLMS. | |
63 | ||
64 | A simple refinement to NLMS can improve its performance with speech. NLMS tends | |
65 | to adapt best to the strongest parts of a signal. If the signal is white noise, | |
66 | the NLMS algorithm works very well. However, speech has more low frequency than | |
67 | high frequency content. Pre-whitening (i.e. filtering the signal to flatten its | |
68 | spectrum) the echo signal improves the adapt rate for speech, and ensures the | |
69 | final residual signal is not heavily biased towards high frequencies. A very | |
70 | low complexity filter is adequate for this, so pre-whitening adds little to the | |
71 | compute requirements of the echo canceller. | |
72 | ||
73 | An FIR filter adapted using pre-whitened NLMS performs well, provided certain | |
74 | conditions are met: | |
75 | ||
76 | - The transmitted signal has poor self-correlation. | |
77 | - There is no signal being generated within the environment being | |
78 | cancelled. | |
79 | ||
80 | The difficulty is that neither of these can be guaranteed. | |
81 | ||
82 | If the adaption is performed while transmitting noise (or something fairly | |
83 | noise like, such as voice) the adaption works very well. If the adaption is | |
84 | performed while transmitting something highly correlative (typically narrow | |
85 | band energy such as signalling tones or DTMF), the adaption can go seriously | |
86 | wrong. The reason is there is only one solution for the adaption on a near | |
87 | random signal - the impulse response of the line. For a repetitive signal, | |
88 | there are any number of solutions which converge the adaption, and nothing | |
89 | guides the adaption to choose the generalised one. Allowing an untrained | |
90 | canceller to converge on this kind of narrowband energy probably a good thing, | |
91 | since at least it cancels the tones. Allowing a well converged canceller to | |
92 | continue converging on such energy is just a way to ruin its generalised | |
93 | adaption. A narrowband detector is needed, so adapation can be suspended at | |
94 | appropriate times. | |
95 | ||
96 | The adaption process is based on trying to eliminate the received signal. When | |
97 | there is any signal from within the environment being cancelled it may upset | |
98 | the adaption process. Similarly, if the signal we are transmitting is small, | |
99 | noise may dominate and disturb the adaption process. If we can ensure that the | |
100 | adaption is only performed when we are transmitting a significant signal level, | |
101 | and the environment is not, things will be OK. Clearly, it is easy to tell when | |
102 | we are sending a significant signal. Telling, if the environment is generating | |
103 | a significant signal, and doing it with sufficient speed that the adaption will | |
104 | not have diverged too much more we stop it, is a little harder. | |
105 | ||
106 | The key problem in detecting when the environment is sourcing significant | |
107 | energy is that we must do this very quickly. Given a reasonably long sample of | |
108 | the received signal, there are a number of strategies which may be used to | |
109 | assess whether that signal contains a strong far end component. However, by the | |
110 | time that assessment is complete the far end signal will have already caused | |
111 | major mis-convergence in the adaption process. An assessment algorithm is | |
112 | needed which produces a fairly accurate result from a very short burst of far | |
113 | end energy. | |
114 | ||
56791f0a GKH |
115 | How do I use it? |
116 | ||
10602db8 DR |
117 | The echo cancellor processes both the transmit and receive streams sample by |
118 | sample. The processing function is not declared inline. Unfortunately, | |
119 | cancellation requires many operations per sample, so the call overhead is only | |
120 | a minor burden. | |
121 | */ | |
122 | ||
123 | #include "fir.h" | |
17f8c114 | 124 | #include "oslec.h" |
10602db8 | 125 | |
56791f0a | 126 | /* |
10602db8 DR |
127 | G.168 echo canceller descriptor. This defines the working state for a line |
128 | echo canceller. | |
129 | */ | |
4460a860 M |
130 | struct oslec_state { |
131 | int16_t tx, rx; | |
10602db8 DR |
132 | int16_t clean; |
133 | int16_t clean_nlp; | |
134 | ||
135 | int nonupdate_dwell; | |
136 | int curr_pos; | |
137 | int taps; | |
138 | int log2taps; | |
139 | int adaption_mode; | |
140 | ||
141 | int cond_met; | |
142 | int32_t Pstates; | |
143 | int16_t adapt; | |
144 | int32_t factor; | |
145 | int16_t shift; | |
146 | ||
147 | /* Average levels and averaging filter states */ | |
148 | int Ltxacc, Lrxacc, Lcleanacc, Lclean_bgacc; | |
149 | int Ltx, Lrx; | |
150 | int Lclean; | |
151 | int Lclean_bg; | |
152 | int Lbgn, Lbgn_acc, Lbgn_upper, Lbgn_upper_acc; | |
153 | ||
154 | /* foreground and background filter states */ | |
c82895b8 M |
155 | struct fir16_state_t fir_state; |
156 | struct fir16_state_t fir_state_bg; | |
10602db8 DR |
157 | int16_t *fir_taps16[2]; |
158 | ||
159 | /* DC blocking filter states */ | |
160 | int tx_1, tx_2, rx_1, rx_2; | |
161 | ||
162 | /* optional High Pass Filter states */ | |
163 | int32_t xvtx[5], yvtx[5]; | |
164 | int32_t xvrx[5], yvrx[5]; | |
165 | ||
166 | /* Parameters for the optional Hoth noise generator */ | |
167 | int cng_level; | |
168 | int cng_rndnum; | |
169 | int cng_filter; | |
170 | ||
171 | /* snapshot sample of coeffs used for development */ | |
172 | int16_t *snapshot; | |
17f8c114 | 173 | }; |
10602db8 | 174 | |
4460a860 | 175 | #endif /* __ECHO_H */ |