FA20
Fourier Transforms & Complex Variables
Decomposing arbitrary signals into rotating-frequency components, with the complex-variable machinery (contour integration, residues) that makes the transforms work.
Concepts learned
Tech
- Python
- NumPy
- Matplotlib
- Web Audio API
Hero demo Epicycle Drawing Animation
Walk me through this step by step
-
You’ve seen this trick before, even if you didn’t know its name. A Spirograph is a small gear rolling inside a bigger one, with a pen sitting on the small gear that traces an intricate flower-shaped curve. Astronomers from Ptolemy onwards modelled the planets as circles rolling on circles — “epicycles” — to fit the wandering paths they saw in the night sky. The viral video of Homer Simpson’s outline drawn by a chain of rotating arms is the same recipe. This demo runs that recipe backwards: hand it any closed shape and it works out which arms you need.
-
The claim is bold: any closed planar curve — heart, square, signature, cartoon outline — can be traced by stacking rotating arms. One arm spins at one revolution per cycle. The next is mounted on the tip of the first and spins at two revolutions, the next at three, and so on (plus the same set spinning backwards). Pick the right length and starting angle for each arm and their combined tip draws your shape exactly. The slider labelled Num terms is how many arms you let the chain use.
-
Treat the canvas as the complex plane, so a point on the curve is z = x + iy. The recipe is the Fourier series of a closed curve:
z(t) = \sum_{k} c_k\, e^{i\, 2\pi k t}Each term c_k e^{i\, 2\pi k t} is exactly one rotating arm: its length is |c_k|, its starting angle is \arg c_k, and the integer k says how many turns it makes per loop. Adding the terms is tip-to-tail vector addition — the rotating chain you watch on the canvas.
-
Start with the simplest preset: load Circle and pull Num terms down to 1. The shape is already a pure rotation, so the analysis puts everything in c_1 and nothing anywhere else. One arm of length 1 spinning once per cycle traces the circle exactly. Push Num terms back up and the extra arms have amplitude zero, so they sit invisibly at the joint — no approximation, no leftover wiggle.
-
Now load Heart. The visualiser doesn’t see your curve as a formula — it samples 128 evenly-spaced points along it, one per parameter t \in \{0/128, 1/128, \ldots, 127/128\}. Those 128 complex samples go into a discrete Fourier transform, which returns 128 complex coefficients c_k. Each one is a length and a starting angle for an arm at integer frequency k. Crank the Sample points slider up and you get more frequencies to choose from.
-
Out of 128 coefficients, the heart’s energy lives in just a handful of low frequencies. The demo sorts them by |c_k| — biggest arm first — and the largest dozen already give a recognisable heart. With 1 arm the tip traces a circle. With 4 it’s a lumpy oval. By 12 it’s clearly a heart, and by 24 the wobble is gone. Each new arm is a smaller correction sitting on top of the previous fit.
-
Why does the transform recover the right arm lengths? Because the complex exponentials are orthogonal: averaging
e^{i\, 2\pi j t}\, \overline{e^{i\, 2\pi k t}}over one full cycle gives zero unless j = k, and 1 when they match. So multiplying your samples by e^{-i\, 2\pi k t} and averaging picks out only the c_k component — every other arm cancels itself out in the integral. That is the entire DFT, summarised in one orthogonality identity.
-
You’ll notice the chain uses both positive and negative frequencies. A positive-k arm spins anti-clockwise; a negative-k arm spins clockwise. You need both because a real-valued curve forces a symmetry on the coefficients, c_{-k} = \overline{c_k}, and the imaginary parts of the two paired arms cancel only when the clockwise twin is present. Drop the negative-frequency arms and the heart tilts off into a spiral.
-
Try it yourself.
-
This is the same idea as the Fourier series builder below, rotated into the complex plane: real sines and cosines become complex exponentials, and “sum of harmonics” becomes “chain of rotating arms.” The two demos are paired — one stacks harmonics vertically against a waveform, the other stacks them tip-to-tail around the origin. The convolution animation and the FT-of-signals demo then extend the same machinery from periodic loops to non-periodic signals, which is where the featured problems pick the story up.
Fourier epicycles tracing the heart path with 24 of 128 terms, advancing at 0.50 cycles per second.
Reflection
Pre-interview preview. Akwasi’s first-person reflection on this course is pending — track at issue #44.
Fourier series builder
Stack sine and cosine harmonics and watch the partial sums converge to square, sawtooth, or triangle waves.
Fourier partial sum approximating a square wave with 1 of 50 harmonics. Gibbs phenomenon: overshoot near the jump never vanishes as N grows.
Fourier transform of common signals
Side-by-side time-domain and frequency-domain plots for canonical signals.
Fourier transform of the rectangular pulse signal with T = 1.00, plotted over frequencies |ω| ≤ 20. Note the time-frequency duality: narrower pulses in time spread wider in frequency.
Convolution animation
Slide one signal past another and trace the running integral of their product.
Walk me through this step by step
-
Blur a photo, hear an echo in a cave, smooth out a noisy stock chart — under the hood it is the same operation every time. Slide one signal across another and accumulate the overlap as you go. That is convolution. It keeps reappearing because it is the natural way to ask “what does input X look like after I run it through system Y” — whether Y is a lens, a room full of reflective walls, or a moving average over a noisy week of trading. Get comfortable with the picture and suddenly half of signal processing, image processing, and probability theory looks like the same trick wearing different hats.
-
Start small, by hand. Take the sequence 1, 2, 3, 4, 5 and a three-tap moving average with weights one-third, one-third, one-third. To smooth the middle of the data, average each value with its two neighbours: (1+2+3)/3 = 2, (2+3+4)/3 = 3, (3+4+5)/3 = 4. Those three central numbers are the heart of the convolution. Full linear convolution also produces small ramped values at the edges where the kernel only partly overlaps the data, but the central 2, 3, 4 is exactly what you would write down on paper if I simply asked you to smooth the sequence.
-
Here is the recipe in full. For two discrete signals f and g, the convolution at output index n is
(f \ast g)[n] = \sum_{k} f[k]\, g[n-k]Read it as four moves: flip g (the index now runs as g[n-k] instead of g[k]), shift it by n, multiply pointwise against f, and sum. We will call this the flip-shift-multiply-sum recipe. The moving average above followed exactly this recipe — the kernel just happened to be symmetric, so the flip was invisible.
-
Why the flip? Without it the operation would not commute. With the flip baked into the definition, f \ast g = g \ast f drops out of a single change of variable in the sum. That symmetry matches the intuition we already had: the lens blurring an image is interchangeable with the image being read out by the lens. The flip is the small piece of algebra that makes “input convolved with system” equal to “system convolved with input” — and it is why nobody has to argue about which signal is the kernel.
-
Push the index from a discrete n to a continuous t and the sum becomes an integral:
(f \ast g)(t) = \int_{-\infty}^{\infty} f(\tau)\, g(t - \tau)\, d\tauSame recipe — flip g, slide it by t, multiply pointwise against f, integrate. The visualiser draws exactly this picture. The blue curve sits still, the orange curve slides left to right, the shaded overlap area is the integrand, and the running area traces the output curve underneath as t advances.
-
Try it yourself.
-
Three rules of thumb fall straight out of the picture. Widths add — convolve a width-w signal with a width-v signal and the result has width w + v (the triangle of base 4 from two boxes of width 2 is this rule made visible). Areas multiply — the total area under the convolution equals the area of f times the area of g. And the output at time t is a weighted average of f near t, with weights given by a flipped, shifted copy of g. That last sentence is the entire mental model.
-
Now the punchline. Take the Fourier transform of both sides of h = f \ast g and the awful sliding integral collapses into pointwise multiplication:
\hat{h}(\omega) = \hat{f}(\omega)\,\hat{g}(\omega)In plain English: if you describe both signals as sums of pure tones, the output tone amplitude at every frequency is just (input tone amplitude) × (filter response at that tone). The complicated time-domain integral becomes pointwise multiplication in frequency. This is the single most-used identity in all of signal processing.
-
Every linear filter is secretly a convolution. A low-pass filter has an impulse response — a small kernel — and applying the filter to your audio is exactly convolving the signal with that kernel. The frequency-domain view is the equaliser slider: multiply the spectrum by a curve that is near 1 at low frequencies and near 0 at high. Both views compute the same output sample for sample. The reverb on a vocal track is the singer’s voice convolved with the impulse response of the room — sometimes literally recorded with a starter pistol.
-
So that is convolution: slide, multiply, sum — and in the frequency domain, just multiply. The next demo, Audio filter, lets you hear the theorem in real time as you drag the cutoff frequency; the impulse response changes and the output changes with it. Pair the rect-rect triangle here with the sinc-squared spectrum in Fourier transform of common signals and the multiplication-in-frequency rule writes itself. The featured problem Gibbs phenomenon at a square-wave discontinuity is also secretly a convolution story — the partial-sum operator is convolution with the Dirichlet kernel, and the overshoot is what that kernel’s side-lobes leave behind.
Convolving the rect ⋆ rect (triangle) signal pair with 120 samples each, sliding the kernel at 10 shifts per second to build up the output one sample at a time.
Audio filter — Web Audio biquad
Drag the cutoff and Q to hear how a biquad filter sculpts a synth or microphone signal.
Lowpass filter passes frequencies below 1000 Hz, with quality factor Q = 0.71.
Complex domain coloring
Phase-as-hue and magnitude-as-brightness visualisation of analytic functions across the complex plane.
Conformal mapping
Watch how an analytic map deforms a grid while preserving angles between curves at every point.
Residue theorem helper
Compute residues at poles inside a contour and verify them against the contour integral.
Featured problems
What’s coming
The author’s written reflection lands alongside the v3 interview. The demos and featured problems above are wired and playable today.