Outline
15.1 Computing the DFT Directly
15.2 Decimation-in-Time FFT
15.3 The Complete Radix-2 FFT
15.4 FFT Variations
15.5 The FFT in MATLAB
15.6 Summary
Exercises
DSP Study Guide · Chapter 15

The Fast Fourier Transform

Why the direct DFT costs O(N²), how Goertzel's algorithm and the decimation-in-time radix-2 FFT exploit twiddle-factor structure, butterflies, bit reversal, in-place computation, and fast transforms in practice

15.1 Computing the DFT Directly

15.1.1 The DFT and twiddle factors

Chapter 8 introduced the DFT as the discrete transform of a discrete (finite-length) sequence. Recall its definition, written compactly using the twiddle factor(旋轉因子) $W_N$:

DFT and twiddle factor $$X[k] = \sum_{n=0}^{N-1} x[n]\, W_N^{kn}, \qquad k = 0,\dots,N-1, \qquad W_N \equiv e^{-j\frac{2\pi}{N}}$$

$W_N$ is a unit-magnitude complex number sitting at angle $-2\pi/N$ on the unit circle. Because $W_N^{r}$ only depends on $r \bmod N$, the powers $W_N^r$ take on only $N$ distinct values — the $N$-th roots of unity. Two consequences of this structure drive everything in this chapter:

Twiddle-factor properties $$\underbrace{W_N^{r+N} = W_N^{r}}_{\text{periodicity 週期性}} \qquad \underbrace{W_N^{\,r+N/2} = -\,W_N^{r}}_{\text{half-period symmetry 對稱性}} \qquad \underbrace{W_N^{2} = W_{N/2}}_{\text{index halving}}$$

In matrix form the DFT is a dense $N\times N$ matrix–vector product,

Matrix form $$\begin{bmatrix} X[0]\\ X[1]\\ X[2]\\ \vdots\\ X[N-1] \end{bmatrix} = \begin{bmatrix} 1 & 1 & 1 & \cdots & 1\\ 1 & W_N^{1} & W_N^{2} & \cdots & W_N^{(N-1)}\\ 1 & W_N^{2} & W_N^{4} & \cdots & W_N^{2(N-1)}\\ \vdots & \vdots & \vdots & \ddots & \vdots\\ 1 & W_N^{(N-1)} & W_N^{2(N-1)} & \cdots & W_N^{(N-1)^2} \end{bmatrix} \begin{bmatrix} x[0]\\ x[1]\\ x[2]\\ \vdots\\ x[N-1] \end{bmatrix}$$

but the matrix is anything but arbitrary: every entry is one of only $N$ values, and the entries are arranged in a highly regular pattern. Figure 15-1 visualizes the real and imaginary parts of the $N=32$ DFT matrix — the structure(規律性結構)is exactly the opportunity for efficiency that the FFT exploits.

2026-06-12T22:38:04.002423 image/svg+xml Matplotlib v3.10.8, https://matplotlib.org/ 0 10 20 30 n 0 5 10 15 20 25 30 k R e { }     ( N   =   3 2 ) W N k n 0 10 20 30 n 0 5 10 15 20 25 30 k I m { }     ( N   =   3 2 ) W N k n −1.00 −0.75 −0.50 −0.25 0.00 0.25 0.50 0.75 1.00
Fig. 15-1 — Real and imaginary parts of the DFT matrix $W_N^{kn}$ for $N=32$. Each row $k$ is a sampled complex exponential; the regular pattern (only $N$ distinct values, mirror symmetries) is what fast algorithms exploit.(DFT 矩陣高度規律,並非任意矩陣 — 這正是 FFT 可以加速的原因。)

15.1.2 Cost of direct evaluation

Evaluate the DFT sum literally. For each output point $X[k]$ we need $N$ complex multiplies and $N-1$ complex adds; there are $N$ output points ($k = 0,\dots,N-1$). Converting to real arithmetic with

$(a+jb)(c+jd) = (ac-bd) + j(ad+bc)$ = 4 real mults + 2 real adds,   1 complex add = 2 real adds,

the total damage is:

Direct DFT cost $$\text{complex: } N^2 \text{ mults},\; N(N-1) \text{ adds} \qquad\Longrightarrow\qquad \boxed{\,4N^2 \text{ real mults},\quad 4N^2 - 2N \text{ real adds}\,}$$
Why O(N²) hurts

The cost grows with the square of the length: doubling $N$ quadruples the work. At $N = 1024$ the direct DFT needs about $4\times 10^6$ complex operations; at $N = 10^6$ (one second of audio at 1 MHz) it needs $10^{12}$ — completely impractical for real-time processing. An $O(N^2)$ barrier(直接計算的平方複雜度)is the reason the 1965 Cooley–Tukey FFT is routinely listed among the most important algorithms of the 20th century.

15.1.3 Goertzel's algorithm

Before attacking the full DFT, the lecture gives a first taste of exploiting twiddle structure: Goertzel's algorithm(Goertzel 演算法) computes a single DFT bin as the output of a small recursive filter. Start from the DFT sum and pull out a factor $W_N^{kN} = 1$:

DFT bin as a convolution $$X[k] = \sum_{\ell=0}^{N-1} x[\ell]\, W_N^{k\ell} = W_N^{kN}\sum_{\ell} x[\ell]\, W_N^{-k(N-\ell)}$$

