Search code examples
iosfftvdsp

FFT with iOS vDSP not symmetrical


I'm using Apples vDSP APIs to calculate the FFT of audio. However, my results (in amp[]) aren't symmetrical around N/2, which they should be, from my understanding of FFTs on real inputs?

In the below frame is an array[128] of floats containing the audio samples.

        int numSamples = 128;
        vDSP_Length log2n = log2f(numSamples);
        FFTSetup fftSetup = vDSP_create_fftsetup(log2n, FFT_RADIX2);
        int nOver2 = numSamples/2;

        COMPLEX_SPLIT A;
        A.realp = (float *) malloc(nOver2*sizeof(float));
        A.imagp = (float *) malloc(nOver2*sizeof(float));

        vDSP_ctoz((COMPLEX*)frame, 2, &A, 1, nOver2);

        //Perform FFT using fftSetup and A
        //Results are returned in A
        vDSP_fft_zrip(fftSetup, &A, 1, log2n, FFT_FORWARD);

        //Convert COMPLEX_SPLIT A result to float array to be returned
        float amp[numSamples];
        amp[0] = A.realp[0]/(numSamples*2);
        for(int i=1;i<numSamples;i++) {
            amp[i]=A.realp[i]*A.realp[i]+A.imagp[i]*A.imagp[i];
            printf("%f ",amp[i]);
        }

If I put the same float array into an online FFT calculator I do get a symmetrical output. Am I doing something wrong above?

For some reason, most values in amp[] are around 0 to 1e-5, but I also get one huge value of about 1e23. I'm not doing any windowing here, just trying to get a basic FFT working initially.

I've attached a picture of the two FFT outputs, using the same data. You can see they are similar upto 64, although not by a constant scaling factor, so I'm not sure what they are different by. Then over 64 they are completely different.

enter image description here


Solution

  • To get symmetric results from strictly real inout to a basic FFT, your complex data input and output arrays have to be the same length as your FFT. You seem to be allocating and copying only half your data into the FFT input, which could be feeding non-real memory garbage to the FFT.