Parseval’s theorem demo (DFT / FFT)
Build a length-N signal, optionally apply a window, and compute its energy two ways: directly in time as Σ|x[n]|², and from the FFT. The DFT has two common scalings, and the demo shows both: the ordinary (unnormalized) DFT needs a 1/N factor, the unitary DFT (divide by √N) does not. The ratio Etime/Efreq should be 1 to rounding error.
|x[n]| after windowing
|X[k]|
Try this: leave everything on defaults and note the ratio is 1.000000000000. Switch the plot between ordinary and unitary: the spectrum height changes by √N, yet both energies match Etime. Then read the amber “common bug” row: without the 1/N the answer is off by exactly a factor of N.
Windows: set Signal = Tone, frequency 8.5, then toggle Hann. Leakage drops, Etime drops too (the window removes energy), but Parseval still balances on the windowed data.
Background articles: Parseval’s theorem derivation · Power and energy of a signal · Significance of RMS value.
Controls explained
- Signal
- Rectangular pulse — a block of ones (spectrum is a sampled sinc). Tone — cos(2πfn/N); a bin-centered tone puts all energy in two bins (k = f and N−f). Gaussian pulse — smooth, its spectrum is also Gaussian. White noise — independent N(0,1) samples; energy is about N and spreads evenly over bins.
- Samples N
- Record length. Energy grows with N for a fixed signal shape (more samples to sum), and the unnormalized |X[k]| grows too. The 1/N in Parseval is exactly what reconciles them.
- Window
- Rectangular leaves x[n] untouched. Hann multiplies by w[n] = 0.5(1 − cos(2πn/N)). The reported energies are those of x[n]·w[n], not of x[n]. ENBW (equivalent noise bandwidth) is NΣw²/(Σw)²: 1.00 bin for rectangular, 1.50 bins for Hann.
- Plot |X[k]| using
- Ordinary is what
numpy.fft.fft, MATLABfft, and most libraries return. Unitary divides by √N (thenorm="ortho"option in NumPy), so that Σ|Xu|² = Σ|x|² with no extra factor. Only the lower plot is affected. - Pulse width / Tone frequency / Gaussian σ / Noise seed
- Signal-specific shape parameters. Each is hidden when it does not apply to the selected signal. None of them can break Parseval; they only change how the same energy is distributed over time and frequency.
- Results panel
- The two ratios should equal 1 up to floating-point rounding (relative error near 1e−15). The “common bug” row shows what you get if you sum |X[k]|² and forget the 1/N: the ratio is exactly 1/N.
How to use this demo
Pick a signal, choose N, and read the results panel. The top rows give the time-domain energy Σ|x[n]|² and the frequency-domain energy computed from the FFT under both common scalings: (1/N)Σ|X[k]|² for the ordinary DFT and Σ|Xu[k]|² for the unitary DFT. Both ratios sit at 1 up to rounding. The amber row shows the classic mistake of summing |X[k]|² without the 1/N.
Quick checks: white noise, N = 1024 (the forgotten-1/N error is now 1/1024), and a leaky tone with a Hann window.
Read next
- Parseval’s theorem: derivation and interpretation
- Power and energy of a signal
- Significance of RMS (root mean square) value
- Equivalent noise bandwidth (ENBW) of window functions
- FFT window functions demo
FAQ
Why is my energy N times too big? You summed |X[k]|² from an unnormalized FFT. Divide by N, or use the unitary (norm="ortho") transform.
Why doesn’t the ratio hit exactly 1? Floating-point rounding. Expect a relative error around 1e−15 to 1e−13, growing slightly with N.
Does a window break Parseval? No. Parseval applies to whatever sequence you hand to the FFT. After windowing, that sequence is x[n]·w[n], so its energy is lower than the original signal’s.
Why do fractional tone frequencies still satisfy Parseval? Leakage spreads the energy over many bins, but the total over all N bins is unchanged. Leakage affects where the energy shows up, not how much there is.