Matlab - 更好地理解 FFT 并找到 Pitch

标签 matlab audio fft wav pitch-detection

我知道有很多关于从 FFT 中找到音高的主题,并且我已经对从时域 -> 频域转换数据样本的整个过程有了不错的理解,但是仍然有一些领域(可能更高级) 我有点坚持。

我将逐步完成我当前的流程,希望有人可以帮助我了解我哪里出错了!

在开始之前,我在这里使用的示例是我在 Logic 中创建的 Wav 文件,它只是 中的钢琴预设。一个秤 ,从 开始 key A4 ,它只是每半个小节向上移动刻度(A4、B4、C#5、D5...),总共 4 秒 120 bpm .如果有帮助,这里是 wav 的链接:[a https://www.dropbox.com/s/zq1u9aylh5cwlmm/PianoA4_120.wav?dl=0]

第一步:
我解析出元数据和实际的样本数据。
元数据:
channels => 2, sample_rate => 44100, byte_rate => 176400, bits_per_sample => 16, data_chunk_size => 705600, data => ...
第二步:
由于有 2 个 channel ,我有一个左右数组,里面装满了相应的样本数据,然后将它们中的每一个都放在 FFT 上。每个 FFT 的结果给出了给定频率的幅度和相位

第三步:
我现在需要找到每个 FFT 的最大值。我通过找到真实/复杂结果的所有大小然后找到最大值来做到这一点。我正在使用 Matlab 来帮助我,所以我运行 max(abs(fft(data))) .我从找到每个 FFT 的最大值中得到的值是 1275.6 1084.0 .

第四步:
从它们各自的 FFT 中找到这些最大值的索引,然后在映射的频域值的索引处找到频率。这给了我 1177.0赫兹 1177.5赫兹 .

这就是我困惑的地方!我绘制了时域图并查看了如何发现音高为 A4 只需查看周期并知道 A4 的周期是多少,但我试图了解如何通过 FFT 得出相同的结论。任何帮助/指向我的地方将不胜感激!

最佳答案

A4 通常为 440Hz。我的猜测是你已经检测到 440Hz 的 3 次谐波并且有一个错误。

以下是对您正在使用的步骤的一些观察:

第2步:

对两个 channel 进行分析可能没有任何收获。通过将两者相加转换为单声道信号

第 3 步:

这不适用于可靠的复音信号(或者就此而言,真实世界的单声道乐器信号),此外,对于单声道信号,在某些情况下来自两个相邻箱的功率具有相同的值 - 这是因为每个箱是带通滤波器在其频率响应中具有指数尾。恰好位于两个频带中间的信号对两者的贡献相同,并且在实际信号的情况下,尽管是主要频率,但两个频带都可能具有频谱中的最高能量:请记住,谐波将存在并且可能很大。另请注意,对于某些真实世界的乐器声音,从根本上说,它们甚至可能没有分音的最高能量。

FFT 的相位分量提供了许多表明跨频带信号的线索。

第4步:

您正在找到具有最高能量的 FFT bin 的中心频率。由于音阶是以 2 为底的对数,这对于较高频率来说是合理的近似值,但在低频下,即使您使用大型 FFT(在这种情况下,您会消耗大量 CPU 周期并丢失时间分辨率)。

为了做得更好,您可以使用 Short-time Fourier Transform并利用
i) 来自 FFT 数据的连续窗口的相位 (Phi)
ii) 并且 F = dPhi/dt

由此您可以获得非常准确的结果。

关于Matlab - 更好地理解 FFT 并找到 Pitch,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27208622/

相关文章:

html - Kindle Fire HD使用HTML5音频标签同时播放Ogg和MP3

c++ - 将一个音频 channel 静音

python - python 中的 fft 没有在正确的位置显示峰值

执行 (0 :N-1)/N * M

matlab - Matlab 中的可变帧率动画

javascript - jQuery - $(audio).on ('ended' function()) 仅在第一个元素上触发一次

math - 在哪里可以找到真正的FFT和iFFT实现?

arrays - 将 MATLAB 元胞数组导出到 csv 文件

matlab - 将 Matlab GUI 发送到后台

c++ - 使用 C++ 定点进行 FFT 优化 ARM 设备的性能