如何在Python中应用Butterworth带通滤波器后去除信号开头的大尖峰?

4
我想使用带通滤波器去趋势化一个信号。我在Python中使用了FL=0.1 Hz和FH=20 Hz的Butterworth滤波器,但在应用该带通滤波器后,我发现趋势化信号的开头出现了一个大的尖峰。
这个尖峰是什么原因造成的?如何在Python中去除这个尖峰?
您可以使用此链接下载"data1.csv"。 Filtered signal
from scipy.signal import butter, lfilter
from numpy import genfromtxt
import numpy as np
import matplotlib.pyplot as plt

def butter_bandpass(lowcut, highcut, fs, order=5):
    nyq = 0.5 * fs
    low = lowcut / nyq
    high = highcut / nyq
    b, a = butter(order, [low, high], btype='band')
    return b, a

def butter_bandpass_filter(data, lowcut, highcut, fs, order=5):
    b, a = butter_bandpass(lowcut, highcut, fs, order=order)
    y = lfilter(b, a, data)
    return y


BP_without_NaN = genfromtxt('data1.csv', delimiter=',')
framerate=1024

# detrending [0.1Hz  20Hz]
OMW = butter_bandpass_filter(data = BP_without_NaN, lowcut = 0.1, highcut = 20 , fs = framerate, order = 3)

# plot OMW
time = np.linspace(0, len(OMW)/framerate ,len(OMW))
plt.plot(time, OMW)
plt.show()

3
欢迎来到SO! 你目前试过了什么?请添加最小完整可验证示例以便我们可以帮助你! - ti7
1个回答

5

应用Butterworth(或任何IIR)滤波器时,每个输出样本都是基于先前的输出样本计算的。

y[n] = b0 * x[n] + b1 * x[n-1] + ... + bk * x[n-k]
                 - a1 * y[n-1] + ... + ak * y[n-k]

这会导致一个问题,即如何在信号开始时启动过滤器,因为还没有计算出任何输出样本。通常处理这个问题的方法是假设负时间n<0的所有输出都为零,或者等价地将输入概念性地外推为零。这种零初始化方法是scipy.signal.lfilter默认采用的方法。

然而,这种方法并不总是适合。如果输入信号不接近于零,则外推零会在信号中引入人为的阶跃或跳跃间断,并且输出信号将以不想要的瞬态开始,即作为对此人工阶跃的滤波器响应。

enter image description here

根据您提供的数据,输入信号从数值为154的几百个样本开始。这解释了您绘图中的大峰值。您可以通过改变滤波器的初始化来消除峰值。使用scipy.signal.lfilter_zi计算lfilter的初始条件,以使其阶跃响应稳定在值为154的状态:

zi = lfilter_zi(b, a) * data[0]

然后使用lfilter和y, _ = lfilter(b, a, data, zi=zi)一起使用。这是我用这种方法得到的结果:

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接