When you apply FFT to a real signal, you rarely get clean, sharp peaks. Instead, the energy of a single frequency component often spreads across neighboring bins, polluting the spectrum. This phenomenon is called spectral leakage — and understanding why it happens is the first step to controlling it.

Example of spectral leakage in FFT output

Example of spectral leakage — a single frequency component spreads across multiple FFT bins instead of appearing as a single sharp peak.

Why does spectral leakage appear?

FFT assumes that the captured signal repeats perfectly and infinitely — but in practice we only capture a finite slice. When that slice doesn't end cleanly, a discontinuity is introduced at the edges. There are two main scenarios that cause leakage:

Scenario 1 — frequency between bins

Consider two signals: one at 20.0 Hz and one at 22.5 Hz, both sampled at Fs = 1000 Hz with N = 1000 samples. The FFT resolution is df = Fs / N = 1 Hz, so the frequency bins are at 0, 1, 2 ... 20, 21, 22, 23 Hz — but there is no bin at 22.5 Hz.

In the time domain, the 22.5 Hz signal also does not complete an integer number of cycles within the capture window — the end of the window does not match the start:

Time domain — 20 Hz and 22.5 Hz signals in the capture window

The 20 Hz signal fits neatly into the window; the 22.5 Hz signal does not — creating an edge discontinuity.

In the frequency domain this mismatch is clearly visible. The 20 Hz component produces a clean sharp peak, while the 22.5 Hz component spreads its energy across the surrounding bins:

FFT showing spectral leakage of 22.5 Hz signal

The 20 Hz component lands exactly on a bin — clean peak. The 22.5 Hz component falls between bins and leaks into its neighbors.

Scenario 2 — non-integer number of cycles

Even if the signal frequency is perfectly aligned with the FFT bins, leakage can still occur if the captured window doesn't contain a whole number of cycles. The signal appears to jump at the boundary — and FFT treats that jump as broadband energy:

Non-integer number of cycles causing spectral leakage

A non-integer number of cycles in the capture window creates a discontinuity at the edges — leading to leakage in the FFT output.

Windowing — how it helps

A window function is a weighting applied to the signal before FFT. It gradually tapers the amplitude to zero at both edges of the capture window, eliminating the sharp discontinuity that causes leakage. The most commonly used window is the Hann window.

The comparison below shows the same signal processed without a window and with a Hann window applied. The leakage — the wide skirt of energy around the peak — is dramatically reduced:

Windowing comparison — with and without Hann window

Left: raw FFT without windowing — heavy spectral leakage. Right: FFT with Hann window applied — leakage largely eliminated.

In practice, FFT is often applied to a continuous stream of data in overlapping slices. The Hann window is commonly used in 90% of cases — it is applied independently to each frame before the FFT is computed. Let's simulate that scenario and see the results.

Types of window functions

Different window functions offer different trade-offs between frequency resolution and leakage suppression. The plot below shows the shapes of three common windows:

Window function shapes — rectangular, Hann, flat top

Shapes of three common window functions — rectangular, Hann, and flat top.

Rectangular window

The rectangular window is effectively no windowing at all — every sample in the frame is weighted equally at 1.0. It gives the best frequency resolution but provides no protection against spectral leakage. Useful only when the signal is guaranteed to contain an integer number of cycles in the window.

Rectangular window shape and FFT response

Rectangular window — flat weighting, no edge tapering, highest leakage.

Hann window

The Hann window (sometimes called Hanning) is the go-to choice for the vast majority of FFT applications. It smoothly tapers to zero at both edges using a raised cosine shape, effectively eliminating edge discontinuities.

Hann window shape and FFT response

Hann window — smooth cosine taper, good balance between resolution and leakage suppression.

Hann window equation:

w(n) = 0.5 × (1 − cos(2πn / N))
w(n) — weight of the n-th sample
n — sample index
N — last index of the window (N+1 is the window length)

Flat top window

The flat top window is designed for accurate amplitude measurement. Its passband is nearly flat, meaning signal amplitude is preserved faithfully — at the cost of much wider peaks and lower frequency resolution. It is the preferred choice when you need to measure the exact amplitude of a component rather than resolve nearby frequencies.

Flat top window shape and FFT response

Flat top window — wide, flat passband preserves amplitude accuracy at the cost of frequency resolution.

Flat top window equation:

w(n) = a0a1cos(2πn/L) + a2cos(4πn/L) − a3cos(6πn/L) + a4cos(8πn/L)
L — window length
n — sample index
a0 = 0.21558,  a1 = 0.41663,  a2 = 0.27726,  a3 = 0.08358,  a4 = 0.00695

How the windowed signal looks

When a window is applied repeatedly to overlapping slices of a continuous signal, each slice is shaped before going into the FFT. The visualization below shows successive windowed frames — note how each frame tapers smoothly to zero at both ends regardless of what the underlying signal is doing:

Successive windowed signal slices

Overlapping windowed slices of a signal. Each frame is independently tapered before FFT is applied.

The tradeoff with windowing

Applying a window is not free. Any window other than rectangular attenuates the signal — samples near the edges are multiplied by values close to zero, which reduces the total energy entering the FFT. This means the amplitude of peaks in the spectrum will be lower than the true amplitude.

To compensate, a correction factor is applied after the FFT, normalizing the output based on the known energy loss of the chosen window. Most signal processing libraries handle this automatically.

The key trade-offs to keep in mind:

Real-world example — ADXL345 accelerometer

I used an ADXL345 accelerometer connected to an STM32 microcontroller to capture vibration data from a kitchen mixer. A Python script computes FFT and renders both a spectrum and a spectrogram in real time. A physical button on the STM32 board toggles the window function on and off — making it possible to see the effect of windowing instantly on live data.

First, without any window function applied. The dominant frequency peak is clearly visible but has wide skirts — spectral leakage spreading energy into neighboring bins:

FFT without windowing — spectral leakage visible

No window applied — the dominant peak has wide leakage tails spreading into neighboring frequency bins.

After pressing the button to enable the Hann window, the leakage drops immediately. The peak becomes narrower and the spectrum around it is significantly cleaner:

FFT with Hann window — leakage suppressed

Hann window applied — leakage suppressed, the peak is sharper and the noise floor around it drops noticeably.

Real-time spectrogram — Hann window toggled on

Real-time spectrogram showing the moment the Hann window is toggled on — the leakage drops instantly and the frequency band becomes sharper and cleaner.

References

  1. Cover photo: Paweł Czerwiński on Unsplash.
  2. Brian Douglas — FFT Algorithm (MATLAB Tech Talks, YouTube)
  3. SciPy — Hann window documentation
  4. MathWorks — Flat top window