我正在为数字信号处理应用设计一个低通滤波器,理想情况下它只通过 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 位浮点,截止频率为. 这一切都很好,只要我增加freqz
(with worN=
) 的粒度,我什至可以大幅降低拐角频率。
例如,这是上面代码的增益响应图(请注意,我在较高频率处切断了 x 轴):
但是,我的实际应用程序需要 32 位浮点。当我这样做时(设置dtype
为),我在通带iir_lp_coeffs
中np.float32
获得非统一增益。例如,这是fc=10
使用 32 位的增益响应:
如果我将转角频率设置得更高,增益响应看起来又是正确的(例如,fc=100
看起来很好)。
我是否遇到了 32 位 FP 的极限?或者,是否有另一种策略可以让我摆脱 32 位的较低精度?我是否正确将此问题诊断为浮点问题?