无法正确生成 Numpy FFT
Posted
技术标签:
【中文标题】无法正确生成 Numpy FFT【英文标题】:Can't generate Numpy FFT properly 【发布时间】:2018-08-17 05:17:08 【问题描述】:我正在尝试查找人们在 wav 文件中讲话的频谱,但在此之前,我想我会尝试仅使用一个简单的 200hz 音频文件来执行此操作。在下面的代码中,我读入了 200hz 文件并将其绘制在屏幕上。 注意:200hz 文件的采样率为 192000。我的块大小是 1/10,所以每 19200 个样本
from scipy.io import wavfile
import numpy as np
### This is just for drawing
import matplotlib.pyplot as plt
import matplotlib.animation as animation
### Above is for drawing
# Read the .wav file
sample_rate, data = wavfile.read('200hz.wav')
CHUNK_SAMPLES_PER_SECOND = 10
CHUNK = sample_rate / CHUNK_SAMPLES_PER_SECOND
# Now compute the spectrum on a given frame
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
# Now, lets just draw the plot
for frame in range(len(data) / CHUNK):
ax1.clear()
frame_data = data[frame * CHUNK:(frame + 1) * CHUNK, 0] # normally 2 channel, take 1st channel
frame_data = frame_data * 1.0 / frame_data.max()
#### Below, activate those to use the FFT ####
# frame_data = np.fft.fft(frame_data) # Calculate FFT on dataset
# frame_data = frame_data * 1.0 / frame_data.max() # Normalize FFT data
# ax1.set_xlabel('frequency')
ax1.plot(np.abs(frame_data), '-')
ax1.set_xlabel('sample')
ax1.set_ylabel('volume')
plt.pause(1.0 / CHUNK_SAMPLES_PER_SECOND)
以上代码产生:
对我来说,这看起来是正确的。由于我仅以 192000 的采样率采集 19200 个样本,因此该图应为 0.1 秒。因此,一个 200 Hz 的信号应该有大约 20 个全波。
当我通过取消注释来启用以下代码时:
#### Below, activate those to use the FFT ####
# frame_data = np.fft.fft(frame_data) # Calculate FFT on dataset
# frame_data = frame_data * 1.0 / frame_data.max() # Normalize FFT data
# ax1.set_xlabel('frequency')
它会生成一个看起来很时髦的 fft 图表:
我猜我预计它会显示一个大约 200hz 的峰值,或者至少是信号频率的一个明确定义的峰值。谢谢!
编辑: 我添加了我使用的实际音频文件here。
我还将 Y 轴调整为对数刻度,X 轴范围如下:
【问题讨论】:
您是否尝试放大 x 轴的 0-400 范围?那是应该采取行动的地方!另外,对 y 使用对数轴。 看起来不错,只是真的缩小了。如果放大左侧尖峰,您应该会看到一个大的 FFT 箱。如果您使用numpy.fft.fftfreq
以赫兹为单位制作一个真实的频率轴并与之对照,则该尖峰应为 200 Hz。右尖峰应为192000-200
Hz。如果您发布您的 WAV 文件,我们可以独立确认。
@CrisLuengo 啊 - 好点!我放大了图表(见上文),我认为我得到了一些更好的结果,如你所见。山峰似乎不在正确的位置?当我达到 10 个代表时,我会内联图像:(
@AhmedFasih 感谢您的回复!我尝试为绘图功能添加ax1.plot(np.fft.fftfreq(len(frame_data)), np.abs(frame_data))
,但它产生了上面列出的结果。
【参考方案1】:
您的频率轴从 0 到 19200。这是不正确的,通过采用较小的块,您并没有降低采样频率。它应该从 0 到 192000。
因此,假设沿该轴的每个值都乘以 10。因此,正如预期的那样,您在 200 Hz 处有一个峰值,而正如预期的那样,在该轴的整数倍处有一堆峰值。请注意,您的样本不是完美的正弦曲线,由于形状,它有很多谐波。
另请注意,接近 192000 Hz 的第二个大峰值对应于“负频率”:DFT 输出的后半部分是冗余的,是前半部分的镜像副本。
【讨论】:
以上是关于无法正确生成 Numpy FFT的主要内容,如果未能解决你的问题,请参考以下文章