2012-03-21 68 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声明为常量,那么您可能会获益。如果您的任何操作数在编译时已知且已修复,则代码将更有效。