无法正确生成 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的主要内容,如果未能解决你的问题,请参考以下文章

Python Numpy - 无法正确保存/加载数组

PIL 无法将模式 F 写入 jpeg

如何使用 iOS Accelerate 框架正确填充 FFT 的二维数组

解释 numpy.fft.fft2 输出

安装 Anaconda 后无法导入 numpy

Numpy fft 冻结更长的样本