The right-hand sum looks like a convolution evaluated at time $N$: it is $\sum_\ell x[\ell]\, h_k[N-\ell]$ with $h_k[n] = W_N^{-kn}u[n]$. Therefore

Goertzel recursion $$X[k] = y_k[N], \qquad y_k[n] = x_e[n] \circledast h_k[n], \qquad h_k[n] = \begin{cases} W_N^{-kn} & n \ge 0\\ 0 & n < 0\end{cases}$$ $$\text{with } x_e[n] = \begin{cases} x[n] & 0 \le n < N\\ 0 & n = N \end{cases} \qquad\Longrightarrow\qquad y_k[n] = x_e[n] + W_N^{-k}\, y_k[n-1],\quad y_k[-1]=0$$

So one first-order complex recursion, clocked $N+1$ times (feeding $x_e[N]=0$ at the end), delivers $y_k[N] = X[k]$:

xe[n] + yk[n] z−1 WN−k yk[−1] = 0,   xe[N] = 0 yk[N] = X[k]
Fig. 15-2 — Goertzel's algorithm: a first-order recursive filter whose state after $N$ steps equals one DFT bin $X[k]$.(用一個一階遞迴濾波器「跑」過整段訊號,最後一步的輸出就是單一頻點 $X[k]$。)

Properties claimed on the slide, worth memorizing:

Goertzel, second-order form $$H(z) = \frac{1}{1 - W_N^{-k} z^{-1}} = \frac{1 - W_N^{k} z^{-1}}{1 - 2\cos\!\big(\tfrac{2\pi k}{N}\big) z^{-1} + z^{-2}}$$

The recursion now uses the real coefficient $2\cos(2\pi k/N)$ — only 2 real mults per step — and the complex numerator $(1 - W_N^k z^{-1})$ is evaluated only once, at the last step $n=N$.

When Goertzel beats the FFT

Goertzel costs $O(N)$ per bin; the FFT costs $O(N\log_2 N)$ for all $N$ bins. So if you need only $M$ bins, Goertzel wins roughly when $M \lesssim \log_2 N$. A DTMF detector needing 8 tone frequencies out of $N=205$ samples is the classic use case.(只要少數幾個頻點時用 Goertzel,整條頻譜都要時用 FFT。)

15.2 Decimation-in-Time FFT

15.2.1 Splitting the DFT into even/odd halves

The decimation-in-time(時間抽取)DIT FFT rearranges the DFT sum into two halves: terms with even time index $n=2m$ and terms with odd index $n = 2m+1$ (assume $N$ even, ultimately $N = 2^M$):

DIT split — derivation $$\begin{aligned} X[k] &= \sum_{n=0}^{N-1} x[n]\, W_N^{nk}, \qquad k = 0,\dots,N-1\\[2pt] &= \sum_{m=0}^{\frac{N}{2}-1}\Big( x[2m]\,W_N^{2mk} + x[2m+1]\, W_N^{(2m+1)k}\Big)\\[2pt] &= \underbrace{\sum_{m=0}^{\frac{N}{2}-1} x[2m]\, W_{N/2}^{mk}}_{\textstyle X_0\big[\langle k\rangle_{N/2}\big]} \;+\; W_N^{k}\underbrace{\sum_{m=0}^{\frac{N}{2}-1} x[2m+1]\, W_{N/2}^{mk}}_{\textstyle X_1\big[\langle k\rangle_{N/2}\big]} \end{aligned}$$

The key step uses $W_N^{2mk} = W_{N/2}^{mk}$ (index halving). $X_0$ is the $N/2$-point DFT of the even-indexed samples, and $X_1$ is the $N/2$-point DFT of the odd-indexed samples. Because an $N/2$-point DFT is periodic in $k$ with period $N/2$, we evaluate both at $\langle k\rangle_{N/2}$ ($k$ modulo $N/2$). The result, in the lecture's compact notation:

One-step DIT decomposition $$\mathrm{DFT}_N\{x[n]\} \;=\; \mathrm{DFT}_{\frac{N}{2}}\{x_0[n]\} \;+\; W_N^{k}\,\mathrm{DFT}_{\frac{N}{2}}\{x_1[n]\} \qquad \begin{cases} x_0[n] = x[2n] & \text{even samples}\\ x_1[n] = x[2n+1] & \text{odd samples} \end{cases}$$
直觀解釋(點擊展開)
把 $N$ 點訊號按「偶數位置」與「奇數位置」抽開(這就是「時間抽取」的意思),各自做 $N/2$ 點 DFT。偶數那組直接貢獻 $X_0[k]$;奇數那組因為整體往右平移了一格,依時移性質要多乘一個相位 $W_N^k$(旋轉因子)。兩者相加就還原出完整的 $N$ 點 DFT。重點在於:兩個小 DFT 的成本各是 $(N/2)^2$,加起來只有原本 $N^2$ 的一半 — 而且這招可以對小 DFT 反覆使用,一路砍到只剩 2 點 DFT 為止。

Why does this save anything? Count again:

One split ≈ half the work $$\mathrm{DFT}_N \sim O(N^2),\qquad \mathrm{DFT}_{N/2} \sim O\big((N/2)^2\big) = \tfrac14\,O(N^2) \;\;\Longrightarrow\;\; \text{total} \sim 2\cdot\tfrac14\,O(N^2) = \tfrac12\,O(N^2)\;(+\,\varepsilon)$$

