音频文件是具有变化samplerates和10-30ms的长度16位单声道PCM音频文件。
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倍,是其他测试是一致的。这个可以吗?而且是代码是否正确?
通过调用plt.plot()
只有一个y
阵列和没有相应x
阵列,它将使用0, 1, ..., N-1
作为x
值。这不是我们真正想要的,我们希望在x轴的频率。
让我们来表示你的情节,现在看到x
值由“点索引”。让该阵列的长度是N
和取样频率是fs
。当计算的FFT中,时段索引0
对应于0 Hz的频率。下一个二进制位索引1
对应于频率fs / N
赫兹。这是因为FFT将有N
值和0
赫兹到fs
赫兹,所以每一步都是fs / N
赫兹。因此,下一个区段对应于2 * fs / N
赫兹,等等。而最后仓N-1
是(N-1)/N * fs
赫兹,所以几乎fs
赫兹。
如果我们要创造一个你有幅度谱与频率的情节,那么我们需要手工创建一个包含每个分级指数的实际频率的频率向量。幸运的是,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
像你在问题的代码已经这样做了。