1. 程式人生 > >舒適噪聲生成演算法及其實現

舒適噪聲生成演算法及其實現

舒適生成演算法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的訊號,還會對高頻子帶做類似的操作。