Signal Processing Foundations — Week 4

Discrete Fourier
Transform

Decompose any discrete signal into its hidden frequencies — from a chord's individual notes to the radio waves encoding mobile data. The DFT is the mathematical prism at the heart of every digital signal processing pipeline.

$X[k]=\sum x[n]\cdot e^{-j2\pi kn/N}$ Euler's Formula Phasor Wrap IDFT Synthesis Parseval's Theorem Spectral Leakage Window Functions

Time Domain vs. Frequency Domain

Every signal can be described in two complementary ways: as amplitude values evolving over time, or as a collection of frequency components each with its own strength and phase. The DFT is the mathematical bridge that converts between these two equivalent representations.

After this section you will be able to
  • Explain in plain English why the frequency domain exists and what problem it solves that the time domain cannot.
  • Identify which real-world tasks (noise removal, pitch detection, compression) are solved in the frequency domain and why.
  • Read a magnitude spectrum $|X[k]|$ and identify which bins contain signal energy and which are silent.

Imagine trying to identify a musical chord just by reading pressure numbers off an oscilloscope — you'd see a jagged, seemingly random wave. But the moment you pass that same audio through an equalizer, each frequency band lights up independently, instantly revealing the individual notes. Why does this transformation feel like magic, and how does it work mathematically?

🎯
Why this matters: Every downstream task in audio processing, image compression, wireless communication, and scientific analysis begins with a frequency-domain view. Without the ability to switch representations, noise removal, pitch detection, and spectrum sensing would be computationally impossible.
🔗
Think of it this way

The DFT is like a glass prism separating white light into a rainbow. A complex audio chord (the "white light") passes through the DFT (the "prism") and emerges as separate, identifiable pure sinusoidal components (the "colors"). Just as you can reconstruct white light by recombining all the colors, you can perfectly reconstruct the original signal by recombining all the DFT bins.

Time Domain
Amplitude vs time — you see shape but not frequency content
DFT Arrow
$X[k] = \sum x[n]\cdot e^{-j2\pi kn/N}$ — the prism operation
Magnitude Spectrum
$|X[k]|$ vs bin $k$ — tall spikes show which frequencies are present
IDFT Back
Perfectly reconstruct the original signal — zero information lost
Time Domain x[0], x[1], …, x[N−1] N real samples DFT Freq Domain X[0], X[1], …, X[N−1] N complex coefficients Each bin X[k] = how much of frequency k·Δf is in the signal k=0 k=2 k=5 k=7 Δf = fs/N Hz per bin Tall spike = strong freq component

DFT maps N time samples → N complex frequency bins. Each bin $X[k]$ reports the amplitude and phase of the sinusoid at frequency $k \cdot \Delta f$ Hz. Tall bars indicate strong frequency components in the signal.

N
samples in = bins out
DFT is a square transformation — N inputs always produce exactly N outputs
Δf
= fₛ / N
Frequency resolution: more samples = finer bin spacing = better frequency precision
N/2
unique bins
For real signals, bins above N/2 mirror bins below (conjugate symmetry)
0
information lost
DFT is perfectly invertible — the IDFT recovers the original signal exactly
Problem

Two Views of the Same Signal

A signal exists simultaneously in both domains. Neither is more "real" — each is more useful for different tasks.

Dimension Time Domain Frequency Domain
Horizontal axis Sample index $n$ Bin index $k$ (= $k \cdot f_s/N$ Hz)
Vertical axis Amplitude $x[n]$ Magnitude $|X[k]|$ and phase $\angle X[k]$
Best for Detecting events, onsets, transients Identifying pitch, tone, spectral content
Notation $x[n]$ — real discrete samples $X[k]$ — complex DFT coefficients

Reading a Magnitude Spectrum

The magnitude spectrum $|X[k]|$ shows amplitude per frequency bin. A tall spike at bin $k$ means a strong sinusoidal component at frequency $f_k = k \cdot f_s / N$ Hz. Silent bins (near zero) mean no energy at that frequency.

📝 Worked Example — Locating Signal Frequency in the Bin Grid

Problem: Signal is a pure 3 Hz cosine, sampled at $f_s = 16$ Hz, $N = 16$ samples. Which DFT bin contains the energy?

1
Find the frequency resolution.
$\Delta f = f_s / N = 16 / 16 = 1$ Hz per bin.
So bin $k$ represents exactly $k$ Hz.
2
Locate the signal frequency.
Signal is at 3 Hz → falls exactly on bin $k = 3$.
Conjugate symmetry places a mirror at $k = N - 3 = 13$.
3
Interpret the spectrum.
All other bins are zero — single-tone signal.
Magnitude at bin 3: $|X[3]| = N/2 = 8$ (unit-amplitude cosine, before normalization).
Active bins: k=3 (3 Hz) and k=13 (mirror). Δf = 1 Hz/bin.
Quick Check

If $f_s = 8000$ Hz and $N = 256$, what is the frequency resolution $\Delta f$? Which bin contains a 1000 Hz tone?

Hint
Δf = 8000/256 = 31.25 Hz/bin. The 1000 Hz tone lands on bin k = 1000/31.25 = 32.

Six Reasons the Frequency Domain Wins

The frequency domain unlocks operations that are impossible or prohibitively expensive in the time domain.

  1. Audio Compression (MP3). Psychoacoustic models analyze which frequency bins can be aggressively quantized without perceptible quality loss — then store only those.
  2. Image Compression (JPEG). A 2D cousin of the DFT (the DCT) separates low-frequency image structure from high-frequency edge detail, discarding what the eye cannot perceive.
  3. Noise Removal. Noise occupies distinct frequency bands. Setting those $X[k]$ to zero and applying the IDFT returns a clean signal — impossible in the time domain without corrupting the signal.
  4. Pitch & Chord Detection. Music apps identify notes by finding peaks in $|X[k]|$ — each peak corresponds to one frequency component.
  5. OFDM (4G/5G/Wi-Fi). Data bits are modulated onto parallel frequency sub-carriers using an IDFT at the transmitter; the DFT recovers them at the receiver.
  6. Scientific Discovery. Seismologists and astronomers search for periodic phenomena — earthquake resonances, pulsar rotation rates — by inspecting spectral peaks.
⚠️
Common Mistake

Confusing bin index with Hz. Bin $k$ does NOT equal $k$ Hz unless $\Delta f = 1$ Hz. Always compute $f_k = k \cdot f_s / N$ to find the physical frequency. With $f_s = 44100$ Hz and $N = 1024$, bin $k = 10$ represents $10 \times 44100/1024 \approx 430$ Hz — not 10 Hz.

Solution
Pause & Predict

Below is an interactive decomposer. Before pressing play, predict: a square wave is built from sine waves at what frequencies? (Hint: it starts at frequency $f_0$ and includes harmonics at $3f_0$, $5f_0$, $7f_0$, …)

After predicting, try the "Square Wave" button and verify your prediction against the magnitude spectrum.

Try It: Time ↔ Frequency Decomposer

Select a signal type. Watch the time-domain waveform transform into its DFT magnitude spectrum in real time.

Time domain x[n] (top half) DFT magnitude |X[k]| (bottom half)
Implementation
Python · NumPy/SciPy — Computing and Plotting the Magnitude Spectrum
import numpy as np import matplotlib.pyplot as plt fs = 16 # sampling rate (Hz) N = 16 # number of samples n = np.arange(N) # Build a pure 3 Hz cosine signal x = np.cos(2 * np.pi * 3 * n / fs) # Compute DFT and magnitude spectrum X = np.fft.fft(x) # complex DFT coefficients freqs = np.fft.fftfreq(N, 1/fs) # bin frequencies in Hz mag = np.abs(X) # magnitude |X[k]| # Plot (one-sided: bins 0 to N//2) half = N // 2 plt.stem(freqs[:half], mag[:half], 'b', markerfmt='bo') plt.xlabel('Frequency (Hz)'); plt.ylabel('|X[k]|') plt.title('Magnitude Spectrum — 3 Hz cosine') plt.show()
Output
Stem plot with tall spike at 3 Hz (magnitude = 8.0). All other bins are zero (pure single-frequency signal). Mirror spike at 13 Hz (conjugate symmetry for real signals). Δf = fs/N = 1 Hz per bin.
Key Takeaway

