Lab 19: The Butterfly
Time: ~40 minutes | Prerequisites: Lab 18 | Hardware: Pico 2 (no microphone needed)
Four multiplies. That's the whole engine.
Everything in an FFT — all 2,304 operations in a 512-point transform — is this one tiny
thing repeated. Learn it here and you've learned the FFT's entire arithmetic. It even
looks nice on paper.
What You'll Build
The butterfly: a two-in, two-out operation that shares one complex multiplication between both outputs. Then you'll see how butterflies arrange into stages.
Learning Objectives
- Perform a complex multiplication with four real multiplies
- Execute a butterfly by hand and in code
- Explain why both outputs reuse the same product
- Describe how the pairing distance doubles each stage
- Count the butterflies in an N-point FFT
Concepts Introduced
| ID | Concept |
|---|---|
| 384 | Butterfly Structure |
| 385 | Complex Multiplication |
| 386 | Four Multiply Form |
| 387 | Butterfly Pair |
| 388 | Stage Span |
| 389 | Data Flow Graph |
| 390 | Butterfly Count |
| 391 | Stage Loop |
| 392 | Cross Add And Subtract |
Background
The shape
Two complex inputs, two complex outputs, crossing over in the middle. Hence "butterfly."
Run The Butterfly Shares Computation MicroSim Fullscreen
Drag a, b, and the W angle sliders to set up any butterfly. Then toggle
Share b × W between both outputs off and on — the outputs never change,
but the instruction-count cards below the diagram do. That's the whole point:
sharing one product between two outputs is free in terms of the answer and
expensive to skip in terms of work.
The arithmetic
Step 1 — multiply b by the twiddle. Complex multiplication needs four real multiplies:
1 2 | |
Step 2 — cross add and subtract. No more multiplying:
1 2 | |
Total: 4 real multiplies, 6 real adds, two complex outputs.
The saving is the sharing
Notice that W·b is computed once and used for both outputs. The direct DFT computes
those two bins separately, redoing that multiply. Multiply that waste across every bin
and every stage and you have the entire 500× gap from Lab 16.
Stages
1 2 3 | |
Stage 1 pairs neighbours. Each stage the reach doubles until the last stage spans half the array. For N = 512 that's nine stages — the log₂(N) from Lab 17, made concrete.
Every stage does exactly N/2 butterflies, so the total is (N/2)·log₂(N).
Procedure
Step 1 — Work one butterfly by hand
Open 19-butterfly.py and run it:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | |
Part 1 shows every intermediate value for a single butterfly with a = 3+1i, b = 2−1i, and a
45° twiddle. Follow the arithmetic with a calculator once — it makes the rest concrete.
Step 2 — See it as code
1 2 3 4 5 6 7 8 | |
Eight lines. This is the FFT's entire arithmetic. Everything else is loops deciding which indices and which twiddle.
Save a before you overwrite it
Notice ar, ai = re[i1], im[i1] happens before any assignment. Write re[i1] first
and the old value is gone when you need it for re[i2]. It's a two-character bug that
produces a spectrum which looks plausible and is wrong.
Step 3 — Watch the stages spread
Part 3 prints the pairing for every stage of an 8-point FFT. Trace one element — say index 1 — through all three stages and see who it partners with each time.
Step 4 — Count the work
1 2 | |
2,304 butterflies for a 512-point FFT. At 4 multiplies each that's about 9,216 multiplications, where the DFT needed over half a million.
Step 5 — Predict, then measure
Prediction: how many butterflies in a 1,024-point FFT? How many stages?
Work it out before checking the table.
Expected Output
1 2 3 4 5 6 7 8 | |
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Outputs wrong but plausible | Overwrote a before using it |
Save ar, ai first |
| Complex multiply wrong | Sign error | tr = wr·br − wi·bi; the minus is on the real part |
| Pairs overlap between blocks | Block stride wrong | Blocks advance by half*2 |
| Only half the array changes | Inner loop bound wrong | It runs half times, not n |
Challenges
- Three multiplies. There's a known trick computing a complex product with 3 multiplies and 5 adds instead of 4 and 2. Look it up, implement it, and decide whether it's worth it here.
- Draw the graph. Sketch the full 8-point data-flow diagram, all three stages. You'll see why it's called a butterfly network.
- Trace an element. Follow index 3 through all three stages of an 8-point FFT. Which partners does it meet, and which twiddle applies each time?
Check Your Understanding
- How many real multiplies does one butterfly need, and for how many outputs?
- Why must you save
abefore writing the outputs? - In stage 3 of a 16-point FFT, how far apart are the paired elements?
- How many butterflies are in a 256-point FFT?
- In one sentence, where does the FFT's saving actually come from?
You have every piece now
Split, reorder, look up twiddles, butterfly. Next lab you assemble all four into a
working FFT — and find out just how much faster it really is.
Next: Lab 20: A Complete Python FFT | Previous: Lab 18