Skip to content

More FFT algorithms

Split a DFT by any factor of N, rescue prime lengths with Bluestein's chirp, pack two real signals into one FFT, and compare what libraries choose.

Before this3.3 · 5.2
Chapter 14 · Lesson 2 of 4

First, the picture

An FFT splits a DFT into small ones, one stage per factor of NN. Guess first: how much does it save at N=31N=31, a prime?

The factors of N set the stages

Schematic: each box is one small DFT over the rows it joins. Rows are reordered between stages (not drawn).

N
12 = 2 × 2 × 3
work
84 (direct 144)
0.00 / 14.00 s
Describe this picture

A schematic: each row is a small dot, one for each of the NN samples, and each box is one small DFT over the rows it joins; rows are reordered between stages, which is not drawn. Each column of boxes is one stage, headed by its radix. A box tall enough carries its radix NiN_i as a label. Radix 2 boxes are plain rectangles, radix 3 boxes are rounded, and radix 5 and up have a double outline, so the shape tells the radix as well as the colour. The readouts are NN with its factors and the work, with the direct count beside it.

The clip shows four lengths in turn. For each one the rows fade in, then the columns arrive one at a time, and the caption is blank until the last column is in. N=12=2×2×3N=12=2\times2\times3 reads work 84 (direct 144); N=32N=32 reads 320 against 1024; N=30=2×3×5N=30=2\times3\times5, built by about 7.6 s, reads 300 against 900, with a plain, a rounded and a double-outlined column; and the prime N=31N=31 is one box spanning every row, labelled 31, reading 961 (direct 961). Once the clip has finished, dragging up or down on the plot, or the arrow keys (steps of 1), Page Up and Page Down (steps of 8), Home or End, chooses NN from 2 to 32 through a control named “DFT length N”, whose value reads like “30 = 2 × 3 × 5”. The caption then names the factors and the work, as in “N = 30 = 2 × 3 × 5: three stages, work 300 against 900.”, or for a prime, “N = 29 is prime: one 29-point DFT, 841 multiplies.”

The factors of N set the stages

The FFT (14.1) split a DFT by 2: even-indexed samples in one half, odd-indexed in the other. That trick is not special to 2. If N=N1N2N=N_1N_2, write n=N2n1+n2n=N_2n_1+n_2. The DFT becomes N2N_2 DFTs of length N1N_1, a twiddle on each output, then N1N_1 DFTs of length N2N_2. With N2=2N_2=2 this is 14.1’s split again, because n2=0n_2=0 picks the even samples and n2=1n_2=1 the odd ones.

Repeat the split on the small DFTs and the result is a chain of stages, one for each factor in N=N1N2⋯N=N_1N_2\cdots. The size NiN_i of a stage is its radix, and a length whose factors differ is called mixed radix. A stage of radix NiN_i is N/NiN/N_i small DFTs of Ni2N_i^2 multiplies each, so it costs N⋅NiN\cdot N_i, and the whole FFT costs

N (N1+N2+⋯ )N\,(N_1+N_2+\cdots)

multiplies. This is Cooley and Tukey’s count. It also counts the multiplies by ±1\pm1 that 14.1 skipped, so at N=32N=32 it says 320 where 14.1’s N2log⁡2N\tfrac N2\log_2N said 80.

The picture at the top of the page draws these stages. For N=12=2×2×3N=12=2\times2\times3 there are three, and the work is 12×(2+2+3)=8412\times(2+2+3)=84, against 144 directly. For N=32=2×2×2×2×2N=32=2\times2\times2\times2\times2 there are five stages of radix 2, and the work is 320 against 1024. N=30=2×3×5N=30=2\times3\times5 is mixed radix, three stages, and 300 against 900: NN need not be a power of two.

And the guess: N=31N=31 is prime, so there is no factor to split by. It stays one 31-point DFT, 961 multiplies, the same as direct. The figure further down rescues it.

When the clip ends, drag up or down on the plot, or use the arrow keys, to choose NN from 2 to 32; the caption names the factors and the work.

Try N=16N=16, which gives four stages of radix 2: work 128 against 256. Then try N=17N=17, one more sample and a prime: 289 against 289, no saving at all. A length with one large factor, like N=62=2×31N=62=2\times31, saves little: 2046 against 3844. The saving comes from small factors.

A prime length, by three FFTs

A prime length has no factors to split by, but it can be rewritten as a convolution, and a convolution can be done with a longer FFT. The rewriting starts from an identity for the product in the exponent of WNknW_N^{kn}:

