使用 DSP 减轻极低转角频率低通滤波器的浮点数值误差

信息处理 低通滤波器 无限脉冲响应 浮点
2022-02-19 18:04:26

我正在为数字信号处理应用设计一个低通滤波器,理想情况下它只通过 DC 以上非常小的带宽。我为此使用了 IIR 双二阶滤波器,其中系数是使用此处的说明导出的。较小的带宽会导致较长的过滤时间(较大的时间常数)但会产生更准确的结果,而较大的带宽可以更快地过滤但不太准确。这两个都是有效的用例。

这是我得到的代码

#!/usr/bin/env python
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import freqz

# calculates filter coefficients using link above
# fc is corner frequency, fs is sample freq
def iir_lp_coeffs(fc, fs):
    w0 = 2 * np.pi * fc / fs
    q = 1 / np.sqrt(2)
    alpha = np.sin(w0) / (2 * q)
    b0 = (1 - np.cos(w0)) / 2
    b1 = 1 - np.cos(w0)
    b2 = b0
    a0 = 1 + alpha
    a1 = -2 * np.cos(w0)
    a2 = 1 - alpha
    b0 /= a0
    b1 /= a0
    b2 /= a0
    a1 /= a0
    a2 /= a0
    a0 /= a0
    return (
        np.array([b0, b1, b2], dtype=np.float64),
        np.array([a0, a1, a2], dtype=np.float64),
    )


fc = 2  # low pass corner frequency (Hz)
fsample = 500e3
b, a = iir_lp_coeffs(fc, fsample)

w, h = freqz(b, a, worN=int(1e6), fs=fsample)
fig, ax = plt.subplots()
ax.plot(w, 20 * np.log10(abs(h)))
ax.set_ylim(-40, 10)
ax.set_xscale("log")
plt.show()
print(w[0:10])
print(abs(h[0:10]))

当前设置使用 64 位浮点,截止频率为2Hz. 这一切都很好,只要我增加freqz(with worN=) 的粒度,我什至可以大幅降低拐角频率。

例如,这是上面代码的增益响应图(请注意,我在较高频率处切断了 x 轴):

在此处输入图像描述

但是,我的实际应用程序需要 32 位浮点。当我这样做时(设置dtype为),我在通带iir_lp_coeffsnp.float32获得非统一增益。例如,这是fc=10使用 32 位的增益响应:

在此处输入图像描述

如果我将转角频率设置得更高,增益响应看起来又是正确的(例如,fc=100看起来很好)。

我是否遇到了 32 位 FP 的极限?或者,是否有另一种策略可以让我摆脱 32 位的较低精度?我是否正确将此问题诊断为浮点问题?

2个回答

我认为您的问题可能是系数量化和滤波器拓扑。直接形式的双二阶对 0 和 π 弧度的量化效果较差。在定点上分析这种效果更容易,但即使浮点范围更大,它仍然存在缺点。特别是,如果您将一个非常小的数字添加到一个非常大的数字中,那么这个小数字就会消失,因为它无法在可用尾数位数中进行对齐操作。这可能会导致操作顺序影响结果。例如,如果 S 是一个小数,L 很大,则 L - L + S = S,但 L + S - L = 0。

Udo Zolzer 在他的《数字音频信号处理》一书中介绍了几种滤波器结构之间的差异。我从书中借用了对极点位置的直接形式量化效应:

直接形式量化

看看精度在 0 和 π 附近是如何损失的。其他滤波器拓扑在 0 附近可能具有更高的精度,而在 π 附近则更差,这对于您这样的用途来说可能是一个很好的权衡。Gold 和 Rader 的形式分布非常均匀,看起来像一个完美的网格。

另一种在低频下具有良好量化特性的简单流行滤波器是“Chamberlin”状态变量滤波器。这个滤波器有改进的版本,因为它在更高的频率(从大约六分之一的采样率和更高的频率)有问题,但是普通的张伯林在你需要的低频方面非常好。

请参阅我关于 Chamberlin 状态变量滤波器的文章:

数字状态变量滤波器

Zolzer 在这里展示了修改后的张伯林结构:

改进的 Chamberlin 和 Zölzer 滤波器结构

特别是,请参见 Chamberlin 结构接近零的量化效果图——在接近零时非常密集,与直接形式图相比,高频性能较差:

张伯林量化

对于食谱 LPF,我会使用这个三角标识:

cos(ω0)=12sin2(ω02)

你正在做的是从一中减去一个非常接近一的数字所有信息都在差异中。