python中的带通滤波器

时间:2013-04-30 13:49:13

标签: python scipy signal-processing

我正在尝试使用带有128点汉明窗口的带通滤波器,其截止频率为0.7-4Hz。我从图像中获取样本信号。 (1个样本= 1个图像)。 fps经常变化。

如何在python中完成?我读到了这个:http://mpastell.com/2010/01/18/fir-with-scipy/但我觉得很冷静。如何使用此变量fps完成此操作?

3 个答案:

答案 0 :(得分:10)

您可以使用scipy.signal.firwinscipy.signal.firwin2功能创建带通FIR滤波器。您还可以使用scipy.signal.remez

设计FIR滤波器

以下代码提供了一些用于创建带通FIR滤波器的便利包装器。它使用这些来创建与问题中请求的数字相对应的带通滤波器。这假设采样均匀进行。如果采样不均匀,则FIR滤波器不合适。

from scipy.signal import firwin, remez, kaiser_atten, kaiser_beta

# Several flavors of bandpass FIR filters.

def bandpass_firwin(ntaps, lowcut, highcut, fs, window='hamming'):
    nyq = 0.5 * fs
    taps = firwin(ntaps, [lowcut, highcut], nyq=nyq, pass_zero=False,
                  window=window, scale=False)
    return taps

def bandpass_kaiser(ntaps, lowcut, highcut, fs, width):
    nyq = 0.5 * fs
    atten = kaiser_atten(ntaps, width / nyq)
    beta = kaiser_beta(atten)
    taps = firwin(ntaps, [lowcut, highcut], nyq=nyq, pass_zero=False,
                  window=('kaiser', beta), scale=False)
    return taps

def bandpass_remez(ntaps, lowcut, highcut, fs, width):
    delta = 0.5 * width
    edges = [0, lowcut - delta, lowcut + delta,
             highcut - delta, highcut + delta, 0.5*fs]
    taps = remez(ntaps, edges, [0, 1, 0], Hz=fs)
    return taps


if __name__ == "__main__":
    import numpy as np
    import matplotlib.pyplot as plt
    from scipy.signal import freqz

    # Sample rate and desired cutoff frequencies (in Hz).
    fs = 63.0
    lowcut = 0.7
    highcut = 4.0

    ntaps = 128
    taps_hamming = bandpass_firwin(ntaps, lowcut, highcut, fs=fs)
    taps_kaiser16 = bandpass_kaiser(ntaps, lowcut, highcut, fs=fs, width=1.6)
    taps_kaiser10 = bandpass_kaiser(ntaps, lowcut, highcut, fs=fs, width=1.0)
    remez_width = 1.0
    taps_remez = bandpass_remez(ntaps, lowcut, highcut, fs=fs,
                                width=remez_width)

    # Plot the frequency responses of the filters.
    plt.figure(1, figsize=(12, 9))
    plt.clf()

    # First plot the desired ideal response as a green(ish) rectangle.
    rect = plt.Rectangle((lowcut, 0), highcut - lowcut, 1.0,
                         facecolor="#60ff60", alpha=0.2)
    plt.gca().add_patch(rect)

    # Plot the frequency response of each filter.
    w, h = freqz(taps_hamming, 1, worN=2000)
    plt.plot((fs * 0.5 / np.pi) * w, abs(h), label="Hamming window")

    w, h = freqz(taps_kaiser16, 1, worN=2000)
    plt.plot((fs * 0.5 / np.pi) * w, abs(h), label="Kaiser window, width=1.6")

    w, h = freqz(taps_kaiser10, 1, worN=2000)
    plt.plot((fs * 0.5 / np.pi) * w, abs(h), label="Kaiser window, width=1.0")

    w, h = freqz(taps_remez, 1, worN=2000)
    plt.plot((fs * 0.5 / np.pi) * w, abs(h),
             label="Remez algorithm, width=%.1f" % remez_width)

    plt.xlim(0, 8.0)
    plt.ylim(0, 1.1)
    plt.grid(True)
    plt.legend()
    plt.xlabel('Frequency (Hz)')
    plt.ylabel('Gain')
    plt.title('Frequency response of several FIR filters, %d taps' % ntaps)

    plt.show()

这是脚本生成的图。当然,在本地运行脚本更有用,因此您可以放大细节。

plot of frequency responses

答案 1 :(得分:3)

尝试使用不一致的采样率过滤数据非常困难(不可能?)。所以你要做的是:

  1. 以固定采样率创建新信号。固定采样率应为最大采样率或更高。通过设置一个新的“网格”来表示新样本应该去的位置,并从现有数据中插入它们的值。根据您需要的准确程度,存在各种插值方法。线性插值可能不是一个糟糕的起点,但它取决于你在做什么。如果您不确定,请询问https://dsp.stackexchange.com/

  2. 完成后,您可以对信号应用标准信号处理方法,因为样本均匀放置,例如您链接的帖子中描述的那些。

  3. 如有必要,您可能需要再次插值才能恢复原始样本位置。

  4. 如果您只想分析数据,可能会对Lomb Periodigram感兴趣。您可以使用Lomb Periodigram,然后只查看相关频率,或者根据需要对结果进行加权,而不是对数据进行带通然后进行分析。 (另请参阅数字配方系列。第13.8章称为“不均匀间距数据的光谱分析”,这似乎是比维基百科页面更友好的介绍)

答案 2 :(得分:0)

另一种选择是(异步)采样率转换,以便在过滤之前将数据转换为恒定的采样率(例如" gridding")。当然,这只有在您了解采样率时才有效,并且只有在您真正需要过滤数据时才有用(而不仅仅是估算频谱)。

为此目的,例如scipy.interpolate的InterpolatedUnivariateSpline可以逐帧应用,速度非常快。