kn=12[k2+n2−(k−n)2].kn=\tfrac12\left[k^2+n^2-(k-n)^2\right].

Check it with k=3k=3 and n=5n=5: 12(9+25−4)=15\tfrac12(9+25-4)=15, which is 3⋅53\cdot5. Put it in the exponent of WNknW_N^{kn}:

WNkn=e−jπk2/N e−jπn2/N e+jπ(k−n)2/N.W_N^{kn}=e^{-j\pi k^2/N}\,e^{-j\pi n^2/N}\,e^{+j\pi(k-n)^2/N}.

The DFT now has three steps. Multiply x[n]x[n] by the chirp e−jπn2/Ne^{-j\pi n^2/N}, a tone whose frequency rises steadily. Convolve the result with the opposite chirp, e+jπn2/Ne^{+j\pi n^2/N}. Multiply each output by the chirp again. The convolution in the middle is the one from Circular vs linear convolution (13.4): do it with FFTs, zero-padded to any power of two that is at least 2N−12N-1 so that it stays linear.

For N=1009N=1009, a prime, the first power of two at least 2⋅1009−1=20172\cdot1009-1=2017 is 2048.

N = 1009 (prime)× chirpconvolve with chirp,by FFT (size 2048)× chirp
Fig. Bluestein’s trick: a 1009-point DFT as a convolution, done with three 2048-point FFTs. About 38 thousand multiplies instead of a million.

The count follows from 14.1. One 2048-point FFT is 20482⋅11=11 264\tfrac{2048}{2}\cdot11=11\,264 complex multiplies, and the convolution needs three of them: 33 792. Add 2048 products of the two spectra and 2018 chirp multiplies, 1009 before and 1009 after, and the total is 37 858. Computing the DFT directly takes 10092=1 018 0811009^2=1\,018\,081, about 27 times as many.

Two other ideas get one sentence each. Rader’s method also rewrites a prime-length DFT as a convolution, using a different re-indexing. Prime-factor (Good and Thomas) indexing splits N=N1N2N=N_1N_2 with no twiddles at all, when N1N_1 and N2N_2 share no divisor.

Two real FFTs for the price of one

Most signals are real, and the FFT is built for complex input. That wastes half of every transform: the imaginary part of the input is zero. So put one real signal in the real part and another in the imaginary part:

g[n]=x[n]+j y[n],g[n]=x[n]+j\,y[n],

and take one FFT, G[k]G[k]. Because xx is real, its DFT has X[N−k]=X[k]∗X[N-k]=X[k]^* (The DFT, 13.2), and so does yy‘s. The ∗* is the conjugate, the mirror image of Complex numbers for signals (3.3). Take the conjugate of GG at the mirrored bin:

G[N−k]∗=X[N−k]∗−j Y[N−k]∗=X[k]−j Y[k].G[N-k]^*=X[N-k]^*-j\,Y[N-k]^*=X[k]-j\,Y[k].

Adding this to G[k]=X[k]+jY[k]G[k]=X[k]+jY[k] leaves 2X[k]2X[k], and subtracting it leaves 2jY[k]2jY[k]. So

X[k]=12(G[k]+G[N−k]∗),Y[k]=12j(G[k]−G[N−k]∗),\begin{aligned} X[k]&=\tfrac12\left(G[k]+G[N-k]^*\right),\\ Y[k]&=\tfrac1{2j}\left(G[k]-G[N-k]^*\right), \end{aligned}

with G[N]G[N] meaning G[0]G[0]. One complex FFT carries two real DFTs, and the mirrored conjugate pulls them apart.

Before you watch, think of two voices on one phone line, one in each ear of a stereo pair. Which part of GG would tell you which voice is which?

Two real FFTs for the price of one

x[n] = 1 + cos(πn/4) and y[n] = sin(πn/2), N = 8, packed as g = x + jy.

FFTs taken
1 (complex, 8-point)
check
not yet
0.00 / 13.00 s
Describe this picture

Two stacked plots with no control, for x[n]=1+cos⁡(πn/4)x[n]=1+\cos(\pi n/4) and y[n]=sin⁡(πn/2)y[n]=\sin(\pi n/2), N=8N=8, packed as g=x+jyg=x+jy. Both plots run over the bin kk from 0 to 7 and values from −5 to 9. In the upper one, stems with dots show G[k]G[k], and stems with open squares, drawn a little to the side so they do not hide the dots, show the mirrored G[N−k]∗G[N-k]^*. In the lower one, stems with dots show X[k]X[k] and stems with diamonds show Y[k]÷jY[k]\div j; YY is imaginary, so dividing by jj makes it drawable. The readouts are the FFTs taken, “1 (complex, 8-point)”, and a check, which reads “not yet” until the end.

