Numpy Scipy Butter带通无法产生预期的结果

Numpy Scipy Butter带通无法产生预期的结果,numpy,audio,scipy,signal-processing,butterworth,Numpy,Audio,Scipy,Signal Processing,Butterworth,所以我尝试对wav PCM 24位44.1khz文件进行带通滤波。我想做的是从0Hz-22Khz的每个频率带通 到目前为止,我已经加载了数据,可以在Matplot上显示它,如下所示 但是当我去应用从这里得到的带通滤波器时 我得到以下结果: 所以我尝试在100-101Hz的频率下进行带通测试,下面是我的代码: from WaveData import WaveData import matplotlib.pyplot as plt from scipy.signal import butte

所以我尝试对wav PCM 24位44.1khz文件进行带通滤波。我想做的是从0Hz-22Khz的每个频率带通

到目前为止,我已经加载了数据,可以在Matplot上显示它,如下所示

但是当我去应用从这里得到的带通滤波器时

我得到以下结果:

所以我尝试在100-101Hz的频率下进行带通测试,下面是我的代码:

from WaveData import WaveData
import matplotlib.pyplot as plt
from scipy.signal import butter, lfilter, freqz
from scipy.io.wavfile import read
import numpy as np
from WaveData import WaveData

class Filter:
        def __init__(self, wav):
                self.waveData = WaveData(wav)

        def butter_bandpass(self, 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(self, data, lowcut, highcut, fs, order):
                b, a = self.butter_bandpass(lowcut, highcut, fs, order=order)
                y = lfilter(b, a, data)
                return y

        def getFilteredSignal(self, freq):
                return self.butter_bandpass_filter(data=self.waveData.file['Data'], lowcut=100, highcut=101, fs=44100, order=3)

        def getUnprocessedData(self):
            return self.waveData.file['Data']

        def plot(self, signalA, signalB=None):
                plt.plot(signalA)
                if signalB != None:
                        plt.plot(signalB)
                plt.show()

if __name__ == "__main__":
        # file = WaveData("kick.wav")
        # fileA = read("kick0.wav")
        f = Filter("kick.wav")
        a, b = f. butter_bandpass(lowcut=100, highcut=101, fs=44100)
        w, h = freqz(b, a, worN=22000) ##Filted signal is not working?
        f.plot(h, w)
        print("break")
我不明白我哪里出错了


谢谢

因此,您的代码存在一些问题,这意味着您没有正确绘制结果,尽管我相信这不是您的主要问题

检查你的代码 在链接的示例中,它们精确地显示了按不同顺序计算和打印过滤器的过程:

for order in [3, 6, 9]:
    b, a = butter_bandpass(lowcut, highcut, fs, order=order)
    w, h = freqz(b, a, worN=2000)
    plt.plot((fs * 0.5 / np.pi) * w, abs(h), label="order = %d" % order)
您当前没有正确缩放频率轴,或者调用绝对值从
h
获取真实信息,就像上面正确的代码一样

检查你的理论 然而,您的主要问题是您的带通如此陡峭(即只有100Hz-101Hz)。这是非常罕见的,我见过一个如此尖锐的滤波器,因为这是非常处理密集型(将需要大量的滤波器系数),因为你只看1Hz的范围,它将完全摆脱所有其他频率

因此,您所显示的增益为0的图表可能非常正确。如果使用带通截止频率并将其更改为100Hz->101Hz,则输出结果是一个零数组(几乎是,如果不是完全的话)。这是因为它只会在1Hz范围内观察信号的能量,如果你仔细考虑的话,它会非常非常

如果你这样做是为了分析,频率间隔往往更大,即(或更小的倍频带划分)

光谱图 由于我不确定你的最终目的,我无法确切说明你应该走哪条路线到达那里。然而,在这个时代,在每一个频率高达20kHz的频率上使用带通滤波器似乎有点愚蠢


如果我没记错的话,一些在纸上用针的第一次尝试使用模拟带通滤波器组的这种技术来分析频率内容。这让我觉得你可能在寻找与光谱图有关的东西?它允许您分析整个信号的频率信息与时间,并且仍然具有所有信号的振幅信息。Python已经将光谱图功能作为or的一部分

因此,您的代码存在一些问题,这意味着您没有正确地绘制结果,尽管我相信这不是您的主要问题

检查你的代码 在链接的示例中,它们精确地显示了按不同顺序计算和打印过滤器的过程:

for order in [3, 6, 9]:
    b, a = butter_bandpass(lowcut, highcut, fs, order=order)
    w, h = freqz(b, a, worN=2000)
    plt.plot((fs * 0.5 / np.pi) * w, abs(h), label="order = %d" % order)
您当前没有正确缩放频率轴,或者调用绝对值从
h
获取真实信息,就像上面正确的代码一样

检查你的理论 然而,您的主要问题是您的带通如此陡峭(即只有100Hz-101Hz)。这是非常罕见的,我见过一个如此尖锐的滤波器,因为这是非常处理密集型(将需要大量的滤波器系数),因为你只看1Hz的范围,它将完全摆脱所有其他频率

因此,您所显示的增益为0的图表可能非常正确。如果使用带通截止频率并将其更改为100Hz->101Hz,则输出结果是一个零数组(几乎是,如果不是完全的话)。这是因为它只会在1Hz范围内观察信号的能量,如果你仔细考虑的话,它会非常非常

如果你这样做是为了分析,频率间隔往往更大,即(或更小的倍频带划分)

光谱图 由于我不确定你的最终目的,我无法确切说明你应该走哪条路线到达那里。然而,在这个时代,在每一个频率高达20kHz的频率上使用带通滤波器似乎有点愚蠢


如果我没记错的话,一些在纸上用针的第一次尝试使用模拟带通滤波器组的这种技术来分析频率内容。这让我觉得你可能在寻找与光谱图有关的东西?它允许您分析整个信号的频率信息与时间,并且仍然具有所有信号的振幅信息。Python已经将光谱图功能作为or的一部分

@WoodyDev所说的是对的:44.1kHz中的1Hz对于任何类型的滤波器来说都是太小了。只需查看过滤系数
butter
返回:

In [3]: butter(5, [100/(44.1e3/2), 101/(44.1e3/2)], btype='band')
Out[3]:
(array([ 1.83424060e-21,  0.00000000e+00, -9.17120299e-21,  0.00000000e+00,
         1.83424060e-20,  0.00000000e+00, -1.83424060e-20,  0.00000000e+00,
         9.17120299e-21,  0.00000000e+00, -1.83424060e-21]),
 array([   1.        ,   -9.99851389,   44.98765092, -119.95470631,
         209.90388506, -251.87018009,  209.88453023, -119.93258575,
          44.9752074 ,   -9.99482662,    0.99953904]))
查看
b
系数(第一个数组):它们的值在1e-20,这意味着滤波器设计完全无法收敛,如果将其应用于任何信号,输出将为零,这就是您发现的

您没有提到您的应用程序,但如果您真的想将信号的频率内容保持在100和101 Hz之间,您可以对信号进行加零FFT,将频带外的频谱部分调零,然后进行IFFT(查看模块中的
rfft
irfft
,以及
rfftfreq

下面是一个函数,它使用FFT在傅里叶域中应用砖墙带通滤波器:

import numpy.fft as fft
import numpy as np


def fftBandpass(x, low, high, fs=1.0):
    """
    Apply a bandpass signal via FFTs.

    Parameters
    ----------
    x : array_like
        Input signal vector. Assumed to be real-only.
    low : float
        Lower bound of the passband in Hertz. (If less than or equal
        to zero, a high-pass filter is applied.)
    high : float
        Upper bound of the passband, Hertz.
    fs : float
        Sample rate in units of samples per second. If `high > fs / 2`,
        the output is low-pass filtered.

    Returns
    -------
    y : ndarray
        Output signal vector with all frequencies outside the `[low, high]`
        passband zeroed.

    Caveat
    ------
    Note that the energe in `y` will be lower than the energy in `x`, i.e.,
    `sum(abs(y)) < sum(abs(x))`. 
    """
    xf = fft.rfft(x)
    f = fft.rfftfreq(len(x), d=1 / fs)
    xf[f < low] = 0
    xf[f > high] = 0
    return fft.irfft(xf, len(x))


if __name__ == '__main__':
    fs = 44.1e3
    N = int(fs)
    x = np.random.randn(N)
    t = np.arange(N) / fs
    import pylab as plt
    plt.figure()
    plt.plot(t, x, t, 100 * fftBandpass(x, 100, 101, fs=fs))
    plt.xlabel('time (seconds)')
    plt.ylabel('signal')
    plt.legend(['original', 'scaled bandpassed'])
    plt.show()
将numpy.fft导入为fft
将numpy作为np导入
def fftBandpass(x、低、高、fs=1.0):
"""
通过FFT应用带通信号。
参数
----------
x:数组_-like
输入信号向量。假设为仅为实。
低:浮动
以赫兹为单位的通带下限。(如果小于或等于
为零,将应用高通滤波器。)
高:浮动
通带的上限,赫兹。
fs:浮动
采样率(以每秒采样数为单位)。如果“高>fs/2”,
产量低