优化IIR滤波器

时间:2012-03-21 22:57:01

标签: c++ c optimization filter signal-processing

与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;
}

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

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

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

3 个答案:

答案 0 :(得分: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;
}

答案 1 :(得分:3)

我不确定,但是这个:

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

可能会更糟,因为它会编译为间接访问,这比直接访问性能更糟糕。

实际看到的唯一方法是检查已编译的汇编程序并分析代码。

答案 2 :(得分:2)

如果可以将系数b0,b1,b2声明为常量,则可能会获益。如果在编译时已知并修复了任何操作数,代码将更有效。