The DFT is a domain switch — the same signal viewed through a prism that separates it into its constituent frequencies, each bin reporting exactly how much of one sinusoid is present.

🎵
Real-World Application

Real-Time Audio Spectrum Visualizer (Spotify, YouTube Music)

The animated frequency bars bouncing to music in any streaming app are computed by running a DFT repeatedly over short overlapping windows of audio — typically 1024 or 2048 samples. The height of each bar equals $|X[k]|$ for that frequency bin: low-$k$ bins on the left represent deep bass, high-$k$ bins represent treble. This runs on a smartphone at 60 frames per second, processing millions of DFT operations per second in real time.

Checkpoint Time Domain vs. Frequency Domain

Q1 A signal has $f_s = 100$ Hz and $N = 100$ samples. What is the frequency resolution $\Delta f$, and which bin number contains a 25 Hz tone?

Hint
Δf = 100/100 = 1 Hz/bin. The 25 Hz tone is at bin k = 25.

Q2 Why does a unit impulse $x[n]=\delta[n]$ have a flat magnitude spectrum where all $|X[k]|$ are equal?

Hint
$X[k] = \sum x[n]e^{-j2\pi kn/N} = x[0]\cdot e^0 = 1$ for all k. A perfect impulse contains equal energy at every frequency — it is the "all-white-light" signal.

Q3 Name two tasks that become computationally feasible in the frequency domain that are impractical in the time domain.

Hint
Any two of: noise removal by zeroing frequency bins, pitch detection by finding spectral peaks, audio/image compression by discarding perceptually insignificant bins, channel equalization in OFDM wireless systems.

The DFT Equation: A Complete Breakdown

The DFT maps $N$ time-domain samples to $N$ complex frequency coefficients. At its core, it multiplies the signal by a rotating complex sinusoid at each target frequency and sums the result — a clever inner-product test for "how much of this frequency is present?"

After this section you will be able to
  • Compute $X[0]$ and $X[1]$ for any $N=4$ signal by hand using the DFT summation formula.
  • Apply Euler's formula $e^{j\theta} = \cos\theta + j\sin\theta$ to expand any complex exponential into real and imaginary parts.
  • Interpret each symbol in $X[k] = \sum_{n=0}^{N-1} x[n]\,e^{-j2\pi kn/N}$ without referring to notes.

Have you ever wondered why complex numbers appear in a formula about real audio signals? The trick is that a single complex exponential $e^{j\theta}$ simultaneously encodes both a cosine and a sine in one compact object — giving us two orthogonal "frequency detectors" for the price of one symbol.

🎯
Why this matters: Understanding the DFT equation term by term lets you derive every property of the spectrum — symmetry, resolution, bin frequency, and energy — directly from first principles. Every spectral analysis tool you will ever use (SciPy, librosa, MATLAB) implements exactly this formula.
🔗
Think of it this way

Each DFT output $X[k]$ is like asking the signal: "Are you friends with a 440 Hz tone?" You play a 440 Hz test tone, multiply it sample-by-sample with the signal, then sum everything up. If the signal contains 440 Hz, the products add up constructively (large $|X[k]|$). If it doesn't, they cancel to zero. That "multiply-and-sum" is exactly what $\sum x[n]\cdot e^{-j2\pi kn/N}$ does for each bin $k$.

$x[n]$
Input Sample
Time-domain signal value at index $n$
e.g. x[2] = 0.5
$X[k]$
DFT Output
Complex coefficient at frequency bin $k$
e.g. X[3] = 2+0j
$N$
Window Length
Total number of samples analyzed
e.g. N = 1024
$k$
Bin Index
Output frequency index, 0 to N−1
k=0 = DC, k=1 = Δf Hz
$n$
Sample Index
Time index of input samples, 0 to N−1
n=0,1,…,N−1
$e^{-j\theta}$
Probe Sinusoid
Rotating complex exponential — the "test tone"
= cos θ − j sin θ
Problem

The Analysis Equation

Given $N$ samples $x[0], \ldots, x[N-1]$, the DFT produces $N$ complex coefficients $X[0], \ldots, X[N-1]$:

DFT Definition (Analysis Equation)

$$X[k] = \sum_{n=0}^{N-1} x[n]\cdot e^{-j\frac{2\pi}{N}kn}, \quad k = 0, 1, \ldots, N-1$$

$X[k] = \displaystyle\sum_{n=0}^{N-1} x[n] \cdot e^{-j\,\frac{2\pi}{N}\,k\,n}$
X[k]
DFT Output
Complex amplitude at frequency bin k
x[n]
Input sample
Signal value at time step n
e−j2πkn/N
Probe tone
Unit phasor rotating at frequency k/N cycles per sample
Σ
Inner product
Sum over all N samples — tests correlation with probe
N
Window size
Total samples; sets frequency resolution Δf = fₛ/N
📝 Worked Example — Computing X[0] and X[1] for N=4 by Hand

Problem: Compute $X[0]$ and $X[1]$ for the signal $x = [1, 0, -1, 0]$ with $N = 4$.

1
Compute X[0] (DC component, k=0).
$X[0] = \sum_{n=0}^{3} x[n]\cdot e^{0} = x[0]+x[1]+x[2]+x[3]$
$= 1 + 0 + (-1) + 0 = 0$
2
Find probe values for X[1] (k=1).
$e^{-j\frac{2\pi}{4}\cdot 1 \cdot n}$ for $n=0,1,2,3$:
$n=0$: $e^0 = 1$
$n=1$: $e^{-j\pi/2} = \cos(-90°)+j\sin(-90°) = 0 - j = -j$
$n=2$: $e^{-j\pi} = -1$
$n=3$: $e^{-j3\pi/2} = +j$
3
Sum to get X[1].
$X[1] = 1\cdot 1 + 0\cdot(-j) + (-1)\cdot(-1) + 0\cdot j$
$= 1 + 0 + 1 + 0 = 2$
X[0] = 0 (no DC). X[1] = 2 (signal has energy at 1-cycle-per-window).
Quick Check

Using the same signal $x = [1,0,-1,0]$ with $N=4$, compute $X[2]$ by hand. What do you expect physically?

Hint
Probe for k=2: n=0→1, n=1→−1, n=2→1, n=3→−1. X[2] = 1·1 + 0·(−1) + (−1)·1 + 0·(−1) = 1 − 1 = 0. Physically, [1,0,−1,0] is a 1-cycle-per-4-sample cosine, so only bins k=1 and k=3 should have energy.

Euler's Formula — The Hidden Foundation

The complex exponential $e^{j\theta}$ is the key to why the DFT uses complex numbers. Euler's formula unpacks it:

Euler's Formula

$$e^{j\theta} = \cos\theta + j\sin\theta$$

In the DFT, the probe is $e^{-j2\pi kn/N}$, which expands to:

$\cos\!\left(\tfrac{2\pi kn}{N}\right) - j\sin\!\left(\tfrac{2\pi kn}{N}\right)$

The real part (cosine) detects even-symmetric frequency content. The imaginary part (−sine) detects odd-symmetric content. Together they capture both amplitude and phase of any sinusoidal component.

📝 Worked Example — Expanding e^{−j2π·1·n/4} for n=0,1,2,3

Problem: Expand the probe $e^{-j\pi n/2}$ at each $n$ using Euler's formula.

