这是读取音频文件 FFT 的正确方法吗? (python + wav)
Posted
技术标签:
【中文标题】这是读取音频文件 FFT 的正确方法吗? (python + wav)【英文标题】:Is this the correct way to read FFT of a audio file? (python + wav) 【发布时间】:2019-02-04 19:17:42 【问题描述】:音频文件是一个 16 位单声道 PCM 音频文件,具有不同的采样率和 10-30 毫秒的长度。
import struct
from pydub import Audiosegment
import numpy as np
import matplotlib.pyplot as plt
import scipy.fftpack
sound = AudioSegment.from_wav("3000hz.wav")
raw_data = sound.raw_data# needs to be mono
sample_rate = sound.frame_rate
sample_size = sound.sample_width
channels = sound.channels
fmt = "%ih" % sound.frame_count() * channels
amplitudes= struct.unpack(fmt, raw_data)
yVals = scipy.fftpack.fft(amplitudes)
plt.plot(abs(yVals[:(len(yVals)/2)-1]),'r')
plt.show()
带有 3000hz wav 文件(取自在线正弦波发生器)的输出会产生一个不错的 FFT,但峰值为 9000,而不是 3000。这在其他测试中是一致的 3 倍。这个可以吗?代码是否正确?
【问题讨论】:
乍一看,还可以。您可以绘制“幅度”来验证读取 wav 文件是否正确完成。 哦,请确保您正确解释了轴值。如果采样率 = 1000 并且 FFT 峰值为 100,这并不意味着实际频率为 100 Hz :-) @HenkvanderLaak 感谢您的帮助,它似乎给了我真正的频率 * 样本长度(以秒为单位)这是一个好的相关性吗? 【参考方案1】:通过仅使用y
数组而没有对应的x
数组调用plt.plot()
,它将使用0, 1, ..., N-1
作为x
值。这不是我们真正想要的,我们想要的是 x 轴上的频率。
让我们用“bin index”表示您现在在图中看到的x
值。设数组长度为N
,采样频率为fs
。在计算 FFT 时,bin 索引0
对应于 0 Hz 的频率。下一个 bin 索引 1
对应于频率 fs / N
Hz。这是因为 FFT 将具有 N
值并从 0
Hz 变为 fs
Hz,因此每一步都是 fs / N
Hz。因此,下一个 bin 对应于2 * fs / N
Hz,依此类推。最后一个 bin N-1
是 (N-1)/N * fs
Hz,所以几乎是 fs
Hz。
如果我们想要创建一个具有幅度谱与频率的图,那么我们需要手动创建一个频率向量,其中包含每个 bin 索引的实际频率。幸运的是,scipy.fftpack
包含一个函数:fftfreq
:
freq = scipy.fftpack.fftfreq(n=N, d=1.0 / fs)
然后我们可以修改对plt.plot()
的调用以使用freq
作为x
值而不是0 ... N-1
:
plt.plot(freq, abs(yVals), 'r')
这样,峰值应该在正确的位置。
如果您只想查看单面光谱,则可以像问题中的代码一样裁剪 freq
和 yVals
。
【讨论】:
以上是关于这是读取音频文件 FFT 的正确方法吗? (python + wav)的主要内容,如果未能解决你的问题,请参考以下文章