舒適噪聲生成演算法及其實現
舒適生成演算法CNG(comfort noise generation)
舒適噪聲應用在實時語音通訊(VoIP,電話等)場景中,主要解決兩個問題,第一個是減小傳輸資料量,進而減小傳輸頻寬的要求,這是因為50%的時間是沒有語音的,第二個是讓人感覺語音通訊是持續連線的。
隨機數生成
舒適噪聲的生成演算法中用到了隨機數生成演算法,隨機數將會被填充為語音通訊的背景噪聲;這裡分析乘加同餘法實現,該演算法由Lehmer於1951年提出,對任意一個初始值$$x_1$$,偽隨機數序列由下列遞推公式確定:
$$x_{i+1} = a \cdot x_i (modM), \Sigma_{i+1}= \frac{x_{i+1}}{M}, i=1,2,\cdots$$
其中a為常數。
為便於計算機實現,通常取$$M=2^s$$,其中s為計算機中二進位制數的最大可能有效位數,$$x_1=奇數$$, $$a=5^{2k+1}$$,其中k使$$5^{2k+1}$$在計算機上所能容納的最大的整數,
遞推公式如下:
RANDU隨機數產生器有IBM提出
取69096是為了解決乘同餘產生器在三維和三維以上的空間中,所產生的隨機數總是聚集在一些超平面上隨機數序列是關聯的問題。
```
static uint32_t IncreaseSeed(uint32_t* seed) {
seed[0] = (seed[0] * ((int32_t)69069) + 1) & (kMaxSeedUsed - 1);
return seed[0];
}
int16_t WebRtcSpl_RandU(uint32_t* seed) {
return (int16_t)(IncreaseSeed(seed) >> 16);
}
int16_t WebRtcSpl_RandN(uint32_t* seed) {
return kRandNTable[IncreaseSeed(seed) >> 23];
}
// Creates an array of uniformly distributed variables.
int16_t WebRtcSpl_RandUArray(int16_t* vector,
int16_t vector_length,
uint32_t* seed) {
int i;
for (i = 0; i < vector_length; i++) {
vector[i] = WebRtcSpl_RandU(seed);
}
return vector_length;
}
```
舒適噪聲生成實現
1.首先生成隨機數,呼叫前面的隨機數生成演算法,並將其歸一化到正負一之間。
```
// Generate a uniform random array on [0 1]
WebRtcSpl_RandUArray(randW16, PART_LEN, &aec->seed);
for (i = 0; i < PART_LEN; i++) {
rand[i] = ((float)randW16[i]) / 32768;
}
```
2.生成噪聲
抑制低頻噪聲,就是將u[0]之後的都賦值為0.為了對頻域的訊號進行加噪,需要使用尤拉公式,得到實部和虛部分別對應的cos和sin分量值。
```
// Reject LF noise
u[0][0] = 0;
u[0][1] = 0;
for (i = 1; i < PART_LEN1; i++) {
tmp = pi2 * rand[i - 1];
noise = sqrtf(noisePow[i]);
u[i][0] = noise * cosf(tmp);
u[i][1] = -noise * sinf(tmp);
}
u[PART_LEN][1] = 0;
```
3.對分量值進行相乘
為了防止背景噪聲過大,使用了限制因子tmp,該值根據lambda值計算,該值的意義見AEC分析。
```
for (i = 0; i < PART_LEN1; i++) {
// This is the proper weighting to match the background noise power
tmp = sqrtf(WEBRTC_SPL_MAX(1 - lambda[i] * lambda[i], 0));
// tmp = 1 - lambda[i];
efw[0][i] += tmp * u[i][0];
efw[1][i] += tmp * u[i][1];
}
```
如果是寬頻的32KHz的訊號,還會對高頻子帶做類似的操作。