1
n=0: $e^{0} = \cos(0) - j\sin(0) = 1 - 0j = 1$
2
n=1: $e^{-j\pi/2} = \cos(-90°) - j\sin(-90°)$
Wait — use $e^{-j\theta} = \cos\theta - j\sin\theta$:
$= \cos(\pi/2) - j\sin(\pi/2) = 0 - j = -j$
3
n=2: $e^{-j\pi} = \cos\pi - j\sin\pi = -1 - 0j = -1$
n=3: $e^{-j3\pi/2} = \cos(3\pi/2) - j\sin(3\pi/2) = 0 + j = +j$
Probe values: [1, −j, −1, +j] — a unit phasor cycling once around the unit circle.
Quick Check

What is $|e^{j\theta}|$ for any $\theta$? Why does this matter for the DFT probe?

Hint
|e^{jθ}| = √(cos²θ + sin²θ) = 1 always. The probe is a pure unit-length phasor — it never amplifies or attenuates the signal, only rotates it. This ensures the DFT is an energy-preserving (unitary) transform.
💡

Twiddle factor shorthand: The probe $W_N^{kn} = e^{-j2\pi kn/N}$ is often called the twiddle factor in DSP literature. You will see this notation in FFT algorithm descriptions (Week 5). For now, remember $W_N = e^{-j2\pi/N}$ is just Euler's formula with a fixed angular step.

Solution
Pause & Predict

The widget below lets you choose $N$ and watch $X[1]$ computed step by step. Before using it, predict: for $x = [1,0,-1,0]$ with $N=4$, what is $|X[1]|$? (You just computed it by hand above.)

Then try $N = 8$ with the same pattern and predict how the spectrum changes.

Try It: Step-by-Step DFT Summation

Choose a target bin $k$ and signal type. Watch the multiply-and-sum process animate on the complex plane and see the running total build up.

1
$x[n]$ (input) Probe $e^{-j2\pi kn/N}$ (rotating) Product $x[n]\cdot e^{-j2\pi kn/N}$ (accumulating sum)
Live DFT Summation — X[k] = Σ x[n]·e^(−j2πkn/N)
Select a bin to see the summation
Implementation
Python · NumPy — DFT from Scratch vs. np.fft.fft()
import numpy as np def dft_naive(x): """Compute DFT using the definition — O(N²) for learning.""" N = len(x) X = np.zeros(N, dtype=complex) for k in range(N): for n in range(N): X[k] += x[n] * np.exp(-1j * 2 * np.pi * k * n / N) return X x = np.array([1, 0, -1, 0]) X_naive = dft_naive(x) X_fft = np.fft.fft(x) # NumPy's optimised FFT print("Naive DFT:", np.round(X_naive, 6)) print("np.fft.fft:", np.round(X_fft, 6)) print("Match:", np.allclose(X_naive, X_fft))
Output
Naive DFT: [ 0.+0.j 2.+0.j 0.+0.j 2.+0.j] np.fft.fft: [ 0.+0.j 2.+0.j 0.+0.j 2.+0.j] Match: True
Key Takeaway

The DFT is a set of N inner products — each bin $X[k]$ asks "how correlated is this signal with a pure sinusoid at frequency $k \cdot f_s/N$ Hz?" and the complex answer encodes both the amplitude and the phase of that correlation.

📡
Real-World Application

Matched Filter Detection in Radar & Sonar

A radar system transmits a known chirp signal. When the echo returns, it runs a DFT-based matched filter — multiplying the received signal's spectrum $X[k]$ by the conjugate of the transmitted chirp's spectrum $H^*[k]$ and taking the IDFT. The result is a sharp peak at the time delay proportional to distance. This is exactly the "multiply probe and sum" operation of the DFT applied across all frequency bins simultaneously — turning a noisy return signal into a precise range estimate.

Checkpoint DFT Equation & Euler's Formula

Q1 Expand $e^{-j\pi/2}$ using Euler's formula. Give the real and imaginary parts.

Hint
$e^{-j\pi/2} = \cos(\pi/2) - j\sin(\pi/2) = 0 - j = -j$. Real part = 0, imaginary part = −1.

Q2 For the signal $x = [2, 2, 2, 2]$ and $N = 4$, what is $X[0]$? What does this value represent physically?

Hint
$X[0] = x[0]+x[1]+x[2]+x[3] = 8$. Bin k=0 is the DC (average) component. A constant signal has all its energy at zero frequency — the DFT correctly reports 8 (sum of all samples).

Q3 What is $|e^{-j\theta}|$ for any real angle $\theta$? Why is this property important for the DFT?

Hint
$|e^{-j\theta}| = 1$ always (unit circle). This means the probe never amplifies or attenuates the signal — it only rotates the phase. This makes the DFT a norm-preserving (unitary) transform, which is why Parseval's theorem holds.

Phasor Wrap: Why the DFT Finds Hidden Frequencies

The DFT's inner product can be visualised geometrically: wrap the signal around a circle at a chosen frequency and look at where the centre of mass lands. A strong frequency component makes all wrapped points cluster on one side — the centre of mass moves far from the origin, producing a large $|X[k]|$.

After this section you will be able to
  • Describe the phasor-wrap visualisation of the DFT and explain geometrically why the magnitude $|X[k]|$ is large when the signal contains frequency $k$.
  • Explain DFT as correlation: what it means to "correlate" a signal with a probe frequency, and why constructive summation indicates a match.
  • Identify the conjugate symmetry property: for real signals, $X[N-k] = X^*[k]$, and explain why only the first $N/2$ bins carry unique information.

Why does multiplying a signal by a complex exponential and summing detect frequency? The answer becomes obvious once you see it geometrically: imagine winding the signal like a spring around a circle. If the signal oscillates at exactly the winding frequency, all the spring's mass lands on the same side of the circle — its centre of mass is far from the origin. If the frequencies don't match, the mass cancels out and the centre of mass collapses to zero.

🎯
Why this matters: The phasor-wrap model gives you a physical picture of why the DFT works — not just a formula to memorize. It also reveals why a real signal's spectrum is mirror-symmetric and why increasing $N$ sharpens frequency resolution.
🔗
Think of it this way

Imagine you spin a bucket of water at a certain rate. If the water is sloshing at the same frequency as your spin, the water builds up on one wall — you feel a strong net force. If the frequencies don't match, the sloshes cancel around the bucket and you feel no net force. The DFT "spin rate" is $k/N$ cycles per sample; the "felt force" is $|X[k]|$.

Signal x[n]
Original discrete-time signal — amplitude vs sample index
Wrap at f₀
Signal wound onto circle at probe frequency k/N
Match! Large |X[k]|
Points cluster on one side → centre of mass far from origin
No Match → 0
Points spread evenly → centre of mass near origin → |X[k]| ≈ 0
1
Input signal x[n]
2
Probe $e^{-j2\pi kn/N}$ rotates
3
Products x[n]·probe plotted on circle
4
Sum = X[k] (centre of mass vector)
5
|X[k]| large → match ≈0 → no match
|X[k]| = frequency strength

The DFT phasor-wrap: wind x[n] onto a circle at frequency k/N, plot each scaled point, then take the vector sum. A strong frequency component causes the points to cluster, giving a large magnitude $|X[k]|$.

Problem

DFT as Frequency Correlation

Each DFT output is the cross-correlation of the signal with a pure sinusoid. For real $x[n]$ the signal's energy is entirely in bins $k = 0$ to $N/2$:

Correlation Interpretation

The DFT inner product $X[k] = \langle x, \phi_k \rangle$ measures how well the signal $x[n]$ overlaps with the probe $\phi_k[n] = e^{j2\pi kn/N}$. Large $|X[k]|$ = high correlation = signal contains frequency $k \cdot f_s / N$.

  • $|X[k]|$ = correlation strength (amplitude of frequency $k$)
  • $\angle X[k]$ = phase offset of that frequency component
  • $|X[k]|^2$ = power spectral density at bin $k$
📝 Worked Example — Phasor Wrap for x=[1,0,-1,0], k=1, N=4

Goal: Verify that $|X[1]|$ is large by tracing the phasor-wrap mentally.

