2012-03-21 71 views
3

與IIR濾波器係數有關的快速問題。這是我在網上找到的一個直接II型II型二進制IIR處理器的非常典型的實現。IIR濾波器的優化

// b0, b1, b2, a1, a2 are filter coefficients 
// m1, m2 are the memory locations 
// dn is the de-denormal coeff (=1.0e-20f) 

void processBiquad(const float* in, float* out, unsigned length) 
{ 
    for(unsigned i = 0; i < length; ++i) 
    { 
     register float w = in[i] - a1*m1 - a2*m2 + dn; 
     out[i] = b1*m1 + b2*m2 + b0*w; 
     m2 = m1; m1 = w; 
    } 
    dn = -dn; 
} 

據我所知,「登記冊」在某種程度上是不必要的,因爲現代編譯器對於這種事物有多聰明。我的問題是,將濾波器係數存儲在單個變量中而不是使用數組和取消引用值有什麼潛在的性能好處?這個問題的答案是否取決於目標平臺?

out[i] = b[1]*m[1] + b[2]*m[2] + b[0]*w; 

out[i] = b1*m1 + b2*m2 + b0*w; 

回答

5

它確實取決於您的編譯器和優化選項。這是我的:

  • 任何現代編譯器會忽略register。這只是編譯器的一個暗示,現代編譯器不會使用它。
  • 在優化編譯時,通常會優化循環訪問循環中的常量索引。從某種意義上講,使用變量或數組顯示沒有區別。
  • 總是運行基準測試,並查看代碼中性能關鍵部分的生成代碼。

編輯:好吧,剛剛出於好奇,我寫了一個小程序,並得到了與VS2010一起使用完全優化時生成的「相同」代碼。下面是我得到的循環中有問題的表達式(這兩種情況下完全相同):

0128138D fmul  dword ptr [eax+0Ch] 
01281390 faddp  st(1),st 
01281392 fld   dword ptr [eax+10h] 
01281395 fld   dword ptr [w] 
01281398 fld   st(0) 
0128139A fmulp  st(2),st 
0128139C fxch  st(2) 
0128139E faddp  st(1),st 
012813A0 fstp  dword ptr [ecx+8] 

注意,我添加了幾行輸出結果讓我要確保編譯器不只是優化掉一切。以下是代碼:

#include <iostream> 
#include <iterator> 
#include <algorithm> 

class test1 
{ 
    float a1, a2, b0, b1, b2; 
    float dn; 
    float m1, m2; 

public: 
    void processBiquad(const float* in, float* out, unsigned length) 
    { 
     for(unsigned i = 0; i < length; ++i) 
     { 
      float w = in[i] - a1*m1 - a2*m2 + dn; 
      out[i] = b1*m1 + b2*m2 + b0*w; 
      m2 = m1; m1 = w; 
     } 
     dn = -dn; 
    } 
}; 

class test2 
{ 
    float a[2], b[3]; 
    float dn; 
    float m1, m2; 

public: 
    void processBiquad(const float* in, float* out, unsigned length) 
    { 
     for(unsigned i = 0; i < length; ++i) 
     { 
      float w = in[i] - a[0]*m1 - a[1]*m2 + dn; 
      out[i] = b[0]*m1 + b[1]*m2 + b[2]*w; 
      m2 = m1; m1 = w; 
     } 
     dn = -dn; 
    } 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    test1 t1; 
    test2 t2; 

    float a[1000]; 
    float b[1000]; 

    t1.processBiquad(a, b, 1000); 
    t2.processBiquad(a, b, 1000); 

    std::copy(b, b+1000, std::ostream_iterator<float>(std::cout, " ")); 

    return 0; 
} 
3

我不知道,但這:

out[i] = b[1]*m[1] + b[2]*m[2] + b[0]*w; 

可能會更糟糕,因爲它會編譯爲間接訪問,這是更糟的是直接訪問性能明智。

實際看到的唯一方法是檢查編譯的彙編程序和配置文件的代碼。

2

如果您可以將係數b0,b1,b2聲明爲常量,那麼您可能會獲益。如果您的任何操作數在編譯時已知且已修復,則代碼將更有效。