iPhone FFT with Accelerate framework vDSP

前端 未结 3 1696
臣服心动
臣服心动 2020-12-23 15:49

I\'m having difficulty implementing an FFT using vDSP. I understand the theory but am looking for a specific code example please.

I have data from a wav file as bel

相关标签:
3条回答
  • 2020-12-23 15:57

    One thing you need to be careful to is the DC component of the calculated FFT. I compared my results with the fftw library FFT and the imaginary part of the transform calculated with the vDSP library always had a different value at index 0 (which means 0 frequency, so DC). Another measure I applied was to divide both real and imaginary parts by a factor of 2. I guess this is due to the algorithm used in the function. Also, both these problems occurred in the FFT process but not in the IFFT process.

    I used vDSP_fft_zrip.

    0 讨论(0)
  • 2020-12-23 16:04

    You can check Apple’s documentation and take good care of data packing.

    Here is my example:

    //  main.cpp
    //  FFTTest
    //
    //  Created by Harry-Chris Stamatopoulos on 11/23/12.
    //  
    
    /* 
     This is an example of a hilbert transformer using 
     Apple's VDSP fft/ifft & other VDSP calls.
     Output signal has a PI/2 phase shift.
     COMPLEX_SPLIT vector "B" was used to cross-check
     real and imaginary parts coherence with the original vector "A"
     that is obtained straight from the fft.
     Tested and working. 
     Cheers!
    */
    
    #include <iostream>
    #include <Accelerate/Accelerate.h>
    #define PI 3.14159265
    #define DEBUG_PRINT 1
    
    int main(int argc, const char * argv[])
    {
        float fs = 44100;           //sample rate
        float f0 = 440;             //sine frequency
        uint32_t i = 0;
    
        uint32_t L = 1024;
    
        /* vector allocations*/
        float *input = new float [L];
        float *output = new float[L];
        float *mag = new float[L/2];
        float *phase = new float[L/2];
    
        for (i = 0 ; i < L; i++)
        {
            input[i] = cos(2*PI*f0*i/fs);
        }
    
        uint32_t log2n = log2f((float)L);
        uint32_t n = 1 << log2n;
        //printf("FFT LENGTH = %lu\n", n);
    
        FFTSetup fftSetup;
        COMPLEX_SPLIT A;
        COMPLEX_SPLIT B;
        A.realp = (float*) malloc(sizeof(float) * L/2);
        A.imagp = (float*) malloc(sizeof(float) * L/2);
    
        B.realp = (float*) malloc(sizeof(float) * L/2);
        B.imagp = (float*) malloc(sizeof(float) * L/2);
    
        fftSetup = vDSP_create_fftsetup(log2n, FFT_RADIX2);
    
        /* Carry out a Forward and Inverse FFT transform. */
        vDSP_ctoz((COMPLEX *) input, 2, &A, 1, L/2);
        vDSP_fft_zrip(fftSetup, &A, 1, log2n, FFT_FORWARD);
    
        mag[0] = sqrtf(A.realp[0]*A.realp[0]);
    
        //get phase
        vDSP_zvphas (&A, 1, phase, 1, L/2);
        phase[0] = 0;
    
        //get magnitude;
        for(i = 1; i < L/2; i++){
            mag[i] = sqrtf(A.realp[i]*A.realp[i] + A.imagp[i] * A.imagp[i]);
        }
    
        //after done with possible phase and mag processing re-pack the vectors in VDSP format
        B.realp[0] = mag[0];
        B.imagp[0] = mag[L/2 - 1];;
    
        //unwrap, process & re-wrap phase
        for(i = 1; i < L/2; i++){
            phase[i] -= 2*PI*i * fs/L;
            phase[i] -= PI / 2 ;
            phase[i] += 2*PI*i * fs/L;
        }
    
        //construct real & imaginary part of the output packed vector (input to ifft)
        for(i = 1; i < L/2; i++){
            B.realp[i] = mag[i] * cosf(phase[i]);
            B.imagp[i] = mag[i] * sinf(phase[i]);
        }
    
    #if DEBUG_PRINT
        for (i = 0 ; i < L/2; i++)
        {
           printf("A REAL = %f \t A IMAG = %f \n", A.realp[i], A.imagp[i]);
           printf("B REAL = %f \t B IMAG = %f \n", B.realp[i], B.imagp[i]);
        }
    #endif
        //ifft
        vDSP_fft_zrip(fftSetup, &B, 1, log2n, FFT_INVERSE);
    
        //scale factor
        float scale = (float) 1.0 / (2*L);
    
        //scale values
        vDSP_vsmul(B.realp, 1, &scale, B.realp, 1, L/2);
        vDSP_vsmul(B.imagp, 1, &scale, B.imagp, 1, L/2);
    
        //unpack B to real interleaved output
        vDSP_ztoc(&B, 1, (COMPLEX *) output, 2, L/2);
    
        // print output signal values to console
        printf("Shifted signal x = \n");
        for (i = 0 ; i < L/2; i++)
            printf("%f\n", output[i]);
    
        //release resources
        free(input);
        free(output);
        free(A.realp);
        free(A.imagp);
        free(B.imagp);
        free(B.realp);
        free(mag);
        free(phase);
    }
    
    0 讨论(0)
  • 2020-12-23 16:17
    1. You put your audio sample data into the real part of the input, and zero the imaginary part.

    2. If you are just interested in the magnitude of each bin in the frequency domain then you calculate sqrt(re*re + im*im) for each output bin. If you're only interested in relative magnitude then you can drop the sqrt and just calculate the squared magnitude, (re*re + im*im).

    3. You would look at the magnitudes of the bin or bins (see (2)) that correspond to your frequency or frequencies of interest. If your sample rate is Fs, and your FFT size is N, then the corresponding frequency for output bin i is given by f = i * Fs / N. Conversely if you are interested in a specific frequency f then the bin of interest, i, is given by i = N * f / Fs.

    Additional note: you will need to apply a suitable window function (e.g. Hann aka Hanning) to your FFT input data, prior to calculating the FFT itself.

    0 讨论(0)
提交回复
热议问题