1
Probe rotates: angle per step = $-2\pi k/N = -\pi/2$ rad
Step 0→1→2→3 angles: $0°, -90°, -180°, -270°$ (= +90°)
2
Scale probe by x[n]:
$n=0$: $1 \times (1+0j) = 1$
$n=1$: $0 \times (0-j) = 0$ (no contribution)
$n=2$: $-1 \times (-1+0j) = +1$
$n=3$: $0 \times (0+j) = 0$ (no contribution)
3
Sum = centre of mass.
$X[1] = 1 + 0 + 1 + 0 = 2$
Both non-zero contributions land at the same point (real=+1) on the unit circle — they cluster together, so the vector sum is far from the origin.
|X[1]| = 2. The signal's frequency matches the probe → constructive clustering → large magnitude.
Quick Check

For the same signal, explain geometrically why $|X[2]| = 0$. Where do the non-zero contributions land on the unit circle when using the k=2 probe?

Hint
For k=2, probe angles step by −π rad. At n=0: 1×(+1) = +1. At n=2: −1×(+1) = −1 (probe completed a full half-turn, lands back at +1, but scaled by −1). These two contributions are equal and opposite → they cancel → X[2] = 0. Perfect destructive cancellation = no signal at frequency 2.

Conjugate Symmetry (Real Signals)

When the input $x[n]$ is real-valued (as it almost always is for physical signals), the DFT has a mirror property:

Conjugate Symmetry Property

$$X[N-k] = X^*[k] \quad \text{(for real } x[n]\text{)}$$

Consequence: Bins $k = 0$ to $k = N/2$ contain all unique frequency information. Bins $k = N/2 + 1$ to $k = N-1$ are redundant (complex conjugates of bins $k = N/2 - 1$ down to $k = 1$).

One-sided spectrum: When plotting real signals, only show bins $k = 0$ to $k = N/2$, and double the magnitudes of bins $1$ to $N/2 - 1$ to conserve total energy.

📝 Worked Example — Verifying Conjugate Symmetry for N=4

Signal: $x = [1, 0, -1, 0]$. We computed $X = [0, 2, 0, 2]$.

1
Check X[3] vs X*[1].
$X[1] = 2 + 0j$ → $X^*[1] = 2 - 0j = 2$
$X[N-1] = X[3] = 2$. ✓ Match.
2
Unique bins: k = 0, 1, 2 (= N/2).
Bin 3 mirrors bin 1. For a more complex signal, bins $\{3, N-1\}$ always mirror $\{1\}$ for real $x[n]$.
Unique information in N=4 signal: bins k=0,1,2. Bin k=3 is redundant.
Quick Check

For a real signal with $N = 256$ samples, how many unique (non-redundant) DFT bins are there?

Hint
N/2 + 1 = 129 unique bins: k=0 (DC), k=1 to k=127 (one-sided), and k=128 (Nyquist). Bins k=129 to k=255 mirror bins k=127 down to k=1.
💡
Key Insight

The phasor wrap is why DFT needs complex numbers. A real-only probe (cosine) can only tell you the amplitude, not the phase. The complex probe simultaneously rotates through all phase angles, detecting both the magnitude AND the phase offset of each frequency component in a single pass. Using only a cosine probe would require two separate passes.

Solution
Pause & Predict

The widget below animates the phasor wrap for different signals and probe frequencies. Before adjusting the slider, predict: if you set the probe frequency equal to the signal frequency, what shape will the wrapped points form?

Prediction: all points cluster on one side of the circle (not spread evenly). Verify with the widget.

Try It: Phasor-Wrap Visualiser

Adjust the probe frequency $k$. Watch how the wrapped points cluster (match) or spread (no match). The centre-of-mass vector is $X[k]$.

2
Wrapped points x[n]·probe Centre of mass = X[k]
Implementation
Python · NumPy — One-Sided Spectrum & Conjugate Symmetry Check
import numpy as np N = 64 fs = 64 n = np.arange(N) x = np.cos(2*np.pi*5*n/fs) + 0.5*np.cos(2*np.pi*12*n/fs) X = np.fft.fft(x) # Verify conjugate symmetry: X[N-k] == conj(X[k]) k = 5 print(f"X[k] = {X[k]:.4f}") print(f"X[N-k] = {X[N-k]:.4f}") print(f"X[k]* = {X[k].conj():.4f}") print(f"Symmetric: {np.isclose(X[N-k], X[k].conj())}") # One-sided magnitude spectrum (bins 0 to N//2) half = N // 2 mag_one_sided = np.abs(X[:half+1]) mag_one_sided[1:half] *= 2 # double non-DC/Nyquist bins for energy conservation
Output
X[k] = 32.0000+0.0000j X[N-k] = 32.0000-0.0000j X[k]* = 32.0000-0.0000j Symmetric: True
Key Takeaway

The DFT is a geometric correlation test: a large $|X[k]|$ means the signal's phasor-wrapped points cluster on one side of the circle, revealing that frequency $k \cdot f_s/N$ is present with that strength and phase.

🔬
Real-World Application

NMR & MRI — Phasor Wrap in Medicine

In Magnetic Resonance Imaging, hydrogen nuclei in the body precess (spin) at frequencies proportional to the local magnetic field strength. The MRI scanner records the combined radio-frequency signal from millions of spinning protons. Applying a Fourier transform to the received signal — exactly the phasor-wrap correlation we studied — separates the signal by frequency, and since frequency encodes spatial position (via a field gradient), the result is a spatial image of tissue density. The DFT turns a time-domain radio signal into an anatomical cross-section image.

Checkpoint Phasor Wrap & Conjugate Symmetry

Q1 In the phasor-wrap model, what does it mean when all the wrapped points cluster tightly on one side of the circle?

Hint
The signal contains a strong sinusoidal component at the probe frequency. Constructive clustering pushes the centre of mass (= X[k]) far from the origin, giving a large |X[k]|.

Q2 State the conjugate symmetry property for a real signal $x[n]$ and explain its practical consequence for plotting spectra.

Hint
$X[N-k] = X^*[k]$. The upper half of the DFT (bins N/2+1 to N−1) mirrors the lower half. In practice, we only plot the one-sided spectrum (bins 0 to N/2) and double the magnitudes of bins 1 to N/2−1 to correctly represent signal power.

Q3 Why does the DFT use a complex probe $e^{-j2\pi kn/N}$ rather than just a cosine $\cos(2\pi kn/N)$?

Hint
A cosine probe only captures amplitude, not phase. The complex probe encodes both cosine (real part) and sine (imaginary part) simultaneously, allowing a single pass to detect both the magnitude AND phase offset of any frequency component. A cosine-only probe would be blind to sine components and would require a second pass with a sine probe.

IDFT & Parseval's Theorem

The Inverse DFT reconstructs the original signal from its frequency coefficients — proving the DFT is perfectly reversible. Parseval's Theorem then guarantees that the total energy computed in the time domain exactly equals the total energy computed in the frequency domain, confirming no information is created or destroyed.

After this section you will be able to
  • Write the IDFT formula and identify how it differs from the DFT formula (sign of exponent, $1/N$ scaling).
  • Compute $x[n]$ from a given $X[k]$ for $N = 4$ using the IDFT summation by hand.
  • Apply Parseval's Theorem to verify that time-domain and frequency-domain energies match for a given signal.

After the DFT converts your signal into frequency coefficients, how do you get back to the original waveform? And when you modify those coefficients — say, zeroing out noisy frequency bins — are you guaranteed to get a valid signal back? The IDFT answers the first question, and Parseval's Theorem provides the energy accounting that makes frequency-domain editing trustworthy.

🎯
Why this matters: Every noise-cancellation, equalizer, and compression algorithm works in the frequency domain by modifying $X[k]$ and then applying the IDFT to reconstruct the cleaned signal. Understanding the IDFT and Parseval's guarantees lets you reason about what modifications are valid and what trade-offs exist.
🔗
Think of it this way