First the G[k]G[k] stems rise, 8, 4, 4, 0, 0, 0, −4, 4. Then each mirrored conjugate stem flies from bin N−kN-k to bin kk, 8, 4, −4, 0, 0, 0, 4, 4. Half-sums drop into the lower plot as X[k]X[k], and half-differences divided by 2j2j follow as Y[k]÷jY[k]\div j. At the end the check reads “X and Y match two separate FFTs”.

One complex FFT of g=x+jyg=x+jy gives G=8,4,4,0,0,0,−4,4G=8,4,4,0,0,0,-4,4.

Mirrored and conjugated, G[N−k]∗=8,4,−4,0,0,0,4,4G[N-k]^*=8,4,-4,0,0,0,4,4. At k=2k=2 and 6 the two disagree in sign. Read bin 2 yourself: G[2]=4G[2]=4 and G[6]∗=−4G[6]^*=-4. Half their sum is 0, and half their difference divided by 2j2j is 4/j=−4j4/j=-4j.

Half the sum is XX: 8 at k=0k=0 (the 1), and 4 at k=1k=1 and 7 (the cosine), while bins 2 and 6 cancel. Half the difference, divided by 2j2j, is YY: −4j-4j at k=2k=2 and +4j+4j at k=6k=6 (the sine). Two real DFTs come from one FFT, and they match two separate ones.

Notice the bars at k=2k=2 and k=6k=6. They cancel in XX and double in YY, because the mirrored conjugate of GG keeps the sign of the real signal’s bins and flips the sign of the imaginary signal’s.

The same graph, run backwards

Decimation in time, from 14.1, splits the inputs into even and odd samples. Decimation in frequency splits the outputs. First form two sequences of length N/2N/2 from the two halves of xx:

a[n]=x[n]+x[n+N/2],b[n]=(x[n]−x[n+N/2]) WNn.\begin{aligned} a[n]&=x[n]+x[n+N/2],\\ b[n]&=\bigl(x[n]-x[n+N/2]\bigr)\,W_N^{n}. \end{aligned}

The even-indexed outputs X[0],X[2],…X[0],X[2],\dots are the N/2N/2-point DFT of aa, and the odd-indexed ones are that of bb. The reason is one line each. For even outputs WN2m(n+N/2)=WN2mnW_N^{2m(n+N/2)}=W_N^{2mn}, so the two halves of the sum add. For odd outputs WN(2m+1)(n+N/2)=−WN(2m+1)nW_N^{(2m+1)(n+N/2)}=-W_N^{(2m+1)n}, so the second half is subtracted, and what is left of the exponent is WNnW_N^n times WN/2mnW_{N/2}^{mn}.

The graph is 14.1’s mirrored: inputs in order, the twiddle after the subtraction, outputs in bit-reversed order. In the figure, solid wires add and dashed wires are the ones subtracted.

11X[0]23X[4]02X[2]−10X[6]01X[1]11X[5]2−2X[3]1−2X[7]stage 1stage 2stage 3x[n]
Fig. Decimation in frequency on x = 1, 2, 0, −1, 0, 1, 2, 1: the first stage makes sums 1, 3, 2, 0 and differences, and the outputs land in rows 0, 4, 2, 6, 1, 5, 3, 7: the same X as clip 2 of 14.1.

The numbers beside the rows are the sums and the differences before their twiddles. The sums are 1, 3, 2, 0. The differences are 1, 1, −2, −2, and the twiddles W80,…,W83W_8^0,\dots,W_8^3 then turn them into 11, 0.707−0.707j0.707-0.707j, 2j2j and 1.414+1.414j1.414+1.414j.

Computing in place

Each butterfly reads two values and writes two values to the same two places. So the whole FFT needs no second array: it works in place. libsig’s fft.c does this. It reorders the input into bit-reversed order first and then overwrites it stage by stage.

What libraries choose

Which radix is best is a counting question. Radix-4 handles two stages of radix 2 at once, and its multiplies by ±j\pm j are free. Split-radix uses radix 2 for the even-indexed outputs and radix 4 for the odd-indexed ones. To compare them, count real operations. A multiply by ±1\pm1 or ±j\pm j is free. A multiply by e±jπ/4e^{\pm j\pi/4} or e±j3π/4e^{\pm j3\pi/4} costs two multiplies and two adds. Any other twiddle costs four multiplies and two adds. The table shows the exact counts for N=1024N=1024.