One split halves the computation (the $\varepsilon$ accounts for the $N$ extra twiddle multiplies and adds needed to combine the halves). We can evaluate an $N$-pt DFT as two $N/2$-pt DFTs plus a few mults/adds.

15.2.2 One-stage DIT flowgraph

Writing the combination for all $k = 0,\dots,N-1$ and using periodicity $X_0[\langle k\rangle_{N/2}]$, $X_1[\langle k\rangle_{N/2}]$, the structure for $N=8$ is shown in Fig. 15-3. Note carefully — as the slide stresses — the twiddle factors $W_N^k$ always apply to the odd-half output $X_1[\cdot]$, and they are NOT mirror-imaged: output $X[k+N/2]$ uses $W_N^{k+N/2} = -W_N^k$, not $W_N^{k}$ again.

x[0] x[2] x[4] x[6] x[1] x[3] x[5] x[7] DFT₄ even n DFT₄ odd n X₀[0] X₀[1] X₀[2] X₀[3] X₁[0] X₁[1] X₁[2] X₁[3] W₈⁰ W₈¹ W₈² W₈³ −1 −1 −1 −1 X[0] X[1] X[2] X[3] X[4] X[5] X[6] X[7] classic FFT structure
Fig. 15-3 — One-stage DIT decomposition of an 8-pt DFT (simplified butterflies): $X[k] = X_0[k] + W_8^{k}X_1[k]$ and $X[k+4] = X_0[k] - W_8^{k}X_1[k]$ for $k=0..3$. Twiddles apply only to the odd-half outputs $X_1[\cdot]$; the $-1$ on the lower horizontal branch implements $W_8^{k+4} = -W_8^k$.(旋轉因子只乘在奇數那一半的輸出上,下半部輸出用減法。)

15.2.3 Recursing to multiple stages

If decomposing one $\mathrm{DFT}_N$ into two smaller $\mathrm{DFT}_{N/2}$'s speeds things up — why not further divide into $\mathrm{DFT}_{N/4}$'s? Apply the identical split to $X_0[k]$ (the even-sample DFT): split its inputs into even-of-even and odd-of-even subsets:

Second-level split $$X[k] = X_0\big[\langle k\rangle_{\frac N2}\big] + W_N^{k} X_1\big[\langle k\rangle_{\frac N2}\big],\qquad 0 \le k < N$$ $$X_0[k] = X_{00}\big[\langle k\rangle_{\frac N4}\big] + W_{\frac N2}^{\,k} X_{01}\big[\langle k\rangle_{\frac N4}\big],\qquad 0 \le k < N/2$$ $$X_1[k] = X_{10}\big[\langle k\rangle_{\frac N4}\big] + W_{\frac N2}^{\,k} X_{11}\big[\langle k\rangle_{\frac N4}\big]$$

where $X_{00}$ is the $N/4$-pt DFT of the even points within the even subset of $x[n]$ (i.e. $x[0],x[4],x[8],\dots$), $X_{01}$ the $N/4$-pt DFT of the odd points of the even subset, and so on. Note that the second-level twiddle is $W_{N/2}^{k}$ — for $N=8$ that means $W_4^k = W_8^{2k}$, so only $W_8^0$ and $W_8^2$ appear in the second stage.

Keep recursing until we hit 2-point DFTs, which need no multiplies at all:

2-pt DFT — the atomic butterfly $$\mathrm{DFT}_2:\quad X[0] = x[0] + x[1], \qquad X[1] = x[0] - x[1] \qquad (1 = W_2^0,\;\; -1 = W_2^1)$$

An $N = 2^M$-point DFT thus reduces to $M = \log_2 N$ stages of twiddle factors and summation — the $O(N^2)$ part vanishes entirely.

15.2.4 The butterfly and its simplification

At every stage the elementary operation pairs two values $r$ and $r + N/2$ apart and produces two outputs. This is the butterfly(蝶形運算). As first derived, it needs two complex multiplies, $W_N^r$ and $W_N^{r+N/2}$. But by half-period symmetry,

Twiddle symmetry kills one multiply $$W_N^{\,r+\frac N2} = e^{-j\frac{2\pi (r+\frac N2)}{N}} = e^{-j\frac{2\pi r}{N}}\cdot e^{-j\frac{2\pi (N/2)}{N}} = W_N^{r}\cdot e^{-j\pi} = -\,W_N^{r}$$

so the second multiply is just the negative of the first — i.e. subtract rather than add. Each butterfly then costs one complex multiply and two complex adds:

(a) Butterfly as derived — 2 complex mults X₀[r] X₁[r] WNr WNr+N/2 X[r] X[r+N/2] (b) Simplified butterfly — just 1 complex mult X₀[r] X₁[r] WNr −1 i.e. SUB rather than ADD X[r] X[r+N/2]
Fig. 15-4 — The basic butterfly. (a) As derived: gains $W_N^{r}$ (to the top output) and $W_N^{r+N/2}$ (to the bottom output) on the two edges leaving $X_1[r]$ — two complex multiplies. (b) Since $W_N^{r+N/2} = -W_N^{r}$, multiply $X_1[r]$ by $W_N^{r}$ once, then add for $X[r]$ and subtract for $X[r+N/2]$ — one complex multiply.(蝶形運算化簡:下半輸出改用減法,省掉一次複數乘法。)
Simplified butterfly equations $$\boxed{\;X[r] = X_0[r] + W_N^{r}\,X_1[r], \qquad X\big[r+\tfrac N2\big] = X_0[r] - W_N^{r}\,X_1[r]\;}$$