The DFT is like disassembling a LEGO model into sorted bins (blue bricks here, red bricks there). The IDFT is the instruction sheet that reassembles exactly the same model from those bins. Parseval's Theorem says: the total weight of all the bricks in the bins equals the total weight of the assembled model — nothing was lost in sorting or reassembly.

+j
sign flip
IDFT uses $e^{+j2\pi kn/N}$ — the only difference from the forward DFT's $e^{-j}$
1/N
scaling factor
IDFT divides by N to normalize — forward DFT accumulates, IDFT averages
Et = Ef
Parseval's Theorem
$\sum|x[n]|^2 = \frac{1}{N}\sum|X[k]|^2$ — energy is conserved across domains
Problem

The Inverse DFT

The IDFT reconstructs $x[n]$ from $X[k]$ by summing all $N$ complex sinusoidal components:

IDFT Definition (Synthesis Equation)

$$x[n] = \frac{1}{N}\sum_{k=0}^{N-1} X[k]\cdot e^{+j\frac{2\pi}{N}kn}, \quad n = 0, 1, \ldots, N-1$$

$x[n] = \dfrac{1}{N}\displaystyle\sum_{k=0}^{N-1} X[k]\cdot e^{+j\,\frac{2\pi}{N}\,k\,n}$
x[n]
Reconstructed sample
Time-domain output at index n
X[k]
DFT coefficient
Complex amplitude of bin k from forward DFT
e+j2πkn/N
Synthesis tone
Same phasor as DFT but +j (reversed rotation)
1/N
Normalization
Averages the N accumulated contributions
📝 Worked Example — Recovering x[n] from X[k] by Hand (N=4)

Problem: Given $X = [0, 2, 0, 2]$ with $N=4$, compute $x[0]$ and $x[1]$ using the IDFT.

1
Compute x[0] (n=0).
$x[0] = \frac{1}{4}\sum_{k=0}^{3} X[k]\cdot e^{+j2\pi k\cdot 0/4}$
$= \frac{1}{4}(X[0]\cdot 1 + X[1]\cdot 1 + X[2]\cdot 1 + X[3]\cdot 1)$
$= \frac{1}{4}(0 + 2 + 0 + 2) = \frac{4}{4} = 1$
2
Compute x[1] (n=1).
Probe values for each $k$: $e^{+j2\pi k/4}$ for $k=0,1,2,3$:
$k=0$: $e^0=1$, $k=1$: $e^{+j\pi/2}=j$, $k=2$: $e^{+j\pi}=-1$, $k=3$: $e^{+j3\pi/2}=-j$
$x[1] = \frac{1}{4}(0\cdot 1 + 2\cdot j + 0\cdot(-1) + 2\cdot(-j))$
$= \frac{1}{4}(2j - 2j) = 0$
3
Interpret.
$x[0]=1, x[1]=0$ matches the original $x=[1,0,-1,0]$.
x[0]=1, x[1]=0. The IDFT perfectly recovers the original signal.
Quick Check

Compute $x[2]$ for $X=[0,2,0,2]$ with $N=4$ using the IDFT formula. What do you expect?

Hint
Probe values for n=2: k=0→1, k=1→e^{+jπ}=−1, k=2→e^{+j2π}=1, k=3→e^{+j3π}=−1. x[2] = (1/4)(0·1 + 2·(−1) + 0·1 + 2·(−1)) = (1/4)(−2−2) = −1. Correct — x[2]=−1 matches the original.

Parseval's Theorem

The total signal energy computed in the time domain equals the total energy computed in the frequency domain:

Parseval's Theorem

$$\sum_{n=0}^{N-1}|x[n]|^2 = \frac{1}{N}\sum_{k=0}^{N-1}|X[k]|^2$$

The left side is the total energy of all $N$ time samples. The right side is the total energy of all $N$ frequency bins (divided by $N$ for normalization). They must always be equal.

Why it matters: When you zero out frequency bins (noise removal), you can directly compute how much energy you removed — before inverting. This lets you predict the signal-to-noise ratio improvement before performing the IDFT.

📝 Worked Example — Verifying Parseval's for x=[1,0,-1,0]

Signal: $x=[1,0,-1,0]$, DFT $X=[0,2,0,2]$, $N=4$.

1
Time-domain energy $E_t$:
$E_t = |1|^2 + |0|^2 + |-1|^2 + |0|^2 = 1+0+1+0 = 2$
2
Frequency-domain energy $E_f$:
$E_f = \frac{1}{N}\sum|X[k]|^2 = \frac{1}{4}(|0|^2+|2|^2+|0|^2+|2|^2)$
$= \frac{1}{4}(0+4+0+4) = \frac{8}{4} = 2$
3
Verify.
$E_t = E_f = 2$. ✓
Time energy = Freq energy = 2. Parseval's Theorem confirmed.
Quick Check

For signal $x = [2, 0, 0, 0]$ with $N=4$: (a) compute the time-domain energy $E_t$; (b) verify that $E_f = E_t$ by computing all $|X[k]|$ first.

Hint
(a) E_t = 4. (b) x=[2,0,0,0] is a scaled impulse → X[k]=2 for all k (flat spectrum). E_f = (1/4)(4+4+4+4) = 16/4 = 4. ✓ Matches.
💡

Noise removal arithmetic: If signal energy is $E_s = 10$ and you zero out 30% of the bins, the energy removed is approximately $0.3 \times E_f = 0.3 \times E_t$. The residual energy after denoising is approximately $0.7 \times E_t$ — computable before you even run the IDFT.

Solution
Pause & Predict

The widget below lets you modify frequency bins and see the IDFT reconstruction. Before experimenting, predict: if you zero out all bins except bin $k=3$, what will the reconstructed signal look like?

A single non-zero bin = a pure sinusoid at frequency $3 \cdot f_s/N$ Hz. Predict the frequency and amplitude before pressing.

Try It: IDFT Synthesizer & Parseval Check

Adjust the amplitude of each DFT bin. Watch the IDFT reconstruct the signal in real time. The Parseval panel shows time and frequency energy.

4
0
2
IDFT Reconstruction x[n]
Frequency Domain |X[k]|
Parseval Energy Check
Implementation
Python · NumPy — IDFT, Parseval's Theorem & Frequency-Domain Denoising
import numpy as np fs = 64; N = 64 n = np.arange(N) signal = np.cos(2*np.pi*5*n/fs) noise = 0.5 * np.random.randn(N) x = signal + noise # Forward DFT X = np.fft.fft(x) # Parseval check E_time = np.sum(np.abs(x)**2) E_freq = np.sum(np.abs(X)**2) / N print(f"E_time = {E_time:.4f}, E_freq = {E_freq:.4f}, match: {np.isclose(E_time, E_freq)}") # Simple denoising: zero out bins where |X[k]| < threshold threshold = 5.0 X_clean = X.copy() X_clean[np.abs(X_clean) < threshold] = 0 # Inverse DFT to reconstruct clean signal x_clean = np.real(np.fft.ifft(X_clean)) print(f"Bins zeroed: {np.sum(np.abs(X_clean) == 0)}/{N}") print(f"Energy removed: {(sum(np.abs(X)**2) - sum(np.abs(X_clean)**2)) / N:.4f}")
Output
E_time = 48.2311, E_freq = 48.2311, match: True Bins zeroed: 60/64 Energy removed: 6.3142
Key Takeaway

The DFT and IDFT form a perfect inverse pair: modify frequency bins to engineer the signal, then reconstruct with the IDFT — and Parseval's Theorem guarantees exact energy accounting throughout.

🎧
Real-World Application

Audio Equalizers & Noise Gates

Every digital audio equalizer — from studio mixing consoles to smartphone earphone apps — works by taking the DFT of an audio block, multiplying each bin by a gain factor (the EQ curve), and applying the IDFT. A noise gate zeros out bins below a threshold (similar to our denoising code above). Parseval's Theorem means the audio engineer can directly read energy removed from the frequency display and predict exactly how much quieter the noise floor will become — a direct link between the frequency-domain operation and the audible result.

