我在用我在网上找到的一个不错的 FFT 库 http://www.corix.dk/Mix-FFT/mix-fft.html看看我是否可以编写一个音高检测程序。到目前为止,我已经能够成功地让库对包含一些正弦波的测试音频信号进行 FFT 计算,其中包括 440Hz 的正弦波(我使用 16384 个样本作为大小,采样率为 44100Hz)。
FFT 输出如下所示:
433.356Hz - Real: 590.644 - Imag: -27.9856 - MAG: 16529.5
436.047Hz - Real: 683.921 - Imag: 51.2798 - MAG: 35071.4
438.739Hz - Real: 4615.24 - Imag: 1170.8 - MAG: 5.40352e+006
441.431Hz - Real: -3861.97 - Imag: 2111.13 - MAG: 8.15315e+006
444.122Hz - Real: -653.75 - Imag: 341.107 - MAG: 222999
446.814Hz - Real: -564.629 - Imag: 186.592 - MAG: 105355
正如您所看到的,441.431Hz 和 438.739Hz 频段都显示出同样高的幅度输出(“MAG:”后面最右边的数字),因此很明显目标频率 440Hz 落在两者之间。提高分辨率可能是一种接近的方法,但这会增加计算时间。
如何计算两个频率区间之间的准确频率?
UPDATE:
我尝试过巴里·奎恩的“第二个估算器” http://dspguru.com/dsp/howtos/how-to-interpolate-fft-peak在DSPGuru网站上进行了讨论,并得到了很好的结果。下面显示了 440Hz 方波的结果 - 现在我只偏离了 0.003Hz!
Here is 我使用的代码 https://gist.github.com/hiromorozumi/f74fd4d5592a7f79028560cb2922d05f。我只是简单地适应了这个例子 https://github.com/vadymmarkov/Beethoven/blob/master/Source/Estimation/Strategies/QuinnsSecondEstimator.swift我发现,这是为 Swift 准备的。感谢大家的宝贵意见,这是一次很棒的学习之旅:)
为了计算“真实”频率,一旦我使用抛物线拟合算法 https://ccrma.stanford.edu/~jos/parshl/Peak_Detection_Steps_3.html。它非常适合我的用例。
这是我寻找基频的方法:
- 计算 DFT (WOLA https://ccrma.stanford.edu/~jos/sasp/Overlap_Add_OLA_STFT_Processing.html).
- 查找 DFT 箱中的峰值。
- 求谐波积谱。不是最可靠也不是最精确的,但这是找到候选基频的一种非常简单的方法。
- 根据峰值和 HPS,使用抛物线拟合算法找到基本音调频率(如果需要,还可以找到振幅)。
例如,HPS 表示基本(最强)音调集中在 bin 中x
你的 DFT;如果垃圾箱x
属于巅峰y
,然后从峰值中获取抛物线拟合频率y
这就是您正在寻找的球场。
如果您不是在寻找基本音高,而是在寻找精确的频率anybin,只需应用适合该 bin 的抛物线即可。
一些帮助您入门的代码:
struct Peak
{
float freq ; // Peak frequency calculated by parabola fit algorithm.
float amplitude; // True amplitude.
float strength ; // Peak strength when compared to neighbouring bins.
uint16_t startPos ; // Peak starting position (DFT bin).
uint16_t maxPos ; // Peak location (DFT bin).
uint16_t stopPos ; // Peak stop position (DFT bin).
};
void calculateTrueFrequency( Peak & peak, float const bins, uint32_t const fs, DFT_Magnitudes mags )
{
// Parabola fit:
float a = mags[ peak.maxPos - 1 ];
float b = mags[ peak.maxPos ];
float c = mags[ peak.maxPos + 1 ];
float p = 0.5f * ( a - c ) / ( a - 2.0f * b + c );
float bin = convert<float>( peak.maxPos ) + p;
peak.freq = convert<float>( fs ) * bin / bins / 2;
peak.amplitude = b - 0.25f + ( a - c ) * p;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)