SciPy Cheatsheet

FFT

Use this SciPy reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

Core Import

from scipy.fft import (
    fft, ifft, rfft, irfft, fft2, ifft2, fftn, ifftn,
    rfft2, rfftn, irfftn,
    fftfreq, rfftfreq, fftshift, ifftshift,
    dct, idct, dst, idst,
    next_fast_len, set_workers
)
import numpy as np

Prefer scipy.fft over the legacy scipy.fftpack (frozen) and over numpy.fft when you need real-input transforms, DCT/DST, multithreading, or better performance on large arrays.

1-D FFT

from scipy.fft import fft, ifft, fftfreq, fftshift

# Sample a signal: 2 Hz + 8 Hz sine, fs = 100 Hz
fs = 100
t = np.arange(0, 1, 1/fs)
x = np.sin(2*np.pi*2*t) + 0.5*np.sin(2*np.pi*8*t)

X = fft(x)                    # complex spectrum, length n
freqs = fftfreq(len(x), d=1/fs)  # bin frequencies (0, ..., +f, -f, ...)

# Amplitude spectrum (one-sided)
n = len(x)
amp = 2/n * np.abs(X[:n//2])
f_pos = freqs[:n//2]

# Center zero frequency for plotting
X_shifted = fftshift(X)
f_shifted = fftshift(freqs)

# Round-trip
x_back = ifft(X)              # complex; np.real(x_back) recovers x

# Zero-padding / truncation via n
X = fft(x, n=256)             # pad to 256 points

Real-Input FFT (rfft)

from scipy.fft import rfft, irfft, rfftfreq

# Real input -> only non-negative frequencies (n//2 + 1 bins), ~2x faster
X = rfft(x)                   # shape (n//2 + 1,)
freqs = rfftfreq(len(x), d=1/fs)

x_back = irfft(X, n=len(x))   # pass n for odd-length signals

Always use rfft for real signals — half the memory, no redundant negative frequencies, and irfft returns a real array directly.

N-D FFT

from scipy.fft import fft2, ifft2, fftn, ifftn, fftshift

img = np.random.rand(256, 256)

F = fft2(img)                     # 2-D FFT
F_centered = fftshift(F)          # DC component to center
power = np.abs(F_centered)**2     # power spectrum

img_back = np.real(ifft2(F))

# Arbitrary dimensions / axes
F = fftn(volume)                  # all axes
F = fftn(arr, axes=(0, 1))        # only some axes

DCT & DST

from scipy.fft import dct, idct, dst, idst

x = np.array([1.0, 2.0, 1.0, -1.0, 1.5])

# Discrete cosine transform (type 2 is the default, the "JPEG" DCT)
y = dct(x, type=2, norm='ortho')
x_back = idct(y, type=2, norm='ortho')

# Discrete sine transform
y = dst(x, type=2, norm='ortho')

Use norm='ortho' to make the transform orthonormal so idct(dct(x)) round-trips without scale factors.

Performance

from scipy.fft import fft, fftn, next_fast_len, set_workers

# FFT is fastest on sizes that factor into small primes
n = len(x)
n_fast = next_fast_len(n)          # smallest fast size >= n
X = fft(x, n=n_fast)               # zero-pad to a fast length

# Multithreaded transforms
X = fft(big_array, workers=4)      # per-call

with set_workers(4):               # scoped default
    X = fftn(volume)

Convolution via FFT

from scipy.signal import fftconvolve, oaconvolve

# Fast convolution of long signals (uses scipy.fft internally)
y = fftconvolve(sig, kernel, mode='same')

# Overlap-add: best when one input is much longer than the other
y = oaconvolve(long_sig, short_kernel, mode='same')

Common Gotchas

fft output is unnormalized. Divide by n (and multiply single-sided amplitudes by 2) to recover physical amplitudes; or pass norm='ortho' for a symmetric 1/√n convention on both directions.

Spectral leakage: an FFT assumes the signal is periodic in the window. Apply a window (scipy.signal.get_window('hann', n)) before the FFT for non-periodic data.

irfft needs n for odd lengths. irfft(rfft(x)) returns an even-length array by default — pass irfft(X, n=len(x)) to round-trip odd-length signals exactly.

Frequency ordering: raw fft output is [0, positive freqs, negative freqs]. Use fftshift + fftshift(fftfreq(n, d)) before plotting, or rfft/rfftfreq to avoid negative bins entirely.