Checkpoint IDFT & Parseval's Theorem

Q1 Write the IDFT formula. How does it differ from the DFT formula? (Name both differences.)

Hint
Two differences: (1) exponent sign is +j instead of −j (probe rotates in the opposite direction); (2) a 1/N scaling factor divides the sum to normalize. Everything else — the sum structure, the indices — is identical.

Q2 For signal $x = [3, 0, 0, 0]$ with $N=4$: compute the time-domain energy $E_t$ and verify Parseval's Theorem (all bins of this signal have $|X[k]| = 3$).

Hint
E_t = 3² = 9. |X[k]|=3 for all 4 bins → E_f = (1/4)(9+9+9+9) = 36/4 = 9. ✓ E_t = E_f = 9.

Q3 A denoising algorithm zeros out 80% of the DFT bins of a signal with total energy $E = 100$. Approximately how much energy remains after the IDFT reconstruction?

Hint
Approximately 20% of the total energy remains: E_clean ≈ 0.2 × 100 = 20. By Parseval, zeroing 80% of frequency-domain energy removes 80% of time-domain energy. (This is approximate — the 80% energy assumption depends on how energy is distributed across bins.)

Spectral Leakage & Window Functions

In practice, you rarely have exactly an integer number of signal cycles in your analysis window. When the signal frequency falls between DFT bins, energy "leaks" from the true frequency into neighboring bins — producing a smeared spectrum. Window functions reduce this leakage by smoothly tapering the signal at the edges of the analysis window.

After this section you will be able to
  • Explain what spectral leakage is, why it occurs, and what the "rectangular window" has to do with it.
  • Compare at least three window functions (rectangular, Hann, Hamming) on the trade-off between main-lobe width and side-lobe suppression.
  • Apply a Hann window in Python before computing the DFT and explain the improvement to the magnitude spectrum.

You have a 3.7 Hz tone and you record exactly 1 second at 16 Hz — giving 16 samples. But the DFT has bins only at integer Hz: 3 Hz, 4 Hz. The 3.7 Hz tone doesn't land on any bin. So where does its energy go? It smears across all bins, polluting the spectrum with spurious "ghost" peaks. This is spectral leakage, and it is the single most common artifact beginners encounter when working with real signals.

🎯
Why this matters: Spectral leakage can make a weak frequency component invisible beside a nearby strong one (masking), or create the illusion of frequency components that don't exist. Every production audio analyzer, scientific instrument, and radio receiver uses windowing to control leakage. Without it, your DFT output would be unreliable.
🔗
Think of it this way

Abruptly cropping an audio recording is like slamming a door shut mid-sentence. The sharp cut introduces a click that spreads energy across all frequencies — just like the rectangular window introduces spectral leakage. A window function is like politely fading the recording in and out: the smooth edges eliminate the click and keep the spectrum clean.

No Window (Rectangular)
Abrupt signal cutoff at block edges — causes sharp discontinuities
Leaky Spectrum
Energy spreads to neighboring bins — smeared, misleading spectrum
Hann Window Applied
Smooth taper to zero at edges — signal appears to fade in and out
Clean Spectrum
Energy concentrated near true frequency — side lobes suppressed
BEFORE WINDOWING Leakage sidebands spread energy Apply Hann window AFTER WINDOWING Side lobes suppressed ≥ 30 dB Window Function Comparison Window Main Lobe Side Lobe Use when Rectangular Narrowest −13 dB (high) Exactly integer cycles Hann 2× wider −31 dB (good) General purpose Blackman 3× wider −57 dB (best) Dynamic range critical

Before/after windowing: applying a Hann window eliminates spectral leakage sidebands and concentrates energy near the true frequency bin. The table shows the main-lobe/side-lobe trade-off for common windows.

Problem

Why Leakage Happens

The DFT implicitly assumes the $N$-sample window is one period of an infinitely repeating signal. When the signal frequency doesn't align with a bin, the "stitched" signal has a discontinuity at the block boundary:

The Rectangular Window Problem

Multiplying the signal by the implicit rectangular window $w[n] = 1$ for all $n$ is equivalent to abruptly cutting the signal at both ends. In the frequency domain, the DFT of a rectangular window has high sidelobes (the "Gibbs phenomenon"), and these sidelobes add energy to every bin, creating spectral leakage.

Condition for zero leakage: The signal frequency must fall exactly on a DFT bin: $f = k \cdot f_s / N$ for some integer $k$. In practice this rarely holds for real-world signals.

📝 Worked Example — Identifying Leakage Conditions

Problem: You record $N = 16$ samples at $f_s = 16$ Hz. Which signal frequencies produce zero leakage?

1
Find bin frequencies.
$f_k = k \cdot f_s/N = k \cdot 16/16 = k$ Hz for $k = 0, 1, \ldots, 7$.
2
Zero-leakage frequencies: 0, 1, 2, 3, 4, 5, 6, 7 Hz.
Any other frequency (e.g., 3.7 Hz, 5.5 Hz) produces leakage.
Zero leakage: f ∈ {0,1,2,3,4,5,6,7} Hz. All others leak.
Quick Check

You want to analyze a 440 Hz tone with zero leakage using $f_s = 8000$ Hz. What value of $N$ would guarantee this? (Hint: $N$ must be a multiple of $f_s / f$.) Is this practical?

Hint
N must be a multiple of fₛ/f = 8000/440 ≈ 18.18. The smallest exact integer is N = 8000/440 × some integer → 440 Hz only lands on a bin when N is a multiple of 8000/440 = 200/11 — which is not an integer. It is impossible to achieve zero leakage for 440 Hz with fₛ=8000 Hz. This is why windowing is always needed in practice.

Window Functions: The Fix

Multiply $x[n]$ by a window $w[n]$ that tapers smoothly to zero at both ends before computing the DFT:

Common Window Functions

Rectangular (default, implicit): $w[n] = 1$ — no tapering, maximum leakage

Hann window: $w[n] = 0.5\left(1 - \cos\!\left(\tfrac{2\pi n}{N-1}\right)\right)$

Hamming window: $w[n] = 0.54 - 0.46\cos\!\left(\tfrac{2\pi n}{N-1}\right)$

Blackman window: more complex; best side-lobe suppression (−57 dB)

Trade-off: Wider windows suppress leakage better but widen the main lobe (reducing frequency resolution). Choose the window based on whether resolution or dynamic range matters more for your task.

📝 Worked Example — Computing Hann Window Values for N=8

Problem: Compute the Hann window $w[n]$ for $N=8$ at $n=0,1,2,3,4$.

1
Formula: $w[n] = 0.5(1 - \cos(2\pi n/(N-1))) = 0.5(1 - \cos(2\pi n/7))$
2
$n=0$: $0.5(1-\cos 0) = 0.5(1-1) = 0$
$n=1$: $0.5(1-\cos(2\pi/7)) \approx 0.5(1-0.6235) = 0.188$
$n=2$: $0.5(1-\cos(4\pi/7)) \approx 0.5(1-(-0.2225)) = 0.611$
$n=3$: $0.5(1-\cos(6\pi/7)) \approx 0.5(1-(-0.9009)) = 0.950$
$n=4$: $0.5(1-\cos(8\pi/7)) \approx 0.950$ (symmetric)
w = [0, 0.188, 0.611, 0.950, 0.950, 0.611, 0.188, 0]. Tapers from 0 to peak and back to 0.
Quick Check

Why is $w[0] = 0$ for a Hann window? What does this mean for the first sample of the windowed signal?

Hint
$w[0] = 0.5(1 - \cos 0) = 0.5(1-1) = 0$. The first sample is multiplied by zero, so x[0]·w[0] = 0 regardless of x[0]. The Hann window forces the signal smoothly to zero at both ends, eliminating the abrupt boundary discontinuity that causes leakage.
⚠️
Common Mistake

