IIR 双二阶实时滤波器仅输出噪声

信息处理 无限脉冲响应 即时的 双二阶
2022-02-08 09:12:58

我已经实现了 IIR 滤波器,但它只输出噪声(如调频收音机失谐),我看不出有什么问题。

这是处理函数:

void Filter::process(int size, double *in, double *out)
{
    double xb[2] = { 0, 0 };
    double yb[2] = { 0, 0 };

    for (int n = 0; n < size; n++)
    {
        out[n] = (coeffs->a0 * in[n]) + (coeffs->a1 * xb[0])
               + (coeffs->a2 * xb[1]) - (coeffs->b1 * yb[0])
               - (coeffs->b2 * yb[1]);

        xb[1] = xb[0];
        xb[0] = in[n];
        yb[1] = yb[0];
        yb[0] = out[n];
    }
}

in是 48kHz 采样数据的out缓冲区;是1024 size

系数为FcFs=50048000Q=0.7071

a0:  0.00107054
a1:  0.00214108
a2:  0.00107054
b1:  -1.99572
b2:  0.953753
3个回答

我无法使用您的系数获得稳定的滤波器。您没有说明,但我假设这是一个低通滤波器。在这里使用计算器,我得到:

coeffs = dict(
    a0=0.0010232172047183973,
    a1=0.0020464344094367946,
    a2=0.0010232172047183973,
    b1=-1.9075008174364765,
    b2=0.91159368625535,
)

过滤器代码:

我重铸为转置直接形式 2(不是必需的,但通常推荐用于浮点)为:

def filter_process(input_data):
    zb = [0., 0.]

    output_data = []
    for data in input_data:

        output_data.append(coeffs['a0'] * data + zb[0])
        zb[0] = zb[1] + coeffs['a1'] * data - coeffs['b1'] * output_data[-1]
        zb[1] = coeffs['a2'] * data - coeffs['b2'] * output_data[-1]

    return output_data

测试代码:

import matplotlib.pyplot as plt
import numpy as np

def plot_f(f):
    Fs = 44000
    sample = 1000
    x = np.arange(sample)
    y = np.sin(2 * np.pi * f * x / Fs)
    out_y = np.array(filter_process(y))
    plt.plot(x, out_y)

for freq in (200, 500, 1000):
    plot_f(freq)

plt.show()

结果:

在此处输入图像描述

来自评论的更新:

如果输入和输出缓冲区实际上是同一个缓冲区,那肯定会有问题。当前组织的传递函数在完成将其用作输入之前将新输出写入缓冲区。但这很容易解决:

void Filter::process(int size, double *in, double *out)
{
    double xb[2] = { 0, 0 };
    double yb[2] = { 0, 0 };

    for (int n = 0; n < size; n++)
    {
        double in_n = in[n]
        out[n] = (coeffs->a0 * in_n) + (coeffs->a1 * xb[0])
               + (coeffs->a2 * xb[1]) - (coeffs->b1 * yb[0])
               - (coeffs->b2 * yb[1]);

        xb[1] = xb[0];
        xb[0] = in_n;
        yb[1] = yb[0];
        yb[0] = out[n];
    }
}

看起来你的 a 和 b 系数交换了。反馈项:b0,b1,b2 应该很小(大约 0.00x),a0,a1,a2 的大小可以接近 1 或 2。

状态应该在方法之外声明并成为您的类的成员,因此它们实际上是状态完整的:

class Filter
{
    double xb[2] = { 0, 0 };
    double yb[2] = { 0, 0 };

public:
    void process(int size, double *in, double *out)
    {
        for (int n = 0; n < size; n++)
        {
            out[n] = (coeffs->a0 * in[n]) + (coeffs->a1 * xb[0])
                   + (coeffs->a2 * xb[1]) - (coeffs->b1 * yb[0])
                   - (coeffs->b2 * yb[1]);

            xb[1] = xb[0];
            xb[0] = in[n];
            yb[1] = yb[0];
            yb[0] = out[n];
        }
    }
};