15.3 The Complete Radix-2 FFT

15.3.1 The 8-point DIT flowgraph

Assembling all $M = \log_2 8 = 3$ stages of simplified butterflies gives the classic flowgraph of Fig. 15-5. Trace any output back: stage 1 computes four 2-pt DFTs, stage 2 merges them into two 4-pt DFTs (twiddles $W_8^0, W_8^2$ — i.e. $W_4^0, W_4^1$), stage 3 merges those into the final 8-pt DFT (twiddles $W_8^0,\dots,W_8^3$).

000 100 010 110 001 101 011 111 x[0] x[4] x[2] x[6] x[1] x[5] x[3] x[7] −1 −1 −1 −1 W₈² W₈² −1 −1 −1 −1 W₈¹ W₈² W₈³ −1 −1 −1 −1 X[0] X[1] X[2] X[3] X[4] X[5] X[6] X[7] Stage 1 — four 2-pt DFTs Stage 2 — two 4-pt DFTs Stage 3 — one 8-pt DFT
Fig. 15-5 — Complete 8-pt DIT FFT flowgraph (simplified butterflies). Inputs enter in bit-reversed order (green binary labels), outputs leave in natural order. All $W_8^0 = 1$ multipliers have disappeared; the $-1$'s are absorbed into the summation nodes (lower butterfly branch subtracts). Stage 2 uses $W_8^0, W_8^2$ ($=W_4^0, W_4^1$); stage 3 uses $W_8^0, W_8^1, W_8^2, W_8^3$.(輸入位元反轉排序、輸出自然排序;每級只剩一半的旋轉因子乘法。)
Reading the flowgraph

In stage $s$ ($s = 1,\dots,M$) the butterflies span $2^{s-1}$ rows and the twiddles are powers of $W_{2^s}$, equivalently $W_N^{rN/2^s}$. Only $N/2$ complex multiplies can occur per stage (one per butterfly), and many of those are by $W^0 = 1$ and cost nothing. Trivial factors: $W^0=1$ (free), $W_8^2 = -j$ (a swap of real/imag parts plus sign — also multiplication-free in practice).

15.3.2 Bit-reversed input ordering

Each DIT split sends even-indexed samples up and odd-indexed samples down — i.e. it sorts on the least significant bit (LSB) of the time index. Recursing sorts on the next bit, and so on. After $M$ levels, the sample at input row $r$ is $x[\text{bit-reverse}(r)]$: the address with its $M$-bit binary representation reversed(位元反轉).

Row $r$$r$ binaryreversedinput sample
0000000$x[0]$
1001100$x[4]$
2010010$x[2]$
3011110$x[6]$
4100001$x[1]$
5101101$x[5]$
6110011$x[3]$
7111111$x[7]$
直觀解釋(點擊展開)
為什麼是「位元反轉」?第一次抽取按「最低位元」分組(偶數 LSB=0 在上、奇數 LSB=1 在下);對每半再抽取一次,是按「第二低位元」分組,依此類推。所以樣本最後落在哪一列,是由它的索引位元「由低到高」依序決定的 — 等於把二進位位址整個反過來讀。例如 $x[6]=x[110_2]$:LSB=0 進上半,次位=1 進上半的下半,最高位=1 → 列 $011_2=3$。實作上只要把陣列先做一次位元反轉重排,後面所有蝶形就可以順序進行。

15.3.3 In-place computation

Look again at Fig. 15-5: every butterfly takes two values from rows $(p, q)$ and writes its two outputs back to the same two rows $(p, q)$. No other butterfly in that stage touches those rows. Consequently the whole FFT is an in-place algorithm(原位演算法): one length-$N$ complex array suffices — after the initial bit-reversal shuffle, the $M$ stages overwrite the array sequentially, and the final array contents are $X[0],\dots,X[N-1]$ in natural order. Memory cost: $N$ complex words plus a small twiddle table (or none for Goertzel-style on-the-fly generation).

15.3.4 Complexity: (N/2) log₂ N

An $N = 2^M$-pt DFT reduces to $M = \log_2 N$ stages. Each stage has $N/2$ butterflies, each with at most 1 complex multiply (4 real mults) and 2 complex adds (4 real adds):

Radix-2 FFT complexity $$\text{complex mults} \;\le\; \frac N2\,\log_2 N, \qquad \text{complex adds} \;=\; N\log_2 N$$ $$\text{real mults} < 4N\,M, \qquad \text{real adds} < 2\cdot 2N\,M \qquad\Longrightarrow\qquad \boxed{\;\text{complexity} \sim O(N\cdot M) = O(N\log_2 N)\;}$$

The quadratic term is gone. Figure 15-6 shows just how dramatic the difference is — at $N = 2^{16}$ the FFT needs about 3 orders of magnitude fewer multiplies.

