如何用scipy和lfilter来实时过滤?

问题描述

免责声明:我可能不太擅长DSP,因此遇到的问题比让此代码正常工作更多。

我需要在传入信号发生时对其进行过滤发送。我试图让这段代码工作,但到目前为止我还没能做到。 引用scipy.signal.lfilter doc

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

samples = 100
x = np.linspace(0, 7, samples)
y = [] # Unfiltered output
y_filt1 = [] # Real-time filtered

nyq = 0.5 * samples
f1_norm = 0.1 / nyq
f2_norm = 2 / nyq
b, a = scipy.signal.butter(2, [f1_norm, f2_norm], 'band', analog=False)
zi = scipy.signal.lfilter_zi(b,a)
zi = zi*(np.sin(0) + 0.1*np.sin(15*0))

这将zi初始设置为zi*y[0 ],在本例中为0。我是从lfilter文档中的示例代码中获得的,但我根本不确定这是否正确。

然后到了我不确定如何处理为数不多的初始样本的时候。 这里的系数ablen(a) = 5。 由于lfilter采用从现在到n-4的输入值,我是用零填充它,还是需要等到5个样本经过后将它们作为一个块,然后以同样的方式连续采样下一步?

for i in range(0, len(a)-1): # Append 0 as initial values, wrong?
    y.append(0)

step = 0
for i in xrange(0, samples): #x:
    tmp = np.sin(x[i]) + 0.1*np.sin(15*x[i])
    y.append(tmp)

    # What to do with the inital filterings until len(y) ==  len(a) ?

    if (step> len(a)):
        y_filt, zi = scipy.signal.lfilter(b, a, y[-len(a):], axis=-1, zi=zi)
        y_filt1.append(y_filt[4])

print(len(y))
y = y[4:]
print(len(y))
y_filt2 = scipy.signal.lfilter(b, a, y) # Offline filtered

plt.plot(x, y, x, y_filt1, x, y_filt2)
plt.show()

解决方案

我想我遇到了同样的问题,并在https://github.com/scipy/scipy/issues/5116上找到了解决方案:

from scipy import zeros, signal, random

def filter_sbs():
    data = random.random(2000)
    b = signal.firwin(150, 0.004)
    z = signal.lfilter_zi(b, 1) * data[0]
    result = zeros(data.size)
    for i, x in enumerate(data):
        result[i], z = signal.lfilter(b, 1, [x], zi=z)
    return result

if __name__ == '__main__':
    result = filter_sbs()

其想法是在随后的每个调用中将过滤状态z传递给lfilter。对于前几个示例,过滤可能会给出奇怪的结果,但稍后(取决于过滤的长度)它会开始正常运行。

相关文章