1
$\begingroup$

I'm writing an app in which I need to find the fundamental frequency of a note produced by a trombone. To do this I'm taking the FFT of audio data from a microphone and then using autocorrelation code taken from this question.

Once I've done that I'm then attempting to find the fundamental frequency by finding the highest and second highest peak locations and how many samples they are apart. I then find the amount of time one sample lasts with a sampling rate of 44100 and multiply that by the number of samples between the two peaks to give me the period of the fundamental frequency. Finally I use 1/period to find the fundamental frequency itself. Here's the code I've written for that (in Java):

public double findFundamentalFrequency(double[] autoCorrelatedData){

    double max = Integer.MIN_VALUE;
    double secondMax = Integer.MIN_VALUE;
    int maxLoc = Integer.MIN_VALUE;
    int secondMaxLoc = Integer.MIN_VALUE;

    for(int i = 0; i < autoCorrelatedData.length; i++){
        if(autoCorrelatedData[i] > max){
            secondMaxLoc = maxLoc;
            secondMax = max;

            max = autoCorrelatedData[i];
            maxLoc = i;
        }
        else if(autoCorrelatedData[i] > secondMax){
            secondMax = autoCorrelatedData[i];
            secondMaxLoc = i;
        }
    }

    double samplingPeriod = 1/44100.0;
    //Log.i("a", String.valueOf(maxLoc));
    //Log.i("b", String.valueOf(secondMaxLoc));
    double period = samplingPeriod * Math.abs(maxLoc - secondMaxLoc);
    double fundamentalFreq = 1.0/period;
    return fundamentalFreq;
}

Is this the correct way to find the fundamental frequency using autocorrelation? The answers this gives seem to be incorrect so I'm unsure if I've made a mistake somewhere or if I'm going about this the wrong way.

$\endgroup$
3
  • $\begingroup$ Since you already have the FFT (frequency data), wouldn't it work to get the fundamental frequency from that directly? $\endgroup$ Jul 18, 2016 at 13:29
  • $\begingroup$ According to what I've read, when it comes to pitch of a musical note an FFT isn't enough for an accurate reading and one suggestion for getting a better reading was Autocorrelation. $\endgroup$
    – PyroPez
    Jul 18, 2016 at 13:35
  • $\begingroup$ I see, that makes sense; the distance between peaks in the Auto-correlation will be the delay between repetitions in your waveform, otherwise known as the period. Your explanation seems accurate but I haven't reviewed your code to see if there is a mistake there. $\endgroup$ Jul 18, 2016 at 13:38

1 Answer 1

4
$\begingroup$

Three suggestions:

  • Try searching only over your expected pitch range: from a lag or period a bit shorter than that of your highest expected pitch for the instrument in question, to a lag a bit longer than twice the period of the lowest pitch expected.

  • Make sure there is a sufficient dip between your highest and your 2nd highest peak, or else you might find the shoulder of the 1st peak, and thus completely miss finding any 2nd peak.

  • You might also want to try using parabolic interpolation to better estimate each pitch period if any are between autocorrelation lags.

$\endgroup$
2
  • 2
    $\begingroup$ just to add to your second point, hot, that (from an audio pov) if you run your data through a DC-blocking filter, that means that the autocorrelation must also be DC free. that means between any two peaks (spaced apart by the period length) there must be some negative autocorrelation values (that when added to the positive ones at other lags, adds to zero). then between the "zeroth peak" (at 0 lag) and the first peak that you wanna consider, there are the first negative values. start the search from there. then a dumb search will never end up on the "zeroth peak" which might be the highest. $\endgroup$ Jul 18, 2019 at 20:36
  • $\begingroup$ in fact, now that i consider this (and remember doing this) more, between any two peaks that represent a multiple of the period, there must be negative values. so every candidate peak must be the maximum value between two portions of the autocorrelation with negative values (all this assuming you're operating on data coming out of a DC-blocking filter). this is what separates legit peaks. i would pick the, say, highest 5 candidate peaks and apply some heuristics (that i won't say) to decide which candidate is the best choice. $\endgroup$ Jul 18, 2019 at 21:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.