2
$\begingroup$

I am trying to get the fundamental frequency of a signal that only has a single pitch. I coded out the autocorrelation function using FFT and already got the autocorrelation result. Unfortunately, I don't know how to get the fundamental frequency from the autocorrelation result. Can someone help me? My JAVA code for getting the fundamental frequency using autocorrelation is below:

public double getPitch(double[] buffer, int firstSample, int lastSample, double sampleRate)
{
    int lengthOfFFTWindow=lastSample-firstSample;
    double[] input_buffer=new double[lengthOfFFTWindow];
    DoubleFFT_1D fft = new DoubleFFT_1D(lengthOfFFTWindow);
    double[] autocorrelation_values=new double[lengthOfFFTWindow];
    double[] fftData = new double[lengthOfFFTWindow * 2];
    double max=-1;
    double max_i=-1;
    //FFT on each sample in each window
    for (int i = 0; i < lengthOfFFTWindow; i++) {
        // copying audio data to the fft data buffer, imaginary part is 0
        fftData[2 * i] = buffer[i+firstSample];
        fftData[2 * i + 1] = 0;
    }
    fft.complexForward(fftData);
    for (int i = 0,j=0; i < fftData.length; i += 2,j++) {
        // complex numbers -> vectors, so we compute the length of the vector, which is sqrt(realpart^2+imaginarypart^2)
        autocorrelation_values[j] = Math.sqrt((fftData[i] * fftData[i]) + (fftData[i + 1] * fftData[i + 1]));
    }
    fft.complexInverse(fftData, false);
    for(int i=0;i<autocorrelation_values.length;i++)
    {
        if(max<autocorrelation_values[i])
        {
            max=autocorrelation_values[i];
            max_i=i;
        }
    }
    return max/2;
}

Is it correct to return the maximum autocorrelation value divide by 2 as the fundamental frequency? I keep getting wrong answers when I do that.

$\endgroup$
5
$\begingroup$

The value of the peak of the autocorrelation function (maximum) is not really important - though it can be used as a basic feature for voiced/unvoiced classification or more generally for "pitchedness".

What matters is the index at which the function takes its maximum (arg-maximum). This is very intuitive to understand: if the signal has a period of $\tau$ samples, the original signal and the signal shifted by $\tau$ samples should be very similar, so the autocorrelation function will have a peak when evaluated at $\tau$.

Thus, the interesting variable is max_i in your code. One thing I notice is that you search through the whole autocorrelation_values vector. But the autocorrelation function is maximum at 0, so your maximum will always be 0! I advise you to think about a meaningful range for the fundamental frequency you want to detect, and restrict the search in this range to get a meaningful result.

I hadn't checked the rest of your code in details, I don't think it is the purpose of this site to dive into coding/implementation problems.

$\endgroup$
  • $\begingroup$ If max_i is always zero, then how do I get the fundamental frequency using max_i? $\endgroup$ – Sakura Mar 30 '13 at 15:34
  • 2
    $\begingroup$ By searching for the arg-max in a meaningful range of lags - not between 0 and your analysis window length. You do have prior knowledge about the range of frequencies in which the fundamental frequency is located, right? Then search in this range only. $\endgroup$ – pichenettes Mar 30 '13 at 15:40
  • $\begingroup$ I'd recommend searching at least from the first zero-crossing and beyond. First peak andit's position doesn't play significant role here. $\endgroup$ – mbaitoff May 19 '13 at 10:06
3
$\begingroup$

there are two more issues to worry about so that you choose the correct peak which corresponds to the local period in a quasi-periodic waveform.

first, if you are using FFT -> magnitude squared -> inverse FFT to get the autocorrelation, your FFT length needs to be twice the length of the segment of signal which is zero-padded of equal length. this is necessary to prevent time-aliasing due to the circular convolution that occurs when using this technique.

now that is windowing with a rectangular window and the consequence of that is that the autocorrelation will be governed by an envelope that is a triangular function. so, even where there is a perfect correlation, the apparent autocorrelation at that lag does not rise to the level of lag 0. but this effect can be compensated, if you're careful.

the second issue, which is sorta the opposite problem of the first, is that if a lag of one period results in high autocorrelation, so also is a lag of two periods or three periods. actually two periods can be viewed as a single period of a periodic waveform (it's just that all odd harmonics would be zero). and numerical issues might make that second peak slightly higher than the first and you'll pick the wrong peak. so you may need to do something that emphasizes the first peak slightly.

$\endgroup$
0
$\begingroup$

Is it correct to return the maximum autocorrelation value divide by 2 as the fundamental frequency? I keep getting wrong answers when I do that.

No. The position of the peak of the autocorrelation (argmax(autocorrelation_values)) is the period of the waveform (often written T), in samples, so to convert to a frequency in Hz, for instance, you would do:

$$f = \frac{f_\mathrm{s}}{T}$$

fs is samples/second, and T is samples/cycle, so divided you get cycles/second = Hz.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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