# Algorithms for finding fundamental frequency based on ACF result

I am developing a software for fundamental frequency tracking. For this purpose, I have designed a function which calculates autocorrelation over the signal and a second function which, based on autocorrelation result, finds the peak corresponding to the fundamental frequency.

However the code I have written is not very reliable. What I want to know is: which algorithms are reliable for fundamental frequency peak search?

EDIT

My autocorrelation plot looks as follows so far, when done in MATLAB:

however, I implemented it in C, because my software is in C, as follows:

 91     for(;i < *length;i++) {
92         for(j = i;j < *length + i;j++) {
93             if(j > i) {
94                 sum += 0;
95             } else {
96                 sum += samples[i] * samples[j];
97             }
98         }
99
100         result[i] = sum;
101         sum = 0.0f;
102     }


with i starting in 0. I also believe this code to be OK.

Approximating the above plot in MATLAB, I see this, where the marked peak would be my fundamental frequency one (the note I'm testing with is an E2)

as we can see from this plot

the signal I'm dealing with is quasiperiodic and the difference between those peaks actually result in the fundamental frequency for E2 note: the distance between the two is 389 - 193 == 196 (values obtained from drag & drop of MATLAB plot), which, divided by my sampling rate of 16 kHz, results in 0.01225, that would be my wave period. Inverting this value I obtain 81.6326530612 Hz, which is very near to my expected 82.41 Hz for E2.

However I'm having a real bad time trying to locate these two peaks in code, since I'm not sure what to compare to be sure the peaks I found are actually these two peaks.

• Does this answer to another question help? dsp.stackexchange.com/a/15117/80
– Peter K.
Apr 3, 2014 at 0:59
• @PeterK. I'm gonna implement this suggestion and see if it works. Thanks! Apr 3, 2014 at 1:04
• How did you determine that your existing code was not very reliable? Did your method display an octave uncertainty issue? Or some other problem? Apr 3, 2014 at 4:29
• @hotpaw2 my method can't find the correct peaks. Therefore, it calculates and reports a wrong frequency. Apr 3, 2014 at 18:08
• Posting some of your results, plots and such would be helpful to understand how far along you are. Apr 3, 2014 at 23:39

im assuming your signals are audio and harmonic and you are not doing multiple F0 estimation where you have multiple tones played simultaneously. in that case there are a few easier methods. the normalisation of short time autocorrelation function. r(lag) = (1/N)*sum(x(n)*x(n+lag) N is length of x(n) F0 here is obtained from the inverse of the lag that corresponds to the maximum of r(lag) within a predefined range (for example your range could be from 20 to 250, hence at lag 196 you have a maximum, again play around with this range). to avoid detecting an integer multiple of the period, short lags are better than long ones. here is a C function for this, probably worth playing around with.

void autocorr(
float *r,       /* (output) autocorrelation vector */
const float *x, /* (input) data vector */
int N,          /* length of data vector */
int order       /* largest lag for calculated
autocorrelations */
)
{
int     lag, n;
float   sum;

for (lag = 0; lag <= order; lag++) {
sum = 0;
for (n = 0; n < N - lag; n++) {
sum += x[n] * x[n+lag];
}
r[lag] = sum/N;
}
}


An alternative method for detecting peaks, is center clipping. after your autocorr function you could code something like:

y(n) = a(n) - C, if a(n) >= C

y(n) = a(n) + C, if a(n) <= -C

y(n) = 0 otherwise.

C is some percentage of the max amplitude of the autocorr vector.

all i have showed you above is the very basic stuff, since F0 analysis can be very complex (probably why people have not answered). you can find more in speech codec books or music transcription books.

You may get better results if you do a spectro-temporal auto-correlation. This involves splitting the signal into frequency bands and performing an ACF on each band. Summing across the auto-correlations of all the bands can provide clearer peaks and hence a more reliable $f_0$ estimate.