1*82c29810SThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-only */ 26e2055a9SGreg Kroah-Hartman /* 36e2055a9SGreg Kroah-Hartman * SpanDSP - a series of DSP components for telephony 46e2055a9SGreg Kroah-Hartman * 56e2055a9SGreg Kroah-Hartman * echo.c - A line echo canceller. This code is being developed 66e2055a9SGreg Kroah-Hartman * against and partially complies with G168. 76e2055a9SGreg Kroah-Hartman * 86e2055a9SGreg Kroah-Hartman * Written by Steve Underwood <steveu@coppice.org> 96e2055a9SGreg Kroah-Hartman * and David Rowe <david_at_rowetel_dot_com> 106e2055a9SGreg Kroah-Hartman * 116e2055a9SGreg Kroah-Hartman * Copyright (C) 2001 Steve Underwood and 2007 David Rowe 126e2055a9SGreg Kroah-Hartman * 136e2055a9SGreg Kroah-Hartman * All rights reserved. 146e2055a9SGreg Kroah-Hartman */ 156e2055a9SGreg Kroah-Hartman 166e2055a9SGreg Kroah-Hartman #ifndef __ECHO_H 176e2055a9SGreg Kroah-Hartman #define __ECHO_H 186e2055a9SGreg Kroah-Hartman 196e2055a9SGreg Kroah-Hartman /* 206e2055a9SGreg Kroah-Hartman Line echo cancellation for voice 216e2055a9SGreg Kroah-Hartman 226e2055a9SGreg Kroah-Hartman What does it do? 236e2055a9SGreg Kroah-Hartman 246e2055a9SGreg Kroah-Hartman This module aims to provide G.168-2002 compliant echo cancellation, to remove 256e2055a9SGreg Kroah-Hartman electrical echoes (e.g. from 2-4 wire hybrids) from voice calls. 266e2055a9SGreg Kroah-Hartman 276e2055a9SGreg Kroah-Hartman How does it work? 286e2055a9SGreg Kroah-Hartman 296e2055a9SGreg Kroah-Hartman The heart of the echo cancellor is FIR filter. This is adapted to match the 306e2055a9SGreg Kroah-Hartman echo impulse response of the telephone line. It must be long enough to 316e2055a9SGreg Kroah-Hartman adequately cover the duration of that impulse response. The signal transmitted 326e2055a9SGreg Kroah-Hartman to the telephone line is passed through the FIR filter. Once the FIR is 336e2055a9SGreg Kroah-Hartman properly adapted, the resulting output is an estimate of the echo signal 346e2055a9SGreg Kroah-Hartman received from the line. This is subtracted from the received signal. The result 356e2055a9SGreg Kroah-Hartman is an estimate of the signal which originated at the far end of the line, free 366e2055a9SGreg Kroah-Hartman from echos of our own transmitted signal. 376e2055a9SGreg Kroah-Hartman 386e2055a9SGreg Kroah-Hartman The least mean squares (LMS) algorithm is attributed to Widrow and Hoff, and 396e2055a9SGreg Kroah-Hartman was introduced in 1960. It is the commonest form of filter adaption used in 406e2055a9SGreg Kroah-Hartman things like modem line equalisers and line echo cancellers. There it works very 416e2055a9SGreg Kroah-Hartman well. However, it only works well for signals of constant amplitude. It works 426e2055a9SGreg Kroah-Hartman very poorly for things like speech echo cancellation, where the signal level 436e2055a9SGreg Kroah-Hartman varies widely. This is quite easy to fix. If the signal level is normalised - 446e2055a9SGreg Kroah-Hartman similar to applying AGC - LMS can work as well for a signal of varying 456e2055a9SGreg Kroah-Hartman amplitude as it does for a modem signal. This normalised least mean squares 466e2055a9SGreg Kroah-Hartman (NLMS) algorithm is the commonest one used for speech echo cancellation. Many 476e2055a9SGreg Kroah-Hartman other algorithms exist - e.g. RLS (essentially the same as Kalman filtering), 486e2055a9SGreg Kroah-Hartman FAP, etc. Some perform significantly better than NLMS. However, factors such 496e2055a9SGreg Kroah-Hartman as computational complexity and patents favour the use of NLMS. 506e2055a9SGreg Kroah-Hartman 516e2055a9SGreg Kroah-Hartman A simple refinement to NLMS can improve its performance with speech. NLMS tends 526e2055a9SGreg Kroah-Hartman to adapt best to the strongest parts of a signal. If the signal is white noise, 536e2055a9SGreg Kroah-Hartman the NLMS algorithm works very well. However, speech has more low frequency than 546e2055a9SGreg Kroah-Hartman high frequency content. Pre-whitening (i.e. filtering the signal to flatten its 556e2055a9SGreg Kroah-Hartman spectrum) the echo signal improves the adapt rate for speech, and ensures the 566e2055a9SGreg Kroah-Hartman final residual signal is not heavily biased towards high frequencies. A very 576e2055a9SGreg Kroah-Hartman low complexity filter is adequate for this, so pre-whitening adds little to the 586e2055a9SGreg Kroah-Hartman compute requirements of the echo canceller. 596e2055a9SGreg Kroah-Hartman 606e2055a9SGreg Kroah-Hartman An FIR filter adapted using pre-whitened NLMS performs well, provided certain 616e2055a9SGreg Kroah-Hartman conditions are met: 626e2055a9SGreg Kroah-Hartman 636e2055a9SGreg Kroah-Hartman - The transmitted signal has poor self-correlation. 646e2055a9SGreg Kroah-Hartman - There is no signal being generated within the environment being 656e2055a9SGreg Kroah-Hartman cancelled. 666e2055a9SGreg Kroah-Hartman 676e2055a9SGreg Kroah-Hartman The difficulty is that neither of these can be guaranteed. 686e2055a9SGreg Kroah-Hartman 696e2055a9SGreg Kroah-Hartman If the adaption is performed while transmitting noise (or something fairly 706e2055a9SGreg Kroah-Hartman noise like, such as voice) the adaption works very well. If the adaption is 716e2055a9SGreg Kroah-Hartman performed while transmitting something highly correlative (typically narrow 726e2055a9SGreg Kroah-Hartman band energy such as signalling tones or DTMF), the adaption can go seriously 736e2055a9SGreg Kroah-Hartman wrong. The reason is there is only one solution for the adaption on a near 746e2055a9SGreg Kroah-Hartman random signal - the impulse response of the line. For a repetitive signal, 756e2055a9SGreg Kroah-Hartman there are any number of solutions which converge the adaption, and nothing 766e2055a9SGreg Kroah-Hartman guides the adaption to choose the generalised one. Allowing an untrained 776e2055a9SGreg Kroah-Hartman canceller to converge on this kind of narrowband energy probably a good thing, 786e2055a9SGreg Kroah-Hartman since at least it cancels the tones. Allowing a well converged canceller to 796e2055a9SGreg Kroah-Hartman continue converging on such energy is just a way to ruin its generalised 806e2055a9SGreg Kroah-Hartman adaption. A narrowband detector is needed, so adapation can be suspended at 816e2055a9SGreg Kroah-Hartman appropriate times. 826e2055a9SGreg Kroah-Hartman 836e2055a9SGreg Kroah-Hartman The adaption process is based on trying to eliminate the received signal. When 846e2055a9SGreg Kroah-Hartman there is any signal from within the environment being cancelled it may upset 856e2055a9SGreg Kroah-Hartman the adaption process. Similarly, if the signal we are transmitting is small, 866e2055a9SGreg Kroah-Hartman noise may dominate and disturb the adaption process. If we can ensure that the 876e2055a9SGreg Kroah-Hartman adaption is only performed when we are transmitting a significant signal level, 886e2055a9SGreg Kroah-Hartman and the environment is not, things will be OK. Clearly, it is easy to tell when 896e2055a9SGreg Kroah-Hartman we are sending a significant signal. Telling, if the environment is generating 906e2055a9SGreg Kroah-Hartman a significant signal, and doing it with sufficient speed that the adaption will 916e2055a9SGreg Kroah-Hartman not have diverged too much more we stop it, is a little harder. 926e2055a9SGreg Kroah-Hartman 936e2055a9SGreg Kroah-Hartman The key problem in detecting when the environment is sourcing significant 946e2055a9SGreg Kroah-Hartman energy is that we must do this very quickly. Given a reasonably long sample of 956e2055a9SGreg Kroah-Hartman the received signal, there are a number of strategies which may be used to 966e2055a9SGreg Kroah-Hartman assess whether that signal contains a strong far end component. However, by the 976e2055a9SGreg Kroah-Hartman time that assessment is complete the far end signal will have already caused 986e2055a9SGreg Kroah-Hartman major mis-convergence in the adaption process. An assessment algorithm is 996e2055a9SGreg Kroah-Hartman needed which produces a fairly accurate result from a very short burst of far 1006e2055a9SGreg Kroah-Hartman end energy. 1016e2055a9SGreg Kroah-Hartman 1026e2055a9SGreg Kroah-Hartman How do I use it? 1036e2055a9SGreg Kroah-Hartman 1046e2055a9SGreg Kroah-Hartman The echo cancellor processes both the transmit and receive streams sample by 1056e2055a9SGreg Kroah-Hartman sample. The processing function is not declared inline. Unfortunately, 1066e2055a9SGreg Kroah-Hartman cancellation requires many operations per sample, so the call overhead is only 1076e2055a9SGreg Kroah-Hartman a minor burden. 1086e2055a9SGreg Kroah-Hartman */ 1096e2055a9SGreg Kroah-Hartman 1106e2055a9SGreg Kroah-Hartman #include "fir.h" 1116e2055a9SGreg Kroah-Hartman #include "oslec.h" 1126e2055a9SGreg Kroah-Hartman 1136e2055a9SGreg Kroah-Hartman /* 1146e2055a9SGreg Kroah-Hartman G.168 echo canceller descriptor. This defines the working state for a line 1156e2055a9SGreg Kroah-Hartman echo canceller. 1166e2055a9SGreg Kroah-Hartman */ 1176e2055a9SGreg Kroah-Hartman struct oslec_state { 1186e2055a9SGreg Kroah-Hartman int16_t tx; 1196e2055a9SGreg Kroah-Hartman int16_t rx; 1206e2055a9SGreg Kroah-Hartman int16_t clean; 1216e2055a9SGreg Kroah-Hartman int16_t clean_nlp; 1226e2055a9SGreg Kroah-Hartman 1236e2055a9SGreg Kroah-Hartman int nonupdate_dwell; 1246e2055a9SGreg Kroah-Hartman int curr_pos; 1256e2055a9SGreg Kroah-Hartman int taps; 1266e2055a9SGreg Kroah-Hartman int log2taps; 1276e2055a9SGreg Kroah-Hartman int adaption_mode; 1286e2055a9SGreg Kroah-Hartman 1296e2055a9SGreg Kroah-Hartman int cond_met; 1306e2055a9SGreg Kroah-Hartman int32_t pstates; 1316e2055a9SGreg Kroah-Hartman int16_t adapt; 1326e2055a9SGreg Kroah-Hartman int32_t factor; 1336e2055a9SGreg Kroah-Hartman int16_t shift; 1346e2055a9SGreg Kroah-Hartman 1356e2055a9SGreg Kroah-Hartman /* Average levels and averaging filter states */ 1366e2055a9SGreg Kroah-Hartman int ltxacc; 1376e2055a9SGreg Kroah-Hartman int lrxacc; 1386e2055a9SGreg Kroah-Hartman int lcleanacc; 1396e2055a9SGreg Kroah-Hartman int lclean_bgacc; 1406e2055a9SGreg Kroah-Hartman int ltx; 1416e2055a9SGreg Kroah-Hartman int lrx; 1426e2055a9SGreg Kroah-Hartman int lclean; 1436e2055a9SGreg Kroah-Hartman int lclean_bg; 1446e2055a9SGreg Kroah-Hartman int lbgn; 1456e2055a9SGreg Kroah-Hartman int lbgn_acc; 1466e2055a9SGreg Kroah-Hartman int lbgn_upper; 1476e2055a9SGreg Kroah-Hartman int lbgn_upper_acc; 1486e2055a9SGreg Kroah-Hartman 1496e2055a9SGreg Kroah-Hartman /* foreground and background filter states */ 1506e2055a9SGreg Kroah-Hartman struct fir16_state_t fir_state; 1516e2055a9SGreg Kroah-Hartman struct fir16_state_t fir_state_bg; 1526e2055a9SGreg Kroah-Hartman int16_t *fir_taps16[2]; 1536e2055a9SGreg Kroah-Hartman 1546e2055a9SGreg Kroah-Hartman /* DC blocking filter states */ 1556e2055a9SGreg Kroah-Hartman int tx_1; 1566e2055a9SGreg Kroah-Hartman int tx_2; 1576e2055a9SGreg Kroah-Hartman int rx_1; 1586e2055a9SGreg Kroah-Hartman int rx_2; 1596e2055a9SGreg Kroah-Hartman 1606e2055a9SGreg Kroah-Hartman /* optional High Pass Filter states */ 1616e2055a9SGreg Kroah-Hartman int32_t xvtx[5]; 1626e2055a9SGreg Kroah-Hartman int32_t yvtx[5]; 1636e2055a9SGreg Kroah-Hartman int32_t xvrx[5]; 1646e2055a9SGreg Kroah-Hartman int32_t yvrx[5]; 1656e2055a9SGreg Kroah-Hartman 1666e2055a9SGreg Kroah-Hartman /* Parameters for the optional Hoth noise generator */ 1676e2055a9SGreg Kroah-Hartman int cng_level; 1686e2055a9SGreg Kroah-Hartman int cng_rndnum; 1696e2055a9SGreg Kroah-Hartman int cng_filter; 1706e2055a9SGreg Kroah-Hartman 1716e2055a9SGreg Kroah-Hartman /* snapshot sample of coeffs used for development */ 1726e2055a9SGreg Kroah-Hartman int16_t *snapshot; 1736e2055a9SGreg Kroah-Hartman }; 1746e2055a9SGreg Kroah-Hartman 1756e2055a9SGreg Kroah-Hartman #endif /* __ECHO_H */ 176