1. 基於能量的檢測方法
這個能量指的是短時能量,原理就是近端說話的時候,理論上應該聲音能量明顯大於只有回聲的時候。
1.1 GEIGEL算法
把揚聲器輸出的信號與麥克風採集到的信號做能量比較,採集到的信號如果能量高於輸出信號的話,則說明一定有回聲。除非麥克風有放大輸入信號的作用。由於輸入信號和播放信號之間有一定的時延,所以拿當前的輸入信號和一段時間之內(取大於等於時延的最小值)的輸出信號的最大值做對比,如果輸入信號大於這個值,則認爲有double talk。 當然精確的說,應該是取正好是從當前時間向前推時延個時間單位的揚聲器輸出信號和輸入做對比。但。。。GEIGEL木有這麼做。
例子代碼在 https://www.ietf.org/mail-archive/web/avt/current/msg04629.html
int dtdNdx;
/* For Normalized Least Means Square - Pre-whitening */
#define NLMS_LEN (240*8) /* maximum NLMS filter length in taps
#define DTD_LEN 16 // block size in taps to optimize DTD
float max_x[NLMS_LEN/DTD_LEN];
/* Geigel Double-Talk Detector
*
* in d: microphone sample (PCM as floating point value)
* in x: loudspeaker sample (PCM as floating point value)
* return: 0 for no talking, 1 for talking
*/
int dtd(float d, float x);
int AEC::dtd(float d, float x)
{
// optimized implementation of max(|x[0]|, |x[1]|, .., |x[L-1]|):
// calculate max of block (DTD_LEN values)
x = fabsf(x);
if (x > max_x[dtdNdx]) {
max_x[dtdNdx] = x;
if (x > max_max_x) {
max_max_x = x;
}
}
if (++dtdCnt >= DTD_LEN) {
dtdCnt = 0;
// calculate max of max
max_max_x = 0.0f;
for (int i = 0; i < NLMS_LEN/DTD_LEN; ++i) {
if (max_x[i] > max_max_x) {
max_max_x = max_x[i];
}
}
// rotate Ndx
if (++dtdNdx >= NLMS_LEN/DTD_LEN) dtdNdx = 0;
max_x[dtdNdx] = 0.0f;
}
// The Geigel DTD algorithm with Hangover timer Thold
if (fabsf(d) >= GeigelThreshold * max_max_x) {
hangover = Thold;
}
if (hangover) --hangover;
if (max_max_x < UpdateThreshold) {
// avoid update with silence or noise
return 1;
} else {
return (hangover > 0);
}
}`
1.2 基於能量平均的算法
2. 基於信號相關性的檢測方法
利用信號相關度,其實就是算餘弦相似性,計算揚聲器輸出信號,麥克風輸入信號,回聲估計信號之間的相似性計算。若木有dtd時,麥克風輸入信號和回聲估計信號之間的相似度很大,這樣把自適應濾波器的輸入回聲參考信號和輸出回聲估計信號的每一幀的採樣值做兩個矢量,計算他們的夾角。當沒有DTD時,該夾角的餘弦值基本爲1,否則會明顯小於1。可以設定一個閾值,小於該閾值時定義爲DTD狀態。