| 5 | 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. | 
|  | 26  * | 
|  | 27  * $Id: echo.h,v 1.9 2006/10/24 13:45:28 steveu Exp $ | 
|  | 28  */ | 
|  | 29 | 
|  | 30 /*! \file */ | 
|  | 31 | 
|  | 32 #if !defined(_ECHO_H_) | 
|  | 33 #define _ECHO_H_ | 
|  | 34 | 
|  | 35 /*! \page echo_can_page Line echo cancellation for voice | 
|  | 36 | 
|  | 37 \section echo_can_page_sec_1 What does it do? | 
|  | 38 This module aims to provide G.168-2002 compliant echo cancellation, to remove | 
|  | 39 electrical echoes (e.g. from 2-4 wire hybrids) from voice calls. | 
|  | 40 | 
|  | 41 \section echo_can_page_sec_2 How does it work? | 
|  | 42 The heart of the echo cancellor is FIR filter. This is adapted to match the echo | 
|  | 43 impulse response of the telephone line. It must be long enough to adequately cover | 
|  | 44 the duration of that impulse response. The signal transmitted to the telephone line | 
|  | 45 is passed through the FIR filter. Once the FIR is properly adapted, the resulting | 
|  | 46 output is an estimate of the echo signal received from the line. This is subtracted | 
|  | 47 from the received signal. The result is an estimate of the signal which originated | 
|  | 48 at the far end of the line, free from echos of our own transmitted signal. | 
|  | 49 | 
|  | 50 The least mean squares (LMS) algorithm is attributed to Widrow and Hoff, and was | 
|  | 51 introduced in 1960. It is the commonest form of filter adaption used in things | 
|  | 52 like modem line equalisers and line echo cancellers. There it works very well. | 
|  | 53 However, it only works well for signals of constant amplitude. It works very poorly | 
|  | 54 for things like speech echo cancellation, where the signal level varies widely. | 
|  | 55 This is quite easy to fix. If the signal level is normalised - similar to applying | 
|  | 56 AGC - LMS can work as well for a signal of varying amplitude as it does for a modem | 
|  | 57 signal. This normalised least mean squares (NLMS) algorithm is the commonest one used | 
|  | 58 for speech echo cancellation. Many other algorithms exist - e.g. RLS (essentially | 
|  | 59 the same as Kalman filtering), FAP, etc. Some perform significantly better than NLMS. | 
|  | 60 However, factors such as computational complexity and patents favour the use of NLMS. | 
|  | 61 | 
|  | 62 A simple refinement to NLMS can improve its performance with speech. NLMS tends | 
|  | 63 to adapt best to the strongest parts of a signal. If the signal is white noise, | 
|  | 64 the NLMS algorithm works very well. However, speech has more low frequency than | 
|  | 65 high frequency content. Pre-whitening (i.e. filtering the signal to flatten | 
|  | 66 its spectrum) the echo signal improves the adapt rate for speech, and ensures the | 
|  | 67 final residual signal is not heavily biased towards high frequencies. A very low | 
|  | 68 complexity filter is adequate for this, so pre-whitening adds little to the | 
|  | 69 compute requirements of the echo canceller. | 
|  | 70 | 
|  | 71 An FIR filter adapted using pre-whitened NLMS performs well, provided certain | 
|  | 72 conditions are met: | 
|  | 73 | 
|  | 74     - The transmitted signal has poor self-correlation. | 
|  | 75     - There is no signal being generated within the environment being cancelled. | 
|  | 76 | 
|  | 77 The difficulty is that neither of these can be guaranteed. | 
|  | 78 | 
|  | 79 If the adaption is performed while transmitting noise (or something fairly noise | 
|  | 80 like, such as voice) the adaption works very well. If the adaption is performed | 
|  | 81 while transmitting something highly correlative (typically narrow band energy | 
|  | 82 such as signalling tones or DTMF), the adaption can go seriously wrong. The reason | 
|  | 83 is there is only one solution for the adaption on a near random signal - the impulse | 
|  | 84 response of the line. For a repetitive signal, there are any number of solutions | 
|  | 85 which converge the adaption, and nothing guides the adaption to choose the generalised | 
|  | 86 one. Allowing an untrained canceller to converge on this kind of narrowband | 
|  | 87 energy probably a good thing, since at least it cancels the tones. Allowing a well | 
|  | 88 converged canceller to continue converging on such energy is just a way to ruin | 
|  | 89 its generalised adaption. A narrowband detector is needed, so adapation can be | 
|  | 90 suspended at appropriate times. | 
|  | 91 | 
|  | 92 The adaption process is based on trying to eliminate the received signal. When | 
|  | 93 there is any signal from within the environment being cancelled it may upset the | 
|  | 94 adaption process. Similarly, if the signal we are transmitting is small, noise | 
|  | 95 may dominate and disturb the adaption process. If we can ensure that the | 
|  | 96 adaption is only performed when we are transmitting a significant signal level, | 
|  | 97 and the environment is not, things will be OK. Clearly, it is easy to tell when | 
|  | 98 we are sending a significant signal. Telling, if the environment is generating a | 
|  | 99 significant signal, and doing it with sufficient speed that the adaption will | 
|  | 100 not have diverged too much more we stop it, is a little harder. | 
|  | 101 | 
|  | 102 The key problem in detecting when the environment is sourcing significant energy | 
|  | 103 is that we must do this very quickly. Given a reasonably long sample of the | 
|  | 104 received signal, there are a number of strategies which may be used to assess | 
|  | 105 whether that signal contains a strong far end component. However, by the time | 
|  | 106 that assessment is complete the far end signal will have already caused major | 
|  | 107 mis-convergence in the adaption process. An assessment algorithm is needed which | 
|  | 108 produces a fairly accurate result from a very short burst of far end energy. | 
|  | 109 | 
|  | 110 \section echo_can_page_sec_3 How do I use it? | 
|  | 111 The echo cancellor processes both the transmit and receive streams sample by | 
|  | 112 sample. The processing function is not declared inline. Unfortunately, | 
|  | 113 cancellation requires many operations per sample, so the call overhead is only a | 
|  | 114 minor burden. | 
|  | 115 */ | 
|  | 116 | 
|  | 117 #include "fir.h" | 
|  | 118 | 
|  | 119 /* Mask bits for the adaption mode */ | 
|  | 120 | 
|  | 121 #define ECHO_CAN_USE_ADAPTION       0x01 | 
|  | 122 #define ECHO_CAN_USE_NLP            0x02 | 
|  | 123 #define ECHO_CAN_USE_CNG            0x04 | 
|  | 124 #define ECHO_CAN_USE_CLIP           0x08 | 
|  | 125 #define ECHO_CAN_USE_TX_HPF         0x10 | 
|  | 126 #define ECHO_CAN_USE_RX_HPF         0x20 | 
|  | 127 #define ECHO_CAN_DISABLE            0x40 | 
|  | 128 | 
|  | 129 /*! | 
|  | 130     G.168 echo canceller descriptor. This defines the working state for a line | 
|  | 131     echo canceller. | 
|  | 132 */ | 
|  | 133 typedef struct | 
|  | 134 { | 
|  | 135     int16_t tx,rx; | 
|  | 136     int16_t clean; | 
|  | 137     int16_t clean_nlp; | 
|  | 138 | 
|  | 139     int nonupdate_dwell; | 
|  | 140     int curr_pos; | 
|  | 141     int taps; | 
|  | 142     int log2taps; | 
|  | 143     int adaption_mode; | 
|  | 144 | 
|  | 145     int cond_met; | 
|  | 146     int32_t Pstates; | 
|  | 147     int16_t adapt; | 
|  | 148     int32_t factor; | 
|  | 149     int16_t shift; | 
|  | 150 | 
|  | 151     /* Average levels and averaging filter states */ | 
|  | 152     int Ltxacc, Lrxacc, Lcleanacc, Lclean_bgacc; | 
|  | 153     int Ltx, Lrx; | 
|  | 154     int Lclean; | 
|  | 155     int Lclean_bg; | 
|  | 156     int Lbgn, Lbgn_acc, Lbgn_upper, Lbgn_upper_acc; | 
|  | 157 | 
|  | 158     /* foreground and background filter states */ | 
|  | 159     fir16_state_t fir_state; | 
|  | 160     fir16_state_t fir_state_bg; | 
|  | 161     int16_t *fir_taps16[2]; | 
|  | 162 | 
|  | 163     /* DC blocking filter states */ | 
|  | 164     int tx_1, tx_2, rx_1, rx_2; | 
|  | 165 | 
|  | 166     /* optional High Pass Filter states */ | 
|  | 167     int32_t xvtx[5], yvtx[5]; | 
|  | 168     int32_t xvrx[5], yvrx[5]; | 
|  | 169 | 
|  | 170     /* Parameters for the optional Hoth noise generator */ | 
|  | 171     int cng_level; | 
|  | 172     int cng_rndnum; | 
|  | 173     int cng_filter; | 
|  | 174 | 
|  | 175     /* snapshot sample of coeffs used for development */ | 
|  | 176     int16_t *snapshot; | 
|  | 177 | 
|  | 178 } echo_can_state_t; | 
|  | 179 | 
|  | 180 /*! Create a voice echo canceller context. | 
|  | 181     \param len The length of the canceller, in samples. | 
|  | 182     \return The new canceller context, or NULL if the canceller could not be created. | 
|  | 183 */ | 
|  | 184 echo_can_state_t *echo_can_create(int len, int adaption_mode); | 
|  | 185 | 
|  | 186 /*! Free a voice echo canceller context. | 
|  | 187     \param ec The echo canceller context. | 
|  | 188 */ | 
|  | 189 void echo_can_free(echo_can_state_t *ec); | 
|  | 190 | 
|  | 191 /*! Flush (reinitialise) a voice echo canceller context. | 
|  | 192     \param ec The echo canceller context. | 
|  | 193 */ | 
|  | 194 void echo_can_flush(echo_can_state_t *ec); | 
|  | 195 | 
|  | 196 /*! Set the adaption mode of a voice echo canceller context. | 
|  | 197     \param ec The echo canceller context. | 
|  | 198     \param adapt The mode. | 
|  | 199 */ | 
|  | 200 void echo_can_adaption_mode(echo_can_state_t *ec, int adaption_mode); | 
|  | 201 | 
|  | 202 void echo_can_snapshot(echo_can_state_t *ec); | 
|  | 203 | 
|  | 204 /*! Process a sample through a voice echo canceller. | 
|  | 205     \param ec The echo canceller context. | 
|  | 206     \param tx The transmitted audio sample. | 
|  | 207     \param rx The received audio sample. | 
|  | 208     \return The clean (echo cancelled) received sample. | 
|  | 209 */ | 
|  | 210 int16_t echo_can_update(echo_can_state_t *ec, int16_t tx, int16_t rx); | 
|  | 211 | 
|  | 212 /*! Process to high pass filter the tx signal. | 
|  | 213     \param ec The echo canceller context. | 
|  | 214     \param tx The transmitted auio sample. | 
|  | 215     \return The HP filtered transmit sample, send this to your D/A. | 
|  | 216 */ | 
|  | 217 int16_t echo_can_hpf_tx(echo_can_state_t *ec, int16_t tx); | 
|  | 218 | 
|  | 219 #endif | 
|  | 220 /*- End of file ------------------------------------------------------------*/ |