FFT_comparison.ipynb

by Abigail Stevens, A [dot] L (dot) Stevens {at} uva |dot| nl

This code is designed to compare different FFT functions in Python: SciPy, NumPy, and pyFFTW. It checks that the results are the same to numerical accuracy and times how long each takes to run. Note that for the 2D arrays, we are still taking a 1D FFT down one of the axes.


In [1]:
import pyfftw
import scipy.fftpack as fftpack
import numpy as np
import numpy.fft as npfft
import timeit

In [2]:
nseg = 100
n_bins = 8192
rate1D = np.random.random_integers(0,10000,n_bins)
rate2D = np.random.random_integers(0,10000,(n_bins, nseg))
print "Shape of 1D array:", np.shape(rate1D)
print "Shape of 2D array:", np.shape(rate2D)


Shape of 1D array: (8192,)
Shape of 2D array: (8192, 100)

Taking the 1D and 2D FFTs


In [3]:
scipy_1Dfft = fftpack.fft(rate1D)
## Still only taking a FFT in one dimension, but over a 2D array
scipy_2Dfft = fftpack.fft(rate2D, axis=0)

In [4]:
numpy_1Dfft = npfft.fft(rate1D)
numpy_2Dfft = npfft.fft(rate2D, axis=0)

In [5]:
in1D_array = pyfftw.n_byte_align_empty(n_bins, 16, 'complex128')
out1D_array = pyfftw.n_byte_align_empty(n_bins, 16, 'complex128')
fft1D_object = pyfftw.FFTW(in1D_array, out1D_array, flags=('FFTW_MEASURE',))
ifft1D_object = pyfftw.FFTW(in1D_array, out1D_array, direction='FFTW_BACKWARD', flags=('FFTW_MEASURE',), normalise_idft=False)

in2D_array = pyfftw.n_byte_align_empty((n_bins,nseg), 16, 'complex128')
out2D_array = pyfftw.n_byte_align_empty((n_bins,nseg), 16, 'complex128')
fft2D_object = pyfftw.FFTW(in2D_array, out2D_array, flags=('FFTW_MEASURE',), threads=50, axes=(0,))
ifft2D_object = pyfftw.FFTW(in2D_array, out2D_array, direction='FFTW_BACKWARD', flags=('FFTW_MEASURE',), threads=50, axes=(0,), normalise_idft=False)

In [6]:
in1D_array[:] = rate1D + 0j
pyfftw_1Dfft = fft1D_object(in1D_array)

in2D_array[:] = rate2D + 0j
pyfftw_2Dfft = fft2D_object(in2D_array)

Checking that the results are the same, to numerical accuracy


In [7]:
print np.allclose(scipy_1Dfft, pyfftw_1Dfft)
print np.allclose(numpy_1Dfft, pyfftw_1Dfft)
print np.allclose(scipy_1Dfft, numpy_1Dfft)


True
True
True

In [8]:
print np.allclose(scipy_2Dfft, pyfftw_2Dfft)
print np.allclose(numpy_2Dfft, pyfftw_2Dfft)
print np.allclose(scipy_2Dfft, numpy_2Dfft)


True
True
True

Timing the functions


In [9]:
print "SciPy, FFT, 1D:"
%timeit fftpack.fft(rate1D)
print "pyFFTW, FFT, 1D:"
%timeit fft1D_object(in1D_array)
print "NumPy, FFT, 1D:"
%timeit npfft.fft(rate1D)


SciPy, FFT, 1D:
10000 loops, best of 3: 113 µs per loop
pyFFTW, FFT, 1D:
1000 loops, best of 3: 260 µs per loop
NumPy, FFT, 1D:
1000 loops, best of 3: 210 µs per loop

In [10]:
print "SciPy, FFT, 2D:"
%timeit fftpack.fft(rate2D, axis=0)
print "pyFFTW, FFT, 2D:"
%timeit fft2D_object(in2D_array)
print "NumPy, FFT, 2D:"
%timeit npfft.fft(rate2D, axis=0)


SciPy, FFT, 2D:
10 loops, best of 3: 17.2 ms per loop
pyFFTW, FFT, 2D:
10 loops, best of 3: 26.5 ms per loop
NumPy, FFT, 2D:
10 loops, best of 3: 33.4 ms per loop

And now, checking iFFT


In [11]:
print "SciPy, iFFT, 1D:"
%timeit fftpack.ifft(scipy_1Dfft)
print "pyFFTW, iFFT, 1D:"
%timeit ifft1D_object(pyfftw_1Dfft)
print "NumPy, iFFT, 1D:"
%timeit npfft.ifft(numpy_1Dfft)


SciPy, iFFT, 1D:
1000 loops, best of 3: 200 µs per loop
pyFFTW, iFFT, 1D:
1000 loops, best of 3: 290 µs per loop
NumPy, iFFT, 1D:
1000 loops, best of 3: 279 µs per loop

In [12]:
print "SciPy, iFFT, 2D:"
%timeit fftpack.ifft(scipy_2Dfft, axis=0)
print "pyFFTW, iFFT, 2D:"
%timeit ifft2D_object(pyfftw_2Dfft)
print "NumPy, iFFT, 2D:"
%timeit npfft.ifft(numpy_2Dfft, axis=0)


SciPy, iFFT, 2D:
10 loops, best of 3: 25.2 ms per loop
pyFFTW, iFFT, 2D:
10 loops, best of 3: 21.9 ms per loop
NumPy, iFFT, 2D:
10 loops, best of 3: 38.7 ms per loop

Done!


In [12]: