Skip to content
AI360Xpert
Beta

Discrete Fourier Transform and FFT

The DFT samples the spectrum at evenly spaced bins and the FFT computes those bins in $n \log n$ steps by halving the problem recursively.

Even and odd samples split into halves that combine through butterflies, halving the work at each of log n stages
Even and odd samples split into halves that combine through butterflies, halving the work at each of log n stages

Why Does This Exist?

Theory gives spectra as integrals; hardware holds finite samples. The DFT defines the spectrum on nn samples as nn bins Xk=∑t=0n−1xte−2πikt/nX_k = \sum_{t=0}^{n-1} x_t e^{-2\pi i k t/n}, and the naive sum costs O(n2)O(n^2): a 11-megapixel image row-by-row would stall. The FFT (Cooley-Tukey, 1965) exploits symmetries of roots of unity to cost O(nlog⁡n)O(n \log n), which is why spectral filtering, fast convolution, and spectral solvers run at all. Continuous theory is the parent Fourier page; filtering via bins is the convolution theorem.

The one idea you need first

The nnth roots of unity Wn=e−2πi/nW_n = e^{-2\pi i/n} repeat with period nn and square to half-size roots (Wn2=Wn/2W_n^2 = W_{n/2}). The FFT's halving reuses these symmetries: even and odd subsequences share twiddle factors instead of recomputing them.

Think of It Like This

Sorting tournament brackets

Counting every pairwise match among 1,0241{,}024 teams takes about a million games. A knockout bracket halves the field each round: 512512 matches, then 256256, down ten rounds to one final, totaling about 10,00010{,}000 games. Winners of sub-brackets combine without replaying internal matches.

The FFT brackets frequencies the same way. Split samples into even and odd halves, transform each half (the sub-tournaments), then combine with twiddle-factor weights (the finals). Each of log⁡2n\log_2 n rounds costs nn combines: nlog⁡nn \log n total instead of n2n^2.

How It Actually Works

Radix-2 decimation in time: Xk=Ek+WnkOkX_k = E_k + W_n^k O_k and Xk+n/2=Ek−WnkOkX_{k+n/2} = E_k - W_n^k O_k, where E,OE, O are the half-size DFTs of even and odd samples. One butterfly computes both outputs from (Ek,Ok)(E_k, O_k) with one multiply. Recurse to size 11; total nlog⁡2nn \log_2 n operations. Bit-reversal permutes inputs so the recursion runs in place.

Bin kk means frequency kfs/nk f_s/n for sampling rate fsf_s; resolution fs/nf_s/n. Off-bin tones leak across bins; windowing (Hann: taper edges) localizes leakage at the cost of wider peaks.

Worked example

n=1,024n = 1{,}024 audio samples at fs=8,192f_s = 8{,}192 Hz. Naive DFT: 1,0242≈1.051{,}024^2 \approx 1.05 million complex multiplies. FFT: 1,024×10=10,2401{,}024 \times 10 = 10{,}240: ratio above 100100. Resolution 8,192/1,024=88{,}192/1{,}024 = 8 Hz per bin: a 440440-Hz tone lands in bin 5555 exactly (55×8=44055 \times 8 = 440), peak height 512×512 \times amplitude. A 443443-Hz tone straddles bins 5555 and 5656 (leakage): Hann windowing concentrates 80%80\% of its energy into 33 bins instead of smearing over 1212.

Code

import cmath

def fft(xs: list[complex]) -> list[complex]:    n = len(xs)    if n == 1:        return xs  # base case    even = fft(xs[0::2])    odd = fft(xs[1::2])  # halve: decimation in time    out: list[complex] = [0j] * n    for k in range(n // 2):        tw = cmath.exp(-2j * cmath.pi * k / n) * odd[k]  # twiddle combine        out[k] = even[k] + tw  # butterfly top        out[k + n // 2] = even[k] - tw  # butterfly bottom    return out

xs = [1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0]  # cosine, period 4spec = [round(abs(c), 3) for c in fft([complex(x) for x in xs])]print(spec)  # -> peaks 4.0 at bins 2 and 6, zeros elsewhere

Bins 22 and 66 read 4.04.0 (half the 88 samples times amplitude 11); all others 00: exact binning for an on-grid tone.

Watch Out For

Reading leaked bins as separate tones

One off-grid tone paints a skirt across many bins; peak-pickers report five tones where one exists. Window first, then interpolate the true peak (parabolic or Quinn estimators) instead of counting local maxima.

Zero-padding to fake resolution

Appending zeros interpolates the spectrum (smoother curve) without adding information: two tones 44 Hz apart at 88-Hz resolution stay merged no matter the padding. Resolution comes from longer observation (fs/nf_s/n), never from padding length.

The Quick Version

  • The DFT bins finite samples; naive cost is O(n2)O(n^2).
  • The FFT halves recursively through butterflies to O(nlog⁡n)O(n \log n).
  • At n=1,024n = 1{,}024 the FFT needs 10,24010{,}240 steps versus 1.051.05 million: 100100 times faster.
  • Bin kk means kfs/nk f_s/n Hz; resolution is fs/nf_s/n (88 Hz in the example).
  • Off-grid tones leak; Hann windows concentrate energy threefold.
  • Zero-padding smooths without resolving; longer records resolve.