MIT 6.300 — Lecture 14
Fast Fourier Transform
See Lectures 22 and 23 of 6.1220 for an alternative perspective on the content from this lecture.
Remark. Note that 6.1220 adopts slightly different conventions than 6.300.
In 6.300, the DFT is ; refer to Lecture 12.
In 6.1220, the DFT is ; simpler for abstract purposes, but not as meaningful in physical contexts.
§ Recitation: DFT = Polynomial Sampling
We first provide an alternative perspective on the DFT, as suggested by 6.1220.
Theorem. (DFT = Polynomial Sampling) Consider a DT signal of length along with the corresponding polynomial . Let be a primitive root of unity. Then:
Proof: Follows immediately from the DFT analysis and synthesis equations from Lecture 12.
The above reinterpretation makes it much easier to argue that the DFT of a circular convolution equals the product of the DFTs.
Theorem. (Convolution = Product) Given DT signals and of length with DFTs and , respectively, we have:
Proof: Say and correspond to polynomials and . The point is that the polynomial corresponding to is simply in : convolution is just polynomial multiplication. Thus,
The argument for the inverse DFT works the same way.
A corollary of this reinterpretation is the following.
Theorem. (DFT = Inverse DFT) If is the DFT of , then the DFT of is . Equivalently, writing for circular reversal,
Proof: From 6.1220, the Lectures 22 and 23 notes provide a linear-algebra-based argument from the fundamentals. But we don't need that: this follows immediately from the relationship between the DFT and inverse DFT in the polynomial setting.
Remark. All of the mathematical content of the above proof has, in some sense, been deferred to the mathematical content of the consistency of the synthesis and analysis equations from Lecture 12.
Thus, any result we discover about the DFT has a natural “dual” in the context of the inverse DFT.
§ Lecture: The FFT Algorithm
Via a divide-and-conquer approach, we may compute the DFT of a DT signal of length in time. This algorithm is known as the Fast Fourier Transform (FFT).
from cmath import exp, pi
def FFT(x):
"""Returns the DFT of x, an array whose length is a power of two."""
# Base Case
N = len(x)
if N == 1:
return x
# Divide and Conquer
even_x = x[::2]
odd_x = x[1::2]
FFT_even_x = FFT(even_x)
FFT_odd_x = FFT(odd_x)
# Combine Step
FFT_x = []
for k in range(N // 2):
FFT_x.append((FFT_even_x[k] + exp(-2j * pi * k/N) * FFT_odd_x[k]) / 2)
for k in range(N // 2):
FFT_x.append((FFT_even_x[k] - exp(-2j * pi * k/N) * FFT_odd_x[k]) / 2)
return FFT_x
Refer to Lectures 22 and 23 for details on how this algorithm works; keep in mind the difference in convention.
An implementation of the inverse DFT would look very similar, except with the exponents negated and the factor of removed. Here's how that looks in code.
# DFT Implementation:
FFT_x.append((FFT_even_x[k] + exp(-2j * pi * k/N) * FFT_odd_x[k]) / 2) # first for loop
FFT_x.append((FFT_even_x[k] - exp(-2j * pi * k/N) * FFT_odd_x[k]) / 2) # second for loop
# Inverse DFT Implementation:
FFT_x.append((FFT_even_x[k] + exp(2j * pi * k/N) * FFT_odd_x[k])) # first for loop
FFT_x.append((FFT_even_x[k] - exp(2j * pi * k/N) * FFT_odd_x[k])) # second for loop