【rnnoise源碼分析】band能量計算

rnnoise中有個函數compute_band_energy,用於計算band的能量值。這裏有幾個概念需要理清楚。

基本概念

在看源碼之前,我們要弄懂幾個概念,不然還真沒法看下去了。講一下什麼是frequency band和frequency bin。

band

band字面意思是頻率帶,是一組頻率的範圍。大家都知道,音聲都是由頻率的,而頻率範圍很廣。人耳可知的頻率範圍就在20到20000hz。如果這些頻率都參與計算,計算量過大。特別是一些實時系統,希望延遲低,計算量小,爲了減少運算量,同時也根據人耳對低頻敏感,高頻不敏感的特性,不均等的對頻譜作爲劃分,劃分的每一小段就是一個band。

大名鼎鼎的Mel Scale,梅爾劃分,給出了一個公式。
m=2595log10(1+f700) m=2595 * \log10(1+\frac f {700})
它是根據人耳對音高的不同敏感度做劃分的。

之後的 MFCC(梅爾倒譜系數) 就是基於此做出來的:
音頻加窗FFT後,使用Mel濾波器濾波,然後對數運算DCT,得到MFCC。 (這個不是本文討論重點,網上帖子也很多,有需要可自行查閱

rnnoise的前端是參考opus來做的,opus的band劃分是參考bark scale來做的。

bark scale是根據人耳對不同響度來劃分的,bark是劃分了24個band;opus在它的基礎上略微做了調整,增加了低頻部分band的寬度,同時減少了2個band,所以opus scale是22個band。

opus bands

bin

bin的本意是容器,箱子。frequency bin的意思就是FFT的時候將頻率分成的組。
理論上來講,如果我們研究20000hz以內的頻率,理想情況下我們會有20000組,從1hz到20000hz,每一組就是一個bin。
根據Nyquist-Shannon採樣原理,我們至少要做40000hz的採樣。然後觀測時長至少爲1s,那麼最大頻率20000hz纔可以被觀測到。顯然這樣的處理不符合實時系統。

一般實時系統dsp分析的一幀爲10ms(也有20ms,50ms等其他,不討論這個不同),那麼10ms下40000Hz就會有400個sample。這400個sample數據在做fft後會得到200個數據(實際上是201個),這些數據就是bin。說白了就是用200個數據標識1~20000Hz頻率,那麼每個bin代表了20000/200=100個頻率。
即,
第一個bin是1~100
第二個bin是101~200
.……

那你肯定會問了,那bin和band不是一樣嗎,都標識一個範圍。表面上來看是這樣,但是兩者意義不一樣。

band是人爲根據需要做的劃分,它是固定的,不是平均的;而bin是爲了減少計算量,快速實時處理做的妥協,它不是固定的,根據實際情況而定,但是平均的

常量定義

在rnnoise源碼中,定義了eband5ms來表示22個band的常量數組。如下,

static const opus_int16 eband5ms[] = {
/*0  200 400 600 800  1k 1.2 1.4 1.6  2k 2.4 2.8 3.2  4k 4.8 5.6 6.8  8k 9.6 12k 15.6 20k*/
  0,  1,  2,  3,  4,  5,  6,  7,  8, 10, 12, 14, 16, 20, 24, 28, 34, 40, 48, 60, 78, 100
};

上面這22個數字是何含義?

註釋中數字是opus band的劃分
常量數字的設計就有一些彎彎繞了,我上面說了那些個概念,也是爲了闡述這一塊而作鋪墊。
請看我的分析。

rnnoise使用採樣率是48000(可能是偷懶,兼容opus),10ms一幀的採樣,那麼一幀480samples,windows採用的兩倍的幀長,就是960. 這些源碼裏都有,自己看一下。

那麼計算一下bin的大小,計算如下
48000/960=50

ok,那麼現在有bin=50,以及eband5ms裏的兩排數字,請找出他們的關係。(這簡直就是一道公務員考試裏的數學邏輯題嘛)
節約大家時間,我直接寫出答案

bineband5ms[i]4=band[i] bin * eband5ms[i]*4 = band[i]

爲什麼要這樣設計呢?

爲的是實現三角濾波
三角濾波

每個band會被劃分爲兩個相鄰值差*4個頻率點,即

(eband5ms[i+1]-eband5ms[i])<<2

前面9個都是4,後面的會變多,因爲後面的band會寬一些。

能量計算公式
E(k)=X(k)2 E(k) = |X(k)|^2

那麼就那前兩個bin來看,每一個bin被分爲4份。
bin0的4個子頻率能量被按比例累加到Energy 0和 Energy 1中。(Energy 0指的是band0的能量和)
這個比例我們假設爲 w,它是跟band和bin中子頻率k相關。
所以E(b)的計算公式(E(b)就是band b的能量和)如下
E(b)=0kwb(k)X(k)2 E(b) = \displaystyle\sum_0^k w_b(k) |X(k)|^2

函數源碼解析

compute_band_energy源碼如下,基本該說的我都在上面說了。可以一目瞭然了。

void compute_band_energy(float *bandE, const kiss_fft_cpx *X) {
  int i;
  float sum[NB_BANDS] = {0};
  for (i=0;i<NB_BANDS-1;i++)
  {
    int j;
    int band_size;
    band_size = (eband5ms[i+1]-eband5ms[i])<<FRAME_SIZE_SHIFT;
    for (j=0;j<band_size;j++) {
      float tmp;
      float frac = (float)j/band_size;
      tmp = SQUARE(X[(eband5ms[i]<<FRAME_SIZE_SHIFT) + j].r);
      tmp += SQUARE(X[(eband5ms[i]<<FRAME_SIZE_SHIFT) + j].i);
      sum[i] += (1-frac)*tmp;
      sum[i+1] += frac*tmp;
    }
  }
  sum[0] *= 2;
  sum[NB_BANDS-1] *= 2;
  for (i=0;i<NB_BANDS;i++)
  {
    bandE[i] = sum[i];
  }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章