FFT - calculating the exact frequency between frequency cells

I use the good FFT library that I found on the Internet to find out if I can write a tone detection program. So far, I have succeeded in successfully letting the library calculate FFT on a test audio signal containing several sine waves, including one at 440 Hz (I use 16384 samples as the size and sampling frequency at 44100 Hz).

The FFT output is as follows:

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

As you can see, in blocks 441.431Hz and 438.739Hz, both show equally high amplitude outputs (the rightmost numbers after "MAG:"), so it is obvious that the target frequency of 440 Hz is somewhere in between. Increasing resolution may be one way to close, but this will add to the computation time.

How to calculate the exact frequency that falls between two frequency cells?

UPDATE:

I tried out Barry Quinn's “Second Evaluator,” which was discussed on the DSPGuru website and got great results. Below is the result for a 440 Hz square wave - now I'm only off at 0.003 Hz!

FFT Frequency Evaluation Success

, . , , Swift. , :)

+4
2

"" , . .

, :

  • DFT (WOLA).
  • DFT-.
  • . , .
  • HPS , ( ).

, HPS , ( ) x DFT; bin x y, y, , .

, , , .

:

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;
}
+1

Source: https://habr.com/ru/post/1667449/


All Articles