AlgorithmMultipliesAddsTotal
radix-213 32427 65240 976
radix-410 24825 94436 192
split-radix9 33625 48834 824

Radix-4 saves 11.7 % of the operations of radix-2 and split-radix saves 15.0 %. These are small gains in total, but nearly all of the saving comes from multiplies. Radix-4 needs a length that is a power of 4. Split-radix works for every power of 2.

FFTW, and NumPy’s pocketfft, go further. They factor any NN, use radix 2, 3, 4, 5 and larger blocks of hand-tuned code, and fall back on Rader’s method or Bluestein’s trick for large primes. FFTW also times several candidate plans on your machine and keeps the fastest. So NN need not be a power of two, but large primes are slow, and it is worth avoiding them. libsig’s FFT is radix-2 only, which is why the instruments on this site use powers of two.

Worked example

Every number below was recomputed in NumPy.

  1. Factor counts, N(N1+⋯ )N(N_1+\cdots) against N2N^2. For N=12N=12: 84 against 144. For N=30N=30: 300 against 900. For N=32N=32: 320 against 1024. For N=1000=23⋅53N=1000=2^3\cdot5^3: 21 000 against 1 000 000. For N=1024N=1024: 20 480 against 1 048 576. For the prime N=1009N=1009: 1 018 081 either way.
  2. Bluestein at N=1009N=1009. FFT size 2048. Three FFTs cost 33 792 complex multiplies, plus 2048 products and 2018 chirp multiplies: 37 858 against 1 018 081.
  3. Two for one. The packed spectrum is G=8,4,4,0,0,0,−4,4G=8,4,4,0,0,0,-4,4. Its mirrored conjugate is 8,4,−4,0,0,0,4,48,4,-4,0,0,0,4,4. The results are X=8,4,0,0,0,0,0,4X=8,4,0,0,0,0,0,4 and Y=0,0,−4j,0,0,0,4j,0Y=0,0,-4j,0,0,0,4j,0.
  4. DIF first stage on x=1,2,0,−1,0,1,2,1x=1,2,0,-1,0,1,2,1: sums 1,3,2,01,3,2,0, differences 1,1,−2,−21,1,-2,-2 before the twiddles.
  5. Exact counts at N=4096N=4096, total real operations: radix-2 204 816, radix-4 179 552, split-radix 172 040. At N=1024N=1024 the totals are 40 976, 36 192 and 34 824.

Where you’ll meet this

Fast convolution (14.3) uses power-of-two FFTs to run long filters, and Goertzel and the chirp z-transform (14.4) comes back to the chirp for zooming into a band. Chapter 15 starts with Windowing (15.1), and spectrum analysers there take real-input FFTs.

The maths behind it · Kronecker products

The index n=N2n1+n2n=N_2n_1+n_2 reads a length-NN vector as an N1×N2N_1\times N_2 grid. The mixed-radix FFT is then “DFT the columns, twiddle, DFT the rows”: a Kronecker-product factorisation of the DFT matrix.

The maths behind it · complex-valued measurements

Two independent real measurements stored as one complex number is how I/Q samples from a radio are recorded, which Chapter 27 uses.

Reference card

QuantityFormulaNotes
Mixed radixN=N1N2⋯N=N_1N_2\cdots; work N(N1+N2+⋯ )N(N_1+N_2+\cdots)one stage per factor
Prime NNBluestein: kn=12[k2+n2−(k−n)2]kn=\tfrac12[k^2+n^2-(k-n)^2]convolution by FFT, size at least 2N−12N-1
Two real for oneX[k]=12(G[k]+G[N−k]∗)X[k]=\tfrac12(G[k]+G[N-k]^*), Y[k]=12j(G[k]−G[N−k]∗)Y[k]=\tfrac1{2j}(G[k]-G[N-k]^*)g=x+jyg=x+jy
Decimation in frequencya[n]=x[n]+x[n+N/2]a[n]=x[n]+x[n+N/2], b[n]=(x[n]−x[n+N/2])WNnb[n]=(x[n]-x[n+N/2])W_N^noutputs bit-reversed
Split-radix4Nlog⁡2N−6N+84N\log_2N-6N+8 real operationsfewest of the three
In placebutterflies overwrite their inputsno second array

End of lesson 14.2

Where to go next.

Phasorium
LibraryEvery lesson, in order

Parts

About Phasorium
Look