【问题标题】:Implementing (Butterworth) filter in Python and creating wav file在 Python 中实现(Butterworth)过滤器并创建 wav 文件
【发布时间】:2017-05-09 09:53:00
【问题描述】:

我正在尝试实现一个 Butterworth 带通滤波器,以在 Python 中实现 wav 文件(我对它非常陌生)。我目前得到的代码如下

import wave
import numpy
import matplotlib.pyplot as plt
from scipy import signal
from scipy.signal import filtfilt

# open the audio file and extract some information
spf = wave.open('clip.wav','r')
(nChannels, sampWidth, sampleRate, nFrames, compType, compName) = spf.getparams()

# extract audio from wav file
input_signal = spf.readframes(-1)
input_signal = numpy.fromstring(input_signal, 'Int16')
spf.close()

# create the filter
N = 4
nyq = 0.5 * sampleRate
low = 100 / nyq
high = 500 / nyq
b, a = signal.butter(N, [low, high], btype='band')

# apply filter
output_signal = signal.filtfilt(b, a, input_signal)

# ceate output file
wav_out = wave.open("output.wav", "w")
wav_out.setparams((nChannels, sampWidth, sampleRate, nFrames, compType, compName))

# write to output file
wav_out.writeframes(output_signal.tobytes())
wav_out.close()

# plot the signals
t = numpy.linspace(0, nFrames/sampWidth, nFrames, endpoint = False)
plt.plot(t, input_signal, label='Input')
plt.plot(t, output_signal, label='Output')
plt.show()

一切正常(我认为),但是当我将过滤后的数据(output_signal)写入 output.wav 文件时出现问题。出于某种原因,当我收听输出 wav 文件时,它听起来像是很大的噪音。此外,它的长度(时间)是输入文件的四倍。 奇怪的是,当我在时域中绘制输入和输出时,我看到输出信号是输入的滤波版本。然而,在 Audacity 中分析输出声音片段的时域时,它只是很大的噪音,看起来根本不像 Python 中绘制的时域图。

我想我在使用 filtfilt 函数或 .tobytes 函数时做错了,因为使用 .tobytes 后的输出数组在由 .fromstring 转换时比输入数组大得多,但我可以'不知道我做错了什么。

谢谢!

【问题讨论】:

  • 由于output_signalndarray,并且您在其上调用tobytes(),您确定它以每个样本16 位的形式输出,与您的输入相同吗?我还注意到您使用rw 进行读写,而不是rbwb。这可能也会导致问题吗?
  • 更改为rbwb 遗憾地没有解决问题。在tobytes() 期间一定发生了错误,因为output_signalinput_signal 数组的大小是一样的,但是当对它们都执行tobytes() 时,只有input_array 被正确转换回来,而output_array 会产生一些没有意义的东西。
  • 帮自己一个忙,使用soundfile 模块。这适用于 NumPy 数组。

标签: python audio wav bandpass-filter


【解决方案1】:

输入信号应该被归一化。图表数据显示从 30000 到 -30000 的 y 轴。如果您将幅度从 1.0 标准化到 -1.0,那么您将能够在 audacity 上收听波形文件。

我使用此代码对 1 个通道的输入信号进行归一化

amp = 1.0
input_signal = amp * input_signal / max(abs(max(input_signal)),abs(min(input_signal)))

在使用您的代码读入输入信号后和写入输出文件之前(过滤后),我对幅度进行了归一化。

【讨论】:

    猜你喜欢
    • 2014-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-04
    • 1970-01-01
    • 2018-12-30
    • 2021-06-26
    • 1970-01-01
    相关资源
    最近更新 更多