2026-06-12T22:37:39.790922 image/svg+xml Matplotlib v3.10.8, https://matplotlib.org/ 1 0 1 1 0 2 1 0 3 1 0 4 1 0 5 Transform length N 1 0 1 1 0 3 1 0 5 1 0 7 1 0 9 Complex multiplications N = 1024: speed-up ×205 N = 65536: speed-up ×8 192 Direct DFT vs radix-2 FFT: complex-multiply count D i r e c t   D F T :   N 2 R a d i x - 2   F F T :   ( / 2 ) l o g N N 2
Fig. 15-6 — Complex-multiply counts: direct DFT ($N^2$) vs radix-2 FFT ($\tfrac N2 \log_2 N$), log–log scale. At $N=1024$ the FFT is ~205× cheaper; at $N = 65536$ it is ~8192× cheaper.(兩條線在對數座標上的差距隨 $N$ 不斷拉大 — 這就是「快速」的由來。)
Exam trap — counting FFT multiplies

The count $\frac N2 \log_2 N$ is complex multiplies, and it is an upper bound (many twiddles are $\pm 1, \pm j$ and are free). If a problem asks for real multiplies, multiply by 4. And remember the direct DFT baseline is $N^2$ complex = $4N^2$ real multiplies — don't mix the two units when computing a speed-up ratio.

15.4 FFT Variations

15.4.1 FFT for other values of N

Having $N = 2^M$ meant we could divide each stage into 2 halves — the radix-2 FFT(基數 2 FFT). The same divide-and-conquer approach works more generally:

Practical note

Modern libraries (FFTW — used by MATLAB — numpy.fft, etc.) implement mixed-radix and even prime-length algorithms (Rader, Bluestein), so any $N$ runs in $O(N\log N)$. But the constant factor is smallest for $N = 2^M$; a prime $N$ can easily be several times slower (see Fig. 15-7). When you control the length, choose a power of two.

15.4.2 Inverse FFT via the forward FFT

Recall the IDFT:

IDFT $$x[n] = \frac1N \sum_{k=0}^{N-1} X[k]\, W_N^{-nk}$$

The only differences from the forward DFT are the $1/N$ scale and the sign of the exponent. Conjugating twice fixes the sign:

IFFT via forward FFT $$N\,x^{*}[n] = \sum_{k=0}^{N-1}\big(X[k]\,W_N^{-nk}\big)^{*} = \sum_{k=0}^{N-1} X^{*}[k]\, W_N^{nk} \qquad\Longrightarrow\qquad \boxed{\;x[n] = \frac1N\Bigg[\sum_{k=0}^{N-1} X^{*}[k]\, W_N^{nk}\Bigg]^{*}\;}$$

The bracketed sum is exactly a forward DFT of $x'[n] = X^*[k]\big|_{k=n}$ — a "time" sequence made from the spectrum. So the recipe is: conjugate the spectrum, run the same FFT engine, conjugate the result, divide by $N$. One FFT implementation serves both directions; in a pure real flowgraph this amounts to swapping the roles of real/imaginary parts with a couple of sign flips and $1/N$ scalings at the ports.

15.4.3 DFT of real sequences — two for the price of one

If $x[n]$ is pure-real, the DFT wastes multiplies: by conjugate symmetry(共軛對稱), $X[k] = X^*[-k] = X^*[N-k]$, so half the outputs are redundant. The lecture's trick: pack two real sequences into one complex FFT. Given real $x[n]$ and $w[n]$, form $y[n] = x[n] + j\,w[n]$ and take a single $N$-pt DFT $V[k] = \mathrm{DFT}\{y[n]\} = X[k] + Y[k]$, where $Y[k] = \mathrm{DFT}\{j\,w[n]\} = jW[k]$. Then

Recovering both spectra $$V[k] + V^{*}[-k] = X[k] + \underbrace{X^{*}[-k]}_{=X[k]} + jW[k] + \underbrace{(jW[-k])^{*}}_{=-jW^{*}[-k] = -jW[k]^{*\,*}} \;\Longrightarrow\; \boxed{\;X[k] = \tfrac12\big(V[k] + V^{*}[-k]\big), \qquad W[k] = -\tfrac{j}{2}\big(V[k] - V^{*}[-k]\big)\;}$$

(Here $V^*[-k] = V^*[\langle N-k\rangle_N]$, and the cancellations use the conjugate symmetry of the real-input spectra $X$ and $W$.) That is: compute the DFTs of two $N$-pt real sequences with a single $N$-pt complex DFT — Exercise 5 verifies this numerically to machine precision.

15.5 The FFT in MATLAB

MATLAB's fft/ifft call the FFTW library — mixed-radix $O(N\log N)$ for every length, fastest for $N = 2^M$:

N  = 4096;
x  = randn(1, N);
X  = fft(x);              % N-point FFT (FFTW under the hood)
xr = ifft(X);             % inverse; max(abs(xr - x)) ~ 1e-16
X2 = fft(x, 8192);        % zero-pads x to 8192 points first

% --- timing: power-of-two vs prime length ---
N1 = 2^16;  N2 = 65537;                 % 65536 vs the prime 65537
x1 = randn(1, N1);  x2 = randn(1, N2);
t1 = timeit(@() fft(x1));               % ~ a few ms
t2 = timeit(@() fft(x2));               % noticeably slower
fprintf('N = %6d : %8.3f ms\n', N1, 1e3*t1);
fprintf('N = %6d : %8.3f ms\n', N2, 1e3*t2);

