在Stackoverflow和其他平台上,关于FFT和音高检测的讨论已经数不胜数。
一般认为,FFT虽然快速,但对于很多应用来说准确性并不高,但通常没有解释为什么。
我想解释一下我对此的理解,希望比我聪明的人能够纠正我,并在我无法理解的地方进行补充。
FFT将输入数据从时域转换为频域。
最初,我们从一系列数据开始。如果我们将其绘制在图表上,则Y轴上是声音的振幅,X轴上是时间。这是在时域中。
FFT将这些时间点上的振幅值转换为不同频率上的振幅值。
FFT输出的数据数量与输入的数据数量相同
如果我们输入10个时间点(10个样本)的振幅,FFT将在这些样本中输出10个不同频率的振幅(在乘以虚数和实数的平方根后)。
哪些频率由以下内容确定:
我们将FFT的输出称为 bin ,每个bin的宽度通过将采样率除以FFT中的样本数来计算:
bin width = Sample Rate(Hz)/FFT Length (n samples)
使用一些实际值,可以得到:
bin_width = 44100 / 512 = 86.132
因此,我们从FFT中获得了512个bin(记住输入和输出的数据量是相同的),每个bin跨越86.132 Hz。
因此,对于给定的bin,我们可以通过以下方式计算它代表的频率:
Bin Freq (Hz) = Bin number (n) * bin width (Hz)
使用上面的数值,FFT输出中的第3个bin将代表258.398Hz处的幅度:
Bin Freq (Hz) = 3 * 86.132 = 258.396Hz
这意味着在给定的采样率和缓冲区大小下,FFT输出的精度不能超过±86.132Hz。
如果您需要更高的精度(比如1Hz),则必须降低采样率或增加缓冲区大小(或两者兼备)。
desired bin width: 1Hz = 44100 / 44100 # A buffer size of 44100 would work in this instance
随着缓冲区大小接近采样率,延迟问题变得更加严重。
FFT Results per second = Sample Rate / Buffer Size = 44100/44100 = 1 FFT per second
每秒 44100 个样本,填充一个 44100 个样本的缓冲区 = 每秒 1 个完整缓冲区。
我意识到 FFT 不仅仅是计算基频(具有最高幅度的二进制数),那么我对于声调检测中 FFT 的理解是否正确?
有没有办法在不牺牲延迟的情况下提高 FFT 的准确性?
N
个相等的块。根据实现的不同,允许使用不同选择的N
,但几乎总是允许使用2
。3
和5
较少见。4
是多余的(只是2x2),6
也是如此(2x3)。因为可以填充到8,所以因子7
开始变得不太有用。 - MSalters