Search code examples
c++cfftwspectrum

how to do spectrum analyse with FFTW?


I would like to better understand FFTW's API. FFTW is a library for computing the discrete Fourier transform (DFT) in one or more dimensions.

Now, assume I have a sinus waveform x=30*sin(2*M_PI*f*i*T), where f is the frequency (for example f=1000Hz). If I use FFTW's function to analyse my waveform, I expect to get one frequency f=1000Hz.

My question is how can I do this in c++ using FFTW Library? Any help would be appreciated.


Solution

  • You can find more details in FFTW's documentation.

    However, for the relatively simple case of one-dimensional real-valued signal, the following is a sum-up of the general steps you have to do.

    Typically you would need to allocate input/output buffers, and a data-structure which FFTW uses for its own bookkeeping which the library refers as a plan. This can be done in a number of ways (more details in FFTW's documentation), such as:

      #include "fftw3.h"
    
      // First choose a buffer size:
      //   Typically best performance with a power of 2
      //   but could be a product of small primes
      int           input_size    = 1024; 
      //   Compute corresponding number of complex output samples
      int           output_size   = (input_size/2 + 1);
    
      // Allocate input and output buffers
      double*       input_buffer  = static_cast<double*      >(fftw_malloc(input_size  * sizeof(double)));
      fftw_complex* output_buffer = static_cast<fftw_complex*>(fftw_malloc(output_size * sizeof(fftw_complex)));
    
      // Create plan
      //   Select plan creation flags
      //   see http://www.fftw.org/fftw3_doc/Planner-Flags.html#Planner-Flags
      int           flags = FFTW_ESTIMATE;
      fftw_plan     plan = fftw_plan_dft_r2c_1d(input_size, 
                                                input_buffer, 
                                                output_buffer, 
                                                flags);
    

    Once that is done, you can fill in the input_buffer with the real-valued data samples to analyse, and perform the FFT using:

     fftw_execute(plan);
    

    The complex-valued results will be stored in output_buffer, where output_buffer[0] corresponds to a frequency of 0, and output_buffer[output_size-1] corresponds to half the sampling rate. This plan can be executed multiple times (with updated values in input_buffer, resulting in correspondingly updated values in output_buffer).

    Note that typically fftw_complex (which is the datatype used for the output in this example) is implemented as an array of 2 values: index 0 corresponds to the real-part, and index 1 corresponds to the imaginary-part (e.g. output_buffer[i][0] corresponds to the real-part of the ith frequency component).

    Once you are done, you can release allocated resources with:

      fftw_free(input_buffer);
      fftw_free(output_buffer);
      fftw_destroy_plan(plan);
    

    Note that if you may use float, double or long double versions of those functions. Simply link against the corresponding libfftw3f-3.lib, libfftw3-3.lib or libfftw3l-3.lib.

    Update: If you want to use complex-valued input samples together with fftw_plan_dft_1d, you will then have to set the real and imaginary parts like so:

    for (i = 0; i < N-1; ++i) {
      t[i]=i*T;
      signal[i][0] = 0.7 * sin(2*M_PI*f*t[i]); // real-part
      signal[i][1] = 0.0; // imaginary-part
    }
    

    Alternatively change the input sample type to float, double or long double (together with using fftw_plan_dft_r2c_1d).