Figure 15-7 shows measured run times on this machine (numpy's FFTPACK-style engine; MATLAB/FFTW behaves the same way qualitatively): both power-of-two and prime lengths scale like $N \log N$, but the prime-length constant is ~5× worse, and the direct $O(N^2)$ matrix product blows past both almost immediately.

2026-06-12T22:38:03.298176 image/svg+xml Matplotlib v3.10.8, https://matplotlib.org/ 1 0 3 1 0 4 1 0 5 Transform length N 1 0 5 1 0 4 1 0 3 1 0 2 Time per transform (s) Measured FFT run time vs N Direct DFT (matrix product) f f t ,   = 2 N M fft, N prime
Fig. 15-7 — Measured time per transform vs $N$ (log–log). Grey: direct DFT as a matrix–vector product ($O(N^2)$ — already ~13 ms at $N=4096$). Green: FFT at $N = 2^M$. Red: FFT at prime $N$ — same slope, larger constant. At $N \approx 65536$: FFT ≈ 2.3 ms vs prime-length ≈ 14 ms.(質數長度仍是 $O(N\log N)$,但常數大很多;能選長度時選 2 的冪。)
MATLAB practice
  • nextpow2(L) gives $M$ with $2^M \ge L$; use fft(x, 2^nextpow2(L)) to zero-pad to a fast length.
  • fftshift(X) reorders the output so $k=0$ sits in the middle for plotting.
  • For repeated transforms of the same size, fftw('planner','measure') lets FFTW search for the fastest plan.
  • For real inputs MATLAB already exploits conjugate symmetry internally; keep only bins 1:N/2+1 for analysis.

15.6 Summary

Direct DFT cost

$N$ complex mults + $N{-}1$ adds per bin, $\times N$ bins → $N^2$ complex = $4N^2$ real mults, $4N^2{-}2N$ real adds. $O(N^2)$.

Twiddle factor $W_N$

$W_N = e^{-j2\pi/N}$; only $N$ distinct powers. Periodicity $W_N^{k+N} = W_N^k$, symmetry $W_N^{k+N/2} = -W_N^k$, halving $W_N^2 = W_{N/2}$.

Goertzel

$X[k] = y_k[N]$ from a 1st-order recursion; real-denominator form needs only 2 real mults/step. $O(N)$ per bin — best when you need few bins.

DIT split

$X[k] = X_0[\langle k\rangle_{N/2}] + W_N^k X_1[\langle k\rangle_{N/2}]$ — even-sample DFT plus twiddled odd-sample DFT. One split halves the work; recurse to 2-pt DFTs.

Butterfly

$X[r] = X_0[r] + W_N^r X_1[r]$, $X[r{+}N/2] = X_0[r] - W_N^r X_1[r]$: one complex mult, two adds (SUB instead of a second mult).

Bit reversal & in-place

Inputs in bit-reversed order, outputs natural; each butterfly overwrites its own two slots → whole FFT runs in one length-$N$ array.

FFT complexity

$M = \log_2 N$ stages × $N/2$ butterflies → $\le \frac N2 \log_2 N$ complex mults, $N \log_2 N$ adds: $O(N\log_2 N)$.

Variations

Radix-3/4, mixed radix for composite $N$, zero-pad to $2^M$; IFFT = conjugate → FFT → conjugate → $/N$; two real $N$-pt DFTs from one complex FFT.

Exercises

Exercise 1 — Operation counts and speed-up

Problem: A real-time system must compute a 4096-point DFT. (a) How many real multiplications does direct evaluation require? (b) How many complex multiplications does a radix-2 DIT FFT require (upper bound)? (c) What is the speed-up factor in complex multiplies? (d) If one complex multiply takes 5 ns, compare the two run times.

Click to reveal solution

(a) Direct: $4N^2 = 4\cdot 4096^2 = 67{,}108{,}864$ real multiplications (and $4N^2 - 2N = 67{,}100{,}672$ real adds).

(b) $N = 4096 = 2^{12}$, so $M = 12$ stages with $N/2 = 2048$ butterflies each:

$$\frac N2 \log_2 N = 2048 \times 12 = 24{,}576 \text{ complex multiplies (upper bound).}$$

(c) In complex multiplies: $\dfrac{N^2}{(N/2)\log_2 N} = \dfrac{16{,}777{,}216}{24{,}576} = \dfrac{2N}{\log_2 N} \approx 683\times$.

(d) Direct: $16{,}777{,}216 \times 5\,\text{ns} \approx 83.9\,\text{ms}$. FFT: $24{,}576 \times 5\,\text{ns} \approx 0.123\,\text{ms}$. At a 44.1 kHz audio rate a 4096-pt frame lasts ~93 ms — the direct DFT barely keeps up using all its time budget, while the FFT uses ~0.1%.

Exercise 2 — Deriving the DIT decomposition

Problem: Starting from the $N$-point DFT definition ($N$ even), (a) show that $X[k] = X_0[\langle k\rangle_{N/2}] + W_N^{k} X_1[\langle k\rangle_{N/2}]$ where $X_0, X_1$ are the $N/2$-point DFTs of the even- and odd-indexed samples. (b) Explain why $X_0$ and $X_1$ must be evaluated modulo $N/2$, and (c) show explicitly that $X[k + N/2] = X_0[k] - W_N^{k}X_1[k]$ for $0 \le k < N/2$.

Click to reveal solution

(a) Split the sum over even $n = 2m$ and odd $n = 2m+1$:

$$X[k] = \sum_{m=0}^{\frac N2 -1} x[2m] W_N^{2mk} + \sum_{m=0}^{\frac N2 -1} x[2m+1] W_N^{(2m+1)k} = \sum_m x[2m] \big(W_N^2\big)^{mk} + W_N^k \sum_m x[2m+1]\big(W_N^2\big)^{mk}$$

Since $W_N^2 = e^{-j2\pi\cdot 2/N} = e^{-j2\pi/(N/2)} = W_{N/2}$, the two sums are exactly $N/2$-point DFTs of $x_0[m] = x[2m]$ and $x_1[m] = x[2m+1]$.

(b) $X[k]$ is needed for $k = 0,\dots,N-1$, but an $N/2$-point DFT only defines $N/2$ values. By periodicity of the DFT, $X_0[k + N/2] = X_0[k]$ (the kernel $W_{N/2}^{m(k+N/2)} = W_{N/2}^{mk}$), so for $k \ge N/2$ we read the small DFTs at $\langle k\rangle_{N/2}$.

(c) For $0 \le k < N/2$:

$$X[k+\tfrac N2] = X_0\big[\langle k+\tfrac N2\rangle_{N/2}\big] + W_N^{k+\frac N2} X_1\big[\langle k+\tfrac N2\rangle_{N/2}\big] = X_0[k] + W_N^{k+\frac N2} X_1[k]$$

and the half-period symmetry $W_N^{k + N/2} = W_N^k\,e^{-j\pi} = -W_N^k$ gives

$$\boxed{X[k+\tfrac N2] = X_0[k] - W_N^{k} X_1[k]}$$

This is precisely the lower branch of the simplified butterfly — the same product $W_N^k X_1[k]$ is reused with a sign flip, which is why each butterfly needs only one complex multiply.

Exercise 3 — 4-point DIT FFT by hand

Problem: Compute the 4-point DFT of $x[n] = \{1, 2, 3, 4\}$ by tracing the radix-2 DIT flowgraph: write the bit-reversed input order, evaluate both stages of butterflies, and verify one output bin against the DFT definition.

Click to reveal solution

Step 1 — bit-reversed input. $N=4$, 2 bits: rows receive $x[00_2], x[10_2], x[01_2], x[11_2] = x[0], x[2], x[1], x[3] = 1, 3, 2, 4$.

Step 2 — stage 1 (2-pt DFTs, no twiddles).

$$\begin{aligned} a_0 &= x[0] + x[2] = 1 + 3 = 4, & a_1 &= x[0] - x[2] = 1 - 3 = -2\\ a_2 &= x[1] + x[3] = 2 + 4 = 6, & a_3 &= x[1] - x[3] = 2 - 4 = -2 \end{aligned}$$

Step 3 — stage 2 (twiddles $W_4^0 = 1$, $W_4^1 = e^{-j\pi/2} = -j$).

$$\begin{aligned} X[0] &= a_0 + W_4^0\, a_2 = 4 + 6 = 10\\ X[1] &= a_1 + W_4^1\, a_3 = -2 + (-j)(-2) = -2 + 2j\\ X[2] &= a_0 - W_4^0\, a_2 = 4 - 6 = -2\\ X[3] &= a_1 - W_4^1\, a_3 = -2 - 2j \end{aligned}$$

Step 4 — check $X[1]$ directly.

$$X[1] = \sum_{n=0}^{3} x[n]e^{-j\pi n/2} = 1 + 2(-j) + 3(-1) + 4(j) = -2 + 2j \checkmark$$

Note the count: 1 complex multiply total (the $-j\cdot a_3$, itself trivial) vs $N^2 = 16$ for the direct DFT. Also note $X[3] = X^*[1]$ — conjugate symmetry, since $x[n]$ is real.

Exercise 4 — Bit reversal for N = 16

Problem: For a 16-point radix-2 DIT FFT: (a) list the required input ordering; (b) which indices remain in place, and why? (c) How many stages does the FFT have, what butterflies does stage 3 contain (row spans and twiddles), and how many complex multiplies does the whole transform need (upper bound)?

Click to reveal solution

(a) Reverse 4-bit addresses ($0000 \to 0000$, $0001 \to 1000$, …). Input order:

$$x[0], x[8], x[4], x[12], x[2], x[10], x[6], x[14], x[1], x[9], x[5], x[13], x[3], x[11], x[7], x[15]$$

(b) An index stays in place iff its 4-bit pattern is a palindrome: $0000 = 0$, $0110 = 6$, $1001 = 9$, $1111 = 15$. (The remaining 12 indices form 6 swap pairs — bit reversal is its own inverse, so the shuffle is done with simple pairwise swaps, in place.)

(c) $M = \log_2 16 = 4$ stages. In stage 3 the butterflies span $2^{3-1} = 4$ rows: groups $(0\text{–}3$ with $4\text{–}7)$ and $(8\text{–}11$ with $12\text{–}15)$, twiddles $W_{8}^{0..3} = W_{16}^{0}, W_{16}^{2}, W_{16}^{4}, W_{16}^{6}$ applied to the lower input of each butterfly. Total complex multiplies $\le \frac{N}{2}\log_2 N = 8 \times 4 = 32$ (vs $N^2 = 256$ direct; even fewer in practice since $W^0, W^{N/4}$ are trivial).

Exercise 5 — MATLAB: two real DFTs from one complex FFT

Problem: Write MATLAB code that computes the DFTs of the two real sequences $x[n] = \cos(2\pi\,5n/N) + 0.5\cos(2\pi\,12n/N)$ and $w[n] = \sin(2\pi\,9n/N) + 0.3\,\text{randn}$, $N = 64$, using a single 64-point complex FFT. Recover $X[k]$ and $W[k]$, verify both against direct fft calls, and plot the recovered magnitude spectra.

Click to reveal solution

Pack $y[n] = x[n] + j\,w[n]$, transform once, then split with the conjugate-symmetry formulas of §15.4.3. The only subtlety is indexing $V^*[-k]$: with MATLAB's 1-based arrays, $V^*[\langle N-k\rangle_N]$ for $k = 0,\dots,N{-}1$ is conj(V(mod(N-(0:N-1),N)+1)).

N = 64;  n = 0:N-1;
x = cos(2*pi*5*n/N) + 0.5*cos(2*pi*12*n/N);   % real sequence 1
w = sin(2*pi*9*n/N) + 0.3*randn(1,N);         % real sequence 2

y  = x + 1j*w;                                % pack into ONE complex sequence
V  = fft(y);                                  % single N-pt complex FFT
Vc = conj(V(mod(N-(0:N-1), N) + 1));          % V*[_N]  (= V*[-k])

X = (V + Vc)/2;                               % spectrum of x
W = (V - Vc)/(2j);                            % spectrum of w  (-j/2 form)

errX = max(abs(X - fft(x)))                   % ~ 3.6e-15
errW = max(abs(W - fft(w)))                   % ~ 5.3e-15

subplot(2,1,1); stem(n, abs(X)); ylabel('|X[k]|');
title('Recovered from one complex FFT');
subplot(2,1,2); stem(n, abs(W)); ylabel('|W[k]|'); xlabel('k');

Regenerated result (numpy, same algorithm) — both spectra are recovered to machine precision ($\sim 10^{-15}$):

2026-06-12T22:38:04.777192 image/svg+xml Matplotlib v3.10.8, https://matplotlib.org/ 0 10 20 30 40 50 60 0 10 20 30 |X[k]| |X[k]| recovered from one complex FFT (max error 3.56e-15) 0 10 20 30 40 50 60 k 0 10 20 30 |W[k]| |W[k]| recovered from the same FFT (max error 5.33e-15)
Fig. 15-8 — $|X[k]|$ shows the two cosine lines at $k = 5, 12$ (and mirrors at $59, 52$); $|W[k]|$ shows the sine line at $k = 9$ ($55$) over the noise floor. Max recovery error $\approx 4\times 10^{-15}$.

Why it works: $x$ real $\Rightarrow X[k] = X^*[-k]$; $jw$ contributes the anti-symmetric part. Adding/subtracting $V^*[-k]$ separates the symmetric ($X$) and antisymmetric ($jW$) parts — two real $N$-pt DFTs for the price of one complex FFT, a ~2× saving.

Exercise 6 — Goertzel vs FFT

Problem: (a) Derive the second-order (real-coefficient) Goertzel transfer function from $H(z) = 1/(1 - W_N^{-k}z^{-1})$. (b) Count the real multiplies needed to compute one bin $X[k]$ of an $N$-point DFT with it. (c) A DTMF receiver needs $M = 8$ bins of an $N = 256$-point DFT. Which is cheaper, Goertzel or a radix-2 FFT? Find the break-even number of bins.

Click to reveal solution

(a) Multiply numerator and denominator by $(1 - W_N^{k}z^{-1})$:

$$H(z) = \frac{1}{1 - W_N^{-k}z^{-1}}\cdot\frac{1 - W_N^{k}z^{-1}}{1 - W_N^{k}z^{-1}} = \frac{1 - W_N^{k}z^{-1}}{1 - \big(W_N^{k} + W_N^{-k}\big)z^{-1} + z^{-2}} = \frac{1 - W_N^{k}z^{-1}}{1 - 2\cos\!\big(\tfrac{2\pi k}{N}\big)z^{-1} + z^{-2}}$$

using $W_N^k + W_N^{-k} = 2\cos(2\pi k/N)$. The denominator is now real.

(b) Run the all-pole recursion $s[n] = x[n] + 2\cos(2\pi k/N)\,s[n-1] - s[n-2]$ for $n = 0..N$: one real coefficient × (real input + real states) = 2 real mults per step for complex… for real input $x[n]$ the states stay real, so 1 real mult/step, $\approx N$ real mults total. The complex numerator $y[n] = s[n] - W_N^k s[n-1]$ is evaluated only at the last step $n = N$: + 4 real mults. Total $\approx N + 4$ real mults per bin (vs $4N$ for direct evaluation of one bin).

(c) Goertzel for $M$ bins: $\approx M(N+4) = 8 \times 260 = 2080$ real mults. Radix-2 FFT: $4\cdot\frac N2\log_2 N = 2\cdot 256\cdot 8 = 4096$ real mults (upper bound) — and it computes all 256 bins. Goertzel wins here. Break-even: $M(N+4) \approx 2N\log_2 N \Rightarrow M \approx 2\log_2 N = 16$ bins. Rule of thumb from §15.1.3: Goertzel is preferable when the number of needed bins $M \lesssim 2\log_2 N$; it also needs no input buffer (streaming) and no twiddle table.