Scipy 黄油过滤器 - 使用高采样率去除 DC 偏移

信息处理 过滤器 Python 数字滤波器 scipy 麻木的
2022-01-29 07:48:36

我很难弄清楚如何使用高通滤波器通过“scipy butter”功能消除数据信号的直流偏移,因为我的采样率非常高。我的问题的症结似乎是我的采样率 Fs 非常高,而我的截止频率非常低(理想情况下只是 DC 偏移分量,但可能是 1 到 10Hz,采样率为 125ksps)。

这是我的示例代码:

import numpy as np
from scipy import signal
import matplotlib.pyplot as plt


# inital parameters
Fs = 125000         # sample rate (if changed to 125sps looks better)
n = 9               # filter order
Fc = 10             # cut off freq (Hz)
Nyq = Fs/2.         # Nyquist freq (1/2 Fs)
Fcc = float(Fc)/float(Nyq)  # normalized cut off freq


# find butterworth xfer functions
sos = signal.butter(n, Fcc, btype='hp', output='sos', analog=False)
# find freq/mag
w, h = signal.sosfreqz(sos, worN=1500, fs=Fs)
#convert to log scale
h_db = 20*np.log10(np.abs(h))

# plot filter response
fig1, ax1 = plt.subplots(1, 1)
ax1.plot(0.5*Fs*(w/np.pi), h_db)
ax1.set_title('db log')
plt.show()

我认为这是按预期工作的,因为将采样率从 125,000 降至 125 会产生看起来合理的响应。我认为我在这里缺少 Fc 与 Fs 的一些基本内容。

这是响应图:

在此处输入图像描述

这是我尝试将此过滤器应用于的数据的屏幕截图:

在此处输入图像描述

如您所见,我想使用高通滤波器从我的数据文件中过滤掉一个 DC 偏移量。现在我只是想让过滤器响应正常运行,所以我还不担心处理数据 - 我只是添加了数据文件截图以供参考。我不需要任何花哨的东西。所以我的问题如下:

  1. 为什么我会有响铃和如此激进的反应?
  2. 低截止频率和高采样率如何影响滤波器响应?
  3. 为什么 Scipy 从 b,butter() 过滤器中的方法转到“sos”?我很好奇他们为什么切换到这种新的 sos 方法。我的理解是它更准确和/或防止 b,a 方法中的错误。我不确定这是否只是将二阶传递函数连接在一起,尽管级联更简单过滤器什么的。
  4. 此外,您可以注意到(如果您打印(w)以查看我的频率轴)我的频率似乎从 0 运行到 2*pi。这是正常的还是应该从0到pi?
  5. 如果问题 #4 是“是的,这应该是 0 到 2*pi”而不是脚本中的第 23 行:

实际上是

ax1.plot(0.5*Fs*(w/(2*np.pi)), h_db)

以便我在最终结果/图中的频率范围从 0 到 1/2*Fs?

谢谢你的帮助!

2个回答

为什么我会有响铃和如此激进的反应?

因为你设计了一个非常激进的过滤器,它是临界不稳定的。所有极点距离单位圆小于 1/1000。

低截止频率和高采样率如何影响滤波器响应?

截止越低,阶数越高,采样率越高,响铃越多(就样本而言)。

为什么 Scipy 从 b,butter() 过滤器中的方法转到“sos”?

因为在传递函数表示中,滤波器实际上是不稳定的,即 64 位浮点的数值精度不足以将该滤波器作为高阶多项式运行。

我很好奇他们为什么切换到这种新的 sos 方法。我的理解是它更准确和/或防止 b,a 方法中的错误。

不不不。传递函数表示是最差的,应避​​免使用极点、零点或二阶部分。一旦进入传递函数,您通常无法回到极点和零点。它需要找到一个高阶多项式的根,这是一个数值定义不明确的问题。

此外,您可以注意到(如果您打印(w)以查看我的频率轴)我的频率似乎从 0 运行到 2*pi。这是正常的还是应该从0到pi?

如果您使用函数,最好阅读文档:https ://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.sosfreqz.html#scipy.signal.sosfreqz

由于您将采样率作为参数传入,因此该函数已经返回频率轴。通过您尝试再次对其进行规范化,您将完全胡说八道。这里的死者放弃是比例因子109在你的频率轴上。当前轴的最高频率为 1.25 GHz。

如果问题 #4 是“是的,这应该是 0 到 2*pi”而不是脚本中的第 23 行:

它应该只是ax1.plot(w, h_db)

你没问的问题:

我应该做什么?

@Ben 所说的:使用一阶滤波器并从信号中减去平均值或用信号平均值播种滤波器状态。

  1. 过滤器的阶数是 9,很高。对于 DC 去除目的,通常使用 1 阶 IIR 滤波器。1 阶 IIR 滤波器不响铃。你可以调α价值,以满足您的需要。H(z)=1z11αz1 您还可以执行 DC 块移除。在这种情况下,只需计算信号的平均值并将其从信号中减去。 https://www.embedded.com/dsp-tricks-dc-removal/

  2. 低截止频率通常意味着较长的瞬态。特别是因为您的滤波器的阶数是 9。更高的采样频率意味着更长的瞬态,即您的滤波器需要更多的样本才能稳定下来。但是,即使您改变采样频率,以秒为单位的稳定时间也应该大致相同。

  3. SOS 表示二阶截面。该滤波器被转换为级联的 2 阶 IIR 滤波器。这些过滤器在数值上更稳定。https://www.dsprelated.com/freebooks/filters/Series_Second_Order_Sections.html

  4. 5 我不是 Scipy 方面的专家。