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