0

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

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

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

第 1 步: 我解析出元数据和实际的样本数据。元数据: channels => 2, sample_rate => 44100, byte_rate => 176400, bits_per_sample => 16, data_chunk_size => 705600, data => ...

第 2 步: 由于有 2 个通道,我有一个左右数组,其中包含相应的样本数据,然后将它们中的每一个都通过 FFT。每个 FFT 的结果给出了给定频率的幅度和相位

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

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

这就是我困惑的地方!我已经绘制了时域图,并通过查看 Period 并知道 A4 的周期是如何发现音高是A4,但我试图了解如何通过快速傅里叶变换。任何帮助/指向我的地方将不胜感激!

4

1 回答 1

1

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

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

第2步:

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

第 3 步:

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

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

第4步:

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

为了做得更好,您可以使用短时傅里叶变换并利用 i) FFT 数据的连续窗口的相位 (Phi) ii) 和 F = dPhi/dt

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

于 2014-11-30T18:53:12.097 回答