Forgetting to compensate for window energy loss. Windowing reduces signal amplitude — the Hann window reduces total power by roughly 50%. After windowing, multiply the DFT magnitudes by $2/\text{sum}(w)$ to restore correct amplitude scale. NumPy's np.hanning(N) gives the window; divide by np.sum(w) for the compensation factor.

Solution
Pause & Predict

The widget below shows the same off-bin frequency with and without a Hann window. Before toggling, predict: will the windowed spectrum have a narrower peak or a wider peak than the unwindowed spectrum?

Prediction: wider peak (main lobe is broader) but cleaner — the side lobes disappear. Verify this trade-off with the widget.

Try It: Leakage & Window Comparison

Move the frequency slider to a non-integer value and watch leakage appear. Toggle the window to see it suppressed.

3.7
Windowed signal xw[n] Magnitude spectrum |X[k]| (dB)
Implementation
Python · NumPy/SciPy — Windowed DFT & Leakage Comparison
import numpy as np import matplotlib.pyplot as plt fs = 64; N = 64 n = np.arange(N) f0 = 5.7 # off-bin frequency → causes leakage x = np.cos(2*np.pi*f0*n/fs) # Apply different windows w_rect = np.ones(N) w_hann = np.hanning(N) w_hamming = np.hamming(N) def spectrum_dB(x, w): xw = x * w X = np.fft.fft(xw)[:N//2] mag = np.abs(X) / np.sum(w) # normalise for window energy return 20 * np.log10(mag + 1e-10) dB_rect = spectrum_dB(x, w_rect) dB_hann = spectrum_dB(x, w_hann) freqs = np.fft.fftfreq(N, 1/fs)[:N//2] plt.figure(figsize=(9, 4)) plt.plot(freqs, dB_rect, 'r-', label='Rectangular', alpha=0.75) plt.plot(freqs, dB_hann, 'b-', label='Hann', linewidth=2) plt.legend(); plt.xlabel('Hz'); plt.ylabel('dB') plt.title('Spectral Leakage: Rectangular vs Hann (5.7 Hz tone)') plt.show()
Output
Rectangular: peak at 5 Hz, strong sidelobes at all other bins (−13 dB worst case) Hann: peak broader (spans 5–6 Hz bins), sidelobes suppressed to < −31 dB Hann reduces worst-case sidelobe by ~18 dB compared to rectangular window.
Key Takeaway

Spectral leakage is caused by the implicit rectangular window whenever the signal frequency doesn't land on a DFT bin; applying a smooth window (Hann, Hamming, Blackman) suppresses this leakage at the cost of slightly reduced frequency resolution.

📻
Real-World Application

Spectrum Analyzers & Radio Frequency Monitoring

Every spectrum analyzer — from a $100 USB dongle to a $100,000 lab instrument — applies windowing before computing each DFT block. In radio frequency monitoring, a weak signal at 100.1 MHz might be completely buried under the sidelobes of a strong adjacent station at 100.0 MHz if a rectangular window is used. A Blackman window with −57 dB sidelobe suppression keeps the weak signal visible. The choice of window directly determines whether a frequency-hopping transmitter can be detected — a critical factor in spectrum management, electronic warfare, and interference diagnosis.

Checkpoint Spectral Leakage & Window Functions

Q1 You analyze a 440 Hz signal with $f_s = 8000$ Hz and $N = 512$. Does this signal fall exactly on a DFT bin, or does it cause spectral leakage? Show your calculation.

Hint
Δf = 8000/512 ≈ 15.625 Hz/bin. Bin for 440 Hz: k = 440/15.625 = 28.16 — not an integer. The 440 Hz tone does NOT fall on a bin → spectral leakage occurs. To avoid leakage you would need N = 8000/gcd(8000,440) = 8000/40 = 200 — but that gives only 100 unique bins, which may be too few.

Q2 Write the Hann window formula and explain what value $w[0]$ takes and why this matters.

Hint
$w[n] = 0.5(1-\cos(2\pi n/(N-1)))$. At n=0: w[0] = 0.5(1−cos(0)) = 0. The first sample is multiplied by zero, forcing the windowed signal to start at 0. This eliminates the abrupt discontinuity at the block boundary that would otherwise smear energy across all frequency bins (spectral leakage).

Q3 The Hann window is said to have a "wider main lobe" than the rectangular window. Is this a bug or a feature? Explain the trade-off.

Hint
It is a feature — an intentional trade-off. A wider main lobe reduces frequency resolution (two nearby frequencies are harder to separate) but dramatically suppresses sidelobes (leakage energy from bins far away). For most practical signals this is the right trade-off: the slight resolution loss is acceptable, while the leakage suppression (~18 dB improvement) prevents weak nearby signals from being masked by strong ones.

DFT Explorer: Time, Frequency & Windowing

Build a composite signal from two frequency components, apply a window function, compute the DFT in real time, and observe the magnitude spectrum, phase spectrum, and Parseval energy balance — all in one dashboard.

5
1.0
10
0.5
64
Time Domain x[n]
Magnitude Spectrum |X[k]| dB
Phase Spectrum ∠X[k]
Parseval Stats Energy Balance
Loading…
Dashboard Summary

Every parameter you adjust — frequencies, amplitudes, window size, and window type — has a direct visible consequence in the magnitude spectrum, phase spectrum, and Parseval energy balance, making all five DFT concepts from this week tangible and interactive.

What You Must Remember

The DFT converts N time-domain samples into N complex frequency coefficients — each encoding the amplitude and phase of one frequency in the signal.

🔁

DFT ↔ IDFT are Perfect Inverses

$X[k] = \sum x[n]e^{-j2\pi kn/N}$ (DFT) and $x[n] = \frac{1}{N}\sum X[k]e^{+j2\pi kn/N}$ (IDFT). The only differences are the sign of the exponent and the $1/N$ factor. Zero information is lost.

📐

Bin Frequency Formula

Bin $k$ represents frequency $f_k = k \cdot f_s / N$ Hz. Always use this formula — never assume bin index equals Hz. Frequency resolution $\Delta f = f_s/N$ improves (shrinks) as $N$ increases.

⚖️

Parseval's Theorem

$\sum|x[n]|^2 = \frac{1}{N}\sum|X[k]|^2$. Time-domain energy equals frequency-domain energy. Modifying bins changes the reconstructed signal's energy by exactly the amount you removed — no surprises.

🪟

Windowing Suppresses Leakage

Whenever the signal frequency falls between DFT bins, spectral leakage occurs. Multiply by a Hann or Hamming window before the DFT to suppress sidelobes — at the cost of slightly wider main-lobe width (reduced frequency resolution).

Coming up — Week 5

Fast Fourier Transform (FFT)

The naive DFT you implemented this week runs in $O(N^2)$ — unusable for $N = 16{,}384$. The FFT reduces this to $O(N\log N)$ by exploiting the periodicity and symmetry of the twiddle factors $W_N^{kn}$. You will implement the radix-2 Cooley-Tukey butterfly, see why $N = 2^p$ is preferred, and use numpy.fft.fft() as a production-grade FFT.

Go Deeper

Curated resources to strengthen your DFT intuition — from interactive visualisations to the textbook chapter that every DSP engineer has bookmarked.

Week 4 Exercises

12 exercises across theory and code — two per topic plus two synthesis tasks. Work through them in order; each builds on the concepts from the matching section.

1 Theory · Topic 1 Easy

Frequency Resolution & Bin Mapping

You record a signal at $f_s = 44100$ Hz using $N = 2048$ samples. (a) Compute the frequency resolution $\Delta f$. (b) Which DFT bin contains a 1 kHz tone? (c) How many unique (non-redundant) bins does this real-signal DFT produce?

Hint
Use $\Delta f = f_s/N$ for (a). For (b): $k = f/\Delta f$. For (c): unique bins = $N/2 + 1$ for a real signal.
2 Code · Topic 1 Easy

Plot a Magnitude Spectrum

