0

So i'm working on a guitar tuner app, and i'm struggling to get my head fully around using FFTs to find base frequency. here's my code for "trying" to find frequency from PCM sound array data[], size 4160 (bufferSize), sampling rate of 8000 Hz

  DoubleFFT_1D fft1d = new DoubleFFT_1D(bufferSize); 
            double[] fftBuffer = new double[bufferSize*2]; 
            double[] magnitude = new double[bufferSize/2];

            // copy real input data to complex FFT buffer
            for(int i = 0; i < bufferSize-1; ++i){
                fftBuffer[2*i] = data[i];
                fftBuffer[2*i+1] = 0;
            }

            //perform  FFT on fft[] buffer
            fft1d.realForward(fftBuffer);

            // calculate power spectrum (magnitude) values from fft[]
            for(int i = 0; i < (bufferSize/2)-1; ++i) {

                double real =  (2 * fftBuffer[i]);
                double imaginary =  (2 * fftBuffer[i] + 1);
                magnitude[i] = Math.sqrt( real*real + imaginary*imaginary ); 

            }
            // find largest peak in power spectrum
            for(int i = 0; i < (bufferSize/2)-1; ++i) {
            if(magnitude[i] > maxVal){
                maxVal = (int) magnitude[i];           
                binNo = i;                  
                }   
            }
            // convert index of largest peak to frequency
            freq = 8000 * binNo/bufferSize;

Most of this is based off of examples and answers found to similar questions on this site, so my understanding of it all is a little sketchy at best.

While testing my program using a pitch generator, the frequency value coming back seems to vary massively.

I'm wondering if there's any obvious flaws here in my code, or my understanding of the process, and any pointer in the right direction

user2212383
  • 1
  • 1
  • 3

1 Answers1

0

First things first:

Use

            double real =  fftBuffer[2*i])
            double imaginary =  fftBuffer[2*i + 1];

as these are index computations and not transformations of the value.

Can you give a link to the description of realForward?


Second: If you use realForward, then the buffer is not interleaved with zeros, but you have to take care with the first frequency.

If you use your preparation of constructing complex numbers with imaginary part 0 in the buffer, then you have to use the complexForward FFT method. This then does not require special attention for the first frequency.


And third, to avoid artifacts in the frequency detection, apply a windowing function to your signal segment. I.e., fade it in and out.


realForward:

at input:

buf[0]=x[0], buf[1]=x[1] etc. 
buf[2n-1]=x[2n-1], 

for even number N=2n of samples.

at output:

buf[0]=a[0], buf[1]=a[n], b[0]=0=b[n],

buf[2]=a[1], buf[3]=b[1], 
buf[4]=a[2], buf[5]=b[2], 
etc., 
buf[2n-2]=a[n-1], buf[2n-1]=b[n-1]

complexForward: (N=2n if compared with above)

at input:

buf[0]=x[0], buf[1]=0,
buf[2]=x[1], buf[3]=0,
... ,
buf[2N-2]=x[N-1], buf[2N-1]=0

at output:

buf[0]=a[0], buf[1]=b[0], 
buf[2]=a[1], buf[3]=b[1],
buf[4]=a[2], buf[5]=b[2],
 ... ,
buf[2N-2]=a[N-1], buf[2N-1]=b[N-1],

with, for this real input, a[N-k]=a[k] and b[N-k]=-b[k], so that about half the values are redundant.

Lutz Lehmann
  • 25,219
  • 2
  • 22
  • 51
  • Windowing is something i was going to address next, but i wasn't sure if the lack of window would be creating results of such massive variety (100-3000ish, for a 330hz tone). Will get on it see if i can get some results. – user2212383 Jan 31 '14 at 16:12
  • You got to first correct the first two fundamental errors to get any usable result. – Lutz Lehmann Jan 31 '14 at 16:14
  • Corrected the computation to find magnitude! I'm a little confused by what you mean with "first frequency"? Just to check, using realForward, i should skip creating the complex buffer, and with complexForward i should include it? – user2212383 Jan 31 '14 at 16:15
  • yeah i figured that was the case, so i sort of skipped applying a window, probably should've mentioned in the OP – user2212383 Jan 31 '14 at 16:17
  • Yes, either the complex buffer with complexForward or the real array with realForward and the packed format of the result. – Lutz Lehmann Jan 31 '14 at 16:40
  • Ok, so i've gone ahead and used complexForward as well as fixing the magnitude computation. Still seeing massive variations in results coming back. Looking at a question found [here](http://stackoverflow.com/questions/5774104/android-audio-fft-to-retrieve-specific-frequency-magnitude-using-audiorecord?rq=1) i noticed my sound array is stored as byte[]- should i be converting to double[]? – user2212383 Jan 31 '14 at 17:16
  • By copying into the double array for the complex numbers you are already converting byte to double. But check for the sign assumptions. FFT works best for frequency detection if the signal is normalized for zero DC. -- Without further knowledge on your setup and your data, I can do nothing further in your error analysis. – Lutz Lehmann Jan 31 '14 at 18:17
  • Well thanks very much for the help so far, i'm starting to get a better understanding of what's happening here, even if i'm not quite there yet! – user2212383 Jan 31 '14 at 20:08