Search code examples
fftfrequencydenormalizationtime-frequencypitch-detection

How to denormalize values to do the Harmonic Product Spectrum


I'm trying to execute the HPS algorithm and the results are not right. (48000Hz, 16bits) I've applied to a buffer with the recorded frequency several splits, then a Hanning window, and finally the FFT.

I've obtained a peak in each FFT, that correspond with the frequency I am using, or an octave of it. But when i do the HPS, the results of the fundamental frequency are 0, because the numbers of the array where I make the sum(multiply) are too small, more than my peak in the original FFT. This is the code of the HPS:

                 int i_max_h = 0;
                 double m_max_h = miniBuffer[0];
                 //m_max is the value of the peak in the original time domain array
                 m_max_h = m_max;

                 //array for the sum
                 double sum [] = new double[miniBuffer.length];
                 int fund_freq = 0;

                 //It could be divide by 3, but I'm not going over 500Hz, so it should works
                 for(int k = 0; k < 24000/48 ; k++)
                 {
                     //HPS down sampling and multiply 
                     sum[k] = miniBuffer[k] * miniBuffer[2*k] * miniBuffer[3*k];
                     // find fundamental frequency (maximum value in plot)
                     if( sum[k] > m_max_h && k > 0 )
                     {
                         m_max_h = sum[k];
                         i_max_h = k;
                     }
                  }
                  //This should get the fundamental freq. from sum
                  fund_freq = (i_max_h * Fs / 24000);
                  System.out.print("Fundamental Freq.: ");
                  System.out.println(fund_freq);
                  System.out.println("");

The original HPS code is HERE

I don't know why the sum have little values, when it should be bigger than the previous, and the peak of the sum too. I've applied a RealFordward FFT, maybe there is a problem with the -1 to 1 range, that makes my sum decrease when I multiply it.

Any idea how to fix it, to do the HPS? How could i do the inverse normalize?


Solution

  • The problem was that I was trying to get a higher value of amplitude on the sum array (the HPS array), and my set of values are normalize since I apply the FFT algorithm to them. This is the solution I've created, multiplying the individual values of the sum array by 10 before make the multiply.

    The number 10 is a coefficient that I have selected, but it could be wrong in some high frequencies cases, this coefficient could be another higher number.

    '''

        for(int k = 0; k < 24000/48 ; k++)
                 {
    
                     sum[k] = ((miniBuffer[k]*10) * (miniBuffer[2*k]*10) * (miniBuffer[3*k]*10));
                     // find fundamental frequency (maximum value in plot)
                     if( sum[k] > m_max_h && k > 0 )
                     {
                         m_max_h = sum[k];
                         i_max_h = k;
                     }
                  }
    

    '''

    The range of the frequencies is 24000/48 = 500, so it's between 0 and 499 Hz, more than I need in a bass. If the split of the full array is less than 24000, i should decrease the number 48, and this is admissible, because the down sampled arrays are 24000/3 and 24000/2, so this value could decrease to 3, and it should work well.