Generate a signal $x[n] = \cos(2\pi \cdot 3 \cdot n/f_s) + 0.5\cos(2\pi \cdot 7 \cdot n/f_s)$ with $f_s = 16$ Hz and $N = 32$ samples. Compute and plot the one-sided magnitude spectrum using np.fft.fft and np.fft.fftfreq. Label the two frequency peaks.

Hint
Use freqs = np.fft.fftfreq(N, 1/fs) for the frequency axis. Plot only the first N//2 bins (one-sided). Use np.abs(X) for magnitudes.
3 Theory · Topic 2 Medium

DFT by Hand for N=4

Compute the full DFT $X[k]$ for $k = 0, 1, 2, 3$ of the signal $x = [0, 1, 0, -1]$ with $N = 4$ using the definition $X[k] = \sum_{n=0}^{3} x[n]\, e^{-j\pi kn/2}$. Express each $X[k]$ in the form $a + jb$. What physical signal does this $x[n]$ represent?

Hint
The probe values for each k are the four 4th roots of unity: {1, −j, −1, +j} for k=1 etc. $x=[0,1,0,−1]$ is a pure sine wave — predict that energy appears only at k=1 and k=3 with imaginary-only coefficients.
4 Code · Topic 2 Medium

Implement DFT from Scratch

Write a Python function dft(x) that implements the DFT definition using two nested for loops (no NumPy FFT). Test it on $x = [1, 0, -1, 0]$ and verify against np.fft.fft(x) using np.allclose. Then measure the runtime for $N = 256$ using time.perf_counter and compare to np.fft.fft.

Hint
Initialize X = np.zeros(N, dtype=complex). The inner loop multiplies x[n] * np.exp(-1j * 2 * np.pi * k * n / N). Expect the naive DFT to be ~100–1000× slower than NumPy's FFT for N=256.
5 Theory · Topic 3 Medium

Conjugate Symmetry & One-Sided Spectrum

A real signal has $N = 8$ samples and DFT $X = [8, 3-2j, 0, 1+j, 0, 1-j, 0, 3+2j]$. (a) Verify the conjugate symmetry property $X[N-k] = X^*[k]$ for $k = 1$ and $k = 3$. (b) How many unique bins are there? (c) What is $|X[1]|$ and $|X[7]|$? Are they equal?

Hint
$X^*[k]$ means flip the sign of the imaginary part. Check: $X[N-1]=X[7]$ should equal $X^*[1]$. Unique bins for N=8 real signal: N/2+1 = 5 (bins 0,1,2,3,4).
6 Code · Topic 3 Medium

Visualise Conjugate Symmetry

Generate a random real signal $x = \text{np.random.randn}(32)$. Compute $X = \text{np.fft.fft}(x)$. Plot $|X[k]|$ for all $k = 0$ to $31$ and add a vertical dashed line at $k = N/2$. Numerically verify that $|X[k]| = |X[N-k]|$ for all $k$. Print the maximum difference.

Hint
Use np.max(np.abs(np.abs(X[1:N//2]) - np.abs(X[N//2+1:][::-1]))) to compare the two halves. This should be near machine epsilon (~1e-14).
7 Theory · Topic 4 Medium

IDFT by Hand & Parseval Check

Given $X = [4, 0, 0, 0]$ (a scaled impulse in the frequency domain) with $N = 4$, compute $x[0], x[1], x[2], x[3]$ using the IDFT formula. Then verify Parseval's Theorem: compute $\sum|x[n]|^2$ and $\frac{1}{N}\sum|X[k]|^2$ and confirm they are equal.

Hint
IDFT with only $X[0]=4$ non-zero: $x[n] = \frac{1}{4}\cdot 4 \cdot e^{+j\cdot 0} = 1$ for all n. So $x = [1,1,1,1]$. Time energy = 4, Freq energy = (1/4)×16 = 4. ✓
8 Code · Topic 4 Medium

Frequency-Domain Denoising with Parseval Check

Generate $x[n] = \sin(2\pi \cdot 5 \cdot n/64) + \text{noise}$ with $N=64$, $f_s=64$, and Gaussian noise of std = 0.4. Apply DFT, zero out all bins where $|X[k]| < 5$, apply IDFT to reconstruct. Report: (a) number of bins zeroed, (b) fraction of energy removed (using Parseval), (c) plot original vs. reconstructed signal.

Hint
Use X_clean = X.copy(); X_clean[np.abs(X_clean) < 5] = 0 for zeroing. Energy before: sum(|X|²)/N. Energy after: sum(|X_clean|²)/N. The difference is the noise energy removed.
9 Theory · Topic 5 Medium

Leakage Conditions & Window Formulas

You want to analyze a 250 Hz tone using $f_s = 8000$ Hz and $N = 512$. (a) Does this frequency fall exactly on a DFT bin? Show the calculation. (b) Write the Hann window formula and compute $w[0]$, $w[128]$, and $w[511]$ for $N = 512$. (c) What is the worst-case sidelobe level (in dB) for the rectangular window and the Hann window?

Hint
Δf = 8000/512 ≈ 15.625 Hz. k = 250/15.625 = 16 exactly — no leakage! Hann: w[n] = 0.5(1−cos(2πn/511)). w[0]=0, w[128] ≈ 0.75, w[511]=0. Rectangular worst sidelobe: −13 dB; Hann: −31 dB.
10 Code · Topic 5 Hard

Window Comparison: Leakage vs. Resolution

Generate $x[n] = \cos(2\pi \cdot 5.3 \cdot n/64)$ with $N=64$, $f_s=64$. Compute and plot (on the same axes) the dB magnitude spectrum using (a) rectangular window, (b) Hann window, (c) Blackman window (np.blackman(N)). For each, report the peak bin and the magnitude at bin $k = 3$ (a bin far from the true frequency — pure leakage).

Hint
Normalize each windowed spectrum by np.sum(w) before taking dB. Plot in dB: 20*np.log10(mag + 1e-10). The Blackman window should give the cleanest spectrum (most leakage suppression) but the broadest main lobe.
11 Synthesis Hard

Music Note Detector

Record (or synthesize) a 0.5-second chord of A4 (440 Hz) + C5 (523 Hz) + E5 (659 Hz) at $f_s = 22050$ Hz. (a) Apply a Hann window and compute the DFT. (b) Identify the three dominant frequency bins and convert them to Hz. (c) Verify that the detected frequencies match A4, C5, E5 within $\pm 5$ Hz. (d) What is the minimum $N$ needed to resolve 440 Hz and 523 Hz as two separate peaks (resolution must be $< 83$ Hz)?

Hint
For (d): Δf < 83 Hz → N > fₛ/83 = 22050/83 ≈ 265.7 → minimum N = 266. In practice use N = 512 (next power of 2). For (a)-(c): generate the signal as a sum of three cosines, apply np.hanning(N), compute FFT, find the 3 peaks using np.argsort(|X|)[-3:].
12 Synthesis Hard

Signal Reconstruction & Energy Budget

Generate a noisy signal: $x = \sin(2\pi\cdot 3\cdot n/32) + \sin(2\pi\cdot 7\cdot n/32) + 0.3\cdot\text{randn}(N)$ with $N=32$, $f_s=32$. (a) Compute the DFT. (b) Build $X_{\text{clean}}$ by keeping only the 4 highest-magnitude bins (set all others to 0). (c) Reconstruct via IDFT and plot original vs. reconstructed. (d) Compute the Signal-to-Noise Ratio improvement: $\text{SNR} = 10\log_{10}(E_{\text{signal}}/E_{\text{noise removed}})$. (e) Verify Parseval's Theorem before and after denoising.

Hint
For (b): use idx = np.argsort(np.abs(X))[-4:] to find top 4 bins. For (d): E_noise_removed = (sum(|X|²) − sum(|X_clean|²))/N. SNR is in dB. For (e): check that time-energy and freq-energy/N are equal for both the noisy and clean signals.