FFT - 计算频率仓之间的精确频率

时间:2017-01-21 19:23:53

标签: signal-processing fft

我正在使用a nice FFT library I found online来查看我是否可以编写音高检测程序。到目前为止,我已经能够成功地让磁带库对包含少量正弦波的测试音频信号进行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介于两者之间。提高分辨率可能是一种关闭方式,但这会增加计算时间。

如何计算两个频率仓之间的确切频率?

更新

我尝试了在DSPGuru网站上讨论的Barry Quinn's "Second Estimator",并取得了优异的成绩。以下显示440Hz方波的结果 - 现在我只有0.003Hz!

FFT frequency estimation success

这是the code I used。我只是改编了this example我找到了,这是为了Swift。感谢大家的宝贵意见,这是一次很棒的学习之旅:)。

2 个答案:

答案 0 :(得分:1)

Sinc插值可用于精确地内插(或重建)FFT结果区间之间的频谱。零填充FFT将产生类似的内插频谱。您可以使用具有逐次逼近的高质量插值器(例如窗口Sinc内核)来估计实际光谱峰值,以达到S / N允许的任何分辨率。除非在插值内核中包含光谱共轭图像的影响,否则此重建可能无法在DC或Fs / 2 FFT结果区附近工作。

有关时域重建的详细信息,请参阅:https://ccrma.stanford.edu/~jos/Interpolation/Ideal_Bandlimited_Sinc_Interpolation.htmlhttps://en.wikipedia.org/wiki/Whittaker%E2%80%93Shannon_interpolation_formula,但相同的插值方法分别适用于带限或时间限制信号的域,频率或时间。

如果您需要精度较低的估算器,而计算开销要小得多,则抛物线插值(以及其他类似的曲线拟合估算器)可能会起作用。有关抛物线的详细信息,请参阅:https://www.dsprelated.com/freebooks/sasp/Quadratic_Interpolation_Spectral_Peaks.htmlhttps://mgasior.web.cern.ch/mgasior/pap/FFT_resol_note.pdf,其他曲线拟合峰值估算值请参见http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.555.2873&rep=rep1&type=pdf

答案 1 :(得分:1)

计算" true"频率,一旦我使用 parabola fit algorithm 。它对我的用例非常有用。

这是我为了找到基本频率而遵循的方式:

  • 计算DFT(WOLA)。
  • 在DFT箱中查找峰值。
  • 查找谐波产品频谱。不是最可靠也不精确,但这是找到基本频率候选者的一种非常简单的方法。
  • 根据峰值和HPS,使用抛物线拟合算法找到基本音高频率(如果需要,还可以找到振幅)。

例如,HPS表示基本(最强)音高集中在DFT的x个音箱中;如果bin x属于峰值y,则抛物线拟合频率取自峰值y,即您正在寻找的音高。

如果你不是在任何 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;
}