优化IIR滤波器

lea*_*vst 3 c c++ optimization signal-processing filter

与IIR滤波器系数有关的快速问题.这是我在网上找到的直接形式II双二阶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;
}
Run Code Online (Sandbox Code Playgroud)

据我所知,"寄存器"在某种程度上是不必要的,因为现代编译器的智能程度如何.我的问题是,将滤波器系数存储在单个变量中而不是使用数组并取消引用这些值是否有任何潜在的性能优势?这个问题的答案是否取决于目标平台?

out[i] = b[1]*m[1] + b[2]*m[2] + b[0]*w;
Run Code Online (Sandbox Code Playgroud)

out[i] = b1*m1 + b2*m2 + b0*w;
Run Code Online (Sandbox Code Playgroud)

Ale*_*Sin 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]  
Run Code Online (Sandbox Code Playgroud)

请注意,我添加了几行来输出结果,这样我就确保编译器不会优化所有内容.这是代码:

#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;
}
Run Code Online (Sandbox Code Playgroud)