Using FFTW with DTSource

FFTW (site) is a widely used software library to compute the Discrete Fourier Transform.

The FFTW library is based on creating a data structure called a plan that is created based on the dimensions, if it is a forward or backward transform and the pointer for the input and output data. This is done to limit memory allocations and pre compute data structures.

This shows how to create two functions, the FFT for forward and iFFT for the backward transform. These are not optimal if you plan on calling the FFT multiple times but show how to use the DTSource array library with the FFTW library. Note that this is for the 2D fft. Change the plan function if you are doing 1D fft.

#include <fftw3.h>

DTMutableDoubleComplexArray FFT(const DTDoubleComplexArray &A)
{
    int m = int(A.m());
    int n = int(A.n());
    DTMutableDoubleComplexArray toReturn(m,n);
    fftw_complex *in = (fftw_complex *)A.Pointer();
    fftw_complex *out = (fftw_complex *)toReturn.Pointer();
	
    fftw_plan p = fftw_plan_dft_2d(n, m, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
    fftw_execute(p);
    fftw_destroy_plan(p);

    return toReturn;
}

And the inverse

DTMutableDoubleComplexArray iFFT(const DTDoubleComplexArray &A)
{
    int m = int(A.m());
    int n = int(A.n());
    DTMutableDoubleComplexArray toReturn(m,n);
    fftw_complex *in = (fftw_complex *)A.Pointer();
    fftw_complex *out = (fftw_complex *)toReturn.Pointer();
	
    fftw_plan p = fftw_plan_dft_2d(n, m, in, out, FFTW_BACKWARD, FFTW_ESTIMATE);
    fftw_execute(p);
    fftw_destroy_plan(p);
	
    return toReturn;
}

Note that when these

Lets dig into the details of this a little bit. The DTDoubleComplexArray is a class that is in many ways similar to DTDoubleArray. It wraps around an underlying data store that contains the array as a sequence of (real,imag) values for each index in a 1,2 or 3 dimensional array.

Getting the data

fftw_complex *in = (fftw_complex *)A.Pointer();

A.Pointer() gives the pointer to the underlying data for the complex array. This uses the same memory layout for a number as FFTW so you can cast that pointer into a fftw_complex pointer without problems.

Memory ownership

Note that the fftw_plan object does not copy the data but instead shares the memory with the DTDoubleComplexArray object. That means that the DTDoubleComplexArray needs to stay valid while you use the plan. Here it happens because the fftw_destroy_plan function is called before the array goes out of scope.

Layout

FFTW uses Row Major layout for memory, but DTSource uses Column Major. This is the reason why n goes before m in the line

fftw_plan p = fftw_plan_dft_2d(n, m, in, out, ...

Creating a complex array

The input and output are complex arrays. To convert your array to a complex array use

DTMutableDoubleComplexArray c = ConvertToDoubleComplex(d);

If d is a DTDoubleArray. It returns a mutable array but you can hand that into functions that expect a DTDoubleComplexArray. Make sure that you include that header file at the top of your source file

#include "DTDoubleComplexArray.h"

Converting from Complex to Real

To go back you can use

DTMutableDoubleArray real = RealPart(c);
DTMutableDoubleArray imag = ImaginaryPart(c);

Installing FFTW

Download fftw, go into the download directory and run the following commands in the terminal. The first command might be different depending on where your fftw was downloaded and uncompressed.

cd ~/Downloads/fftw-3.3.9/
./configure
make -j 5
sudo make install

You can test to make sure that things are installed by doing

ls /usr/local/include/
ls /user/local/lib/

Xcode

Including libfftw3 in your Xcode project includes two steps. You need to add an entry to the header search path so that you can include the fftw3.h header file and you need to include the library so that your program will link against it.

Add the header path. Note that you select the entry in the “Project” tab

Add the library

To include the library go into the main project entry (top of the list in the project folder listing), select your target, select the Build Phases tab and add the library into the “Link Binary With Libraries”

Note that when you hit the + button you get the following window.

Select “Add Files…” here

To go into the /usr/local/lib/ folder, you need to hit the “/” to get the following window. Make sure that you are not typing in the search bar. This is one of the hidden tricks to go to a particular folder. The /usr/ folder is not visible in the Finder by default. You can also show this folder by clicking shift-command-G.

Select libfftw.a

Search path for libraries

On some systems (Xcode 12) this is not enough to find the libary. In the same location as you used for the header search path there is a library search path. Add /usr/local/lib/ into that as well.