【问题标题】:Scipy Butter bandpass is not producing the desired resultsScipy Butter 带通没有产生预期的结果
【发布时间】:2018-12-31 02:04:59
【问题描述】:

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

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

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

http://scipy-cookbook.readthedocs.io/items/ButterworthBandpass.html

我得到以下结果:

所以我正在尝试以 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")

我不明白我哪里出错了。

谢谢

【问题讨论】:

    标签: numpy audio scipy signal-processing butterworth


    【解决方案1】:

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

    检查您的代码

    在您链接的示例中,它们精确地显示了计算的过程,并以不同的顺序绘制过滤器:

    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 的图表很可能是正确的。如果您使用their example 并将带通截止频率更改为 100Hz -> 101Hz,则输出结果是一个(如果不完全是)零数组。这是因为它只会查看 1Hz 范围内的信号能量.

    如果您这样做是为了分析,频率间隔往往会更大,即Octave Bands(或更小的倍频程分区)。

    频谱图

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

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

    【讨论】:

    • 天真地以为我知道什么是带通滤波器,因为我制作了音乐,但我忽略了完全了解它的操作。我正在考虑使用高度为 22,000 像素、宽度为时间长度的频谱图。但我知道如何做到这一点的唯一方法是使用 BP 过滤器。关于实现这一目标的更好方法的任何建议?
    【解决方案2】:

    @Woodydev说是真的:44.1 kHz中的1 Hz是的方式 EM> 方式太小的带通布的任何类型的过滤器。只需查看滤波器系数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(查看@ 987654329,irfft,@ 987654330 numpy.fft模块)。

    以下是使用FFTS在傅立叶域中应用砖墙带通滤波器的功能:
    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()
    

    你可以把它放在文件中,fftBandpass.py,刚刚用python fftBandpass.py查看它创建以下绘图:

    注意我必须按100划分1 Hz带通信信号,因为在带通量的情况下,信号中的能量很少。另请注意,生活在这个小通带内的信号几乎只是100 Hz的正弦曲线。

    如果您在自己的代码中提出如下:from fftBandpass import fftBandpass,您可以使用fftBandpass函数。

    您可以尝试的另一件事是使信号100x的极限,因此将其转换为在441Hz处采样的信号。 441 Hz中的1赫兹仍然是一个疯狂的通带,但你可能有更好的运气,而不是试图带来原始信号。查看scipy.signal.decimate,但不要尝试使用q=100,而是通过2,然后2,然后5,然后5(用于总抽取为100x)。

    【讨论】:

    • 嗯,我只使用了一个带通,因为它是我最熟悉的,并且是一个天真的音乐制片人觉得我理解它所做的是,当我上来时,我想起了所有Butterworth过滤器和FFT有点困惑。什么更有效的方法是一次抓住1Hz?。 span>
    • 你是绝对的 100% i>确定你想要1赫兹块吗?你将拥有22000个......但是我会用一种方法更新答案,假设这真的是你所需要的。 span>
    • 是的,我想使用神经网络来生成类似于它训练的声音。我可以使用8khz采样率,但最终需要将其扩展到44.1,以便增加质量 span>
    猜你喜欢
    • 1970-01-01
    • 2015-04-20
    • 2019-12-13
    • 2015-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-26
    • 2017-05-22
    相关资源
    最近更新 更多