Discrete Signal Processing (DSP):
Discrete Fourier Transformation (DFT)
Table of Contents
Given a square matrix $A$, an eigenvector $v$ and corresponding eigenvalue $\lambda$ satisfy:
Extending to a full basis of eigenvectors, we can write:
where $V = [v_0 \mid v_1 \mid \cdots \mid v_{N-1}]$ is the matrix of eigenvectors, and $\Lambda$ is the diagonal matrix of eigenvalues:
This leads to the eigen-decomposition of the matrix:
This decomposition reveals how the matrix $A$ acts on a basis of its eigenvectors: it scales each one by a corresponding eigenvalue.
For signals of length $N$, a linear time-invariant (LTI) system is represented by a circulant matrix $H \in \mathbb{C}^{N \times N}$ whose entries are determined by the impulse response $h[n]$:
Our goal is to find the eigenvectors and eigenvalues of such matrices.
Harmonic Sinusoids as Eigenvectors
The eigenvectors of any circulant matrix (and hence any finite-length LTI system) are known to be the harmonic sinusoids:
To prove this, consider the circular convolution between $s_k[n]$ and $h[n]$:
Thus, $s_k[n]$ is an eigenvector of $H$, and its corresponding eigenvalue is:
This eigenvalue $\lambda \in \mathbb{C}$ is interpreted as the frequency response of the system at frequency index $k$, measuring how strongly the system responds to the complex exponential $s_k$.
We can stack the $N$ orthonormal eigenvectors $\{s_k[n]\}_{k=0}^{N-1}$ into a unitary matrix $S$:
Each column $s_k$ is defined by:
This matrix $S$ forms the discrete Fourier transform (DFT) basis, and diagonalizes any circulant matrix $H$:
This result is fundamental in signal processing, as it connects time-domain convolution with frequency-domain multiplication via the DFT.
The following example visualizes the complex matrix $S$ by separately illustrating its real and imaginary components.
%plot -s 800,500
% visualize S matrix
N = 16;
n = 0:N-1;
k = 0:N-1;
S = 1/sqrt(N)*exp(1j*2*pi/N).^(n'*k);
subplot(1,2,1), imagesc(n,k,real(S)); colormap('jet'); axis('square');
title('real part'), xlabel('k'), ylabel('n')
subplot(1,2,2), imagesc(n,k,imag(S)); colormap('jet'); axis('square');
title('imaginary part'), xlabel('k'), ylabel('n')
Signal decomposition refers to expressing a signal as a sum of fundamental components. To understand this idea, we return to linear algebra and explore vector spaces, basis vectors, and orthonormal transformations. Signal transforms, which map signals between different representations or "domains," are naturally described in terms of basis expansions.
A basis $\{b_k\}$ for a vector space $V$ is a set of vectors that satisfies:
We can organize the basis vectors as columns of a matrix:
Using this matrix, a signal can be represented compactly as:
where $\alpha = [\alpha_0 \; \alpha_1 \; \cdots \; \alpha_{N-1}]^T$ is the coefficient vector.
A set of vectors $\{b_k\}_{k=0}^{N-1}$ is an orthogonal basis for a vector space $V$ if the vectors are mutually orthogonal:
If, in addition, each vector has unit norm:
then $\{b_k\}$ is called an orthonormal basis.
In this case, the basis matrix $B = [b_0 \mid b_1 \mid \cdots \mid b_{N-1}]$ is unitary, meaning:
This orthonormality condition expands to:
This identity plays a central role in signal representation, enabling simple analysis and synthesis of signals using inner products and linear combinations.
Given an orthonormal basis matrix $B$, any signal $x \in \mathbb{C}^N$ can be represented as:
Synthesis: The signal $x$ is constructed as a linear combination of the basis vectors $b_k$ weighted by coefficients $\alpha_k$.
Analysis: The coefficients $\alpha_k$ are obtained by projecting the signal $x$ onto the basis vectors, capturing how much each basis vector contributes to the signal.
This decomposition is powerful:
Since $B$ is unitary ($B^H = B^{-1}$), the transformation between $x$ and $\alpha$ is perfectly invertible.
The complex exponential signals, or harmonic sinusoids, form an orthonormal basis for $\mathbb{C}^N$. Define the $k$-th basis vector as:
Stacking these vectors as columns gives the $N \times N$ matrix:
Then the matrix $S$ satisfies:
This shows that the set $\{s_k\}$ is an orthonormal basis.
These sinusoids are fundamental in signal processing and form the basis of the Discrete Fourier Transform (DFT), enabling analysis of signals in the frequency domain.
Jean Baptiste Joseph Fourier proposed a powerful idea: any signal can be represented as a linear combination of sinusoids.
Discrete Fourier Transform (DFT)
The DFT computes the frequency content of a signal by projecting it onto a basis of harmonic sinusoids:
In expanded form:
Inverse Discrete Fourier Transform (IDFT)
The IDFT reconstructs the time-domain signal from its frequency components:
In expanded form:
This synthesizes $x[n]$ as a linear combination of the harmonic sinusoids weighted by $X[k]$
Unnormalized DFT and IDFT
Some formulations avoid the $\frac{1}{\sqrt{N}}$ normalization by placing the factor entirely in one direction:
This convention is commonly used in numerical implementations (e.g., FFT algorithms)
The Discrete Fourier Transform (DFT) not only decomposes signals into frequency components, but also diagonalizes any linear time-invariant (LTI) system.
Let:
Then the eigendecomposition of $H$ is:
This expresses $H$ in the frequency domain as a diagonal matrix $\Lambda$, meaning the LTI system simply scales each frequency component independently.
Frequency Response as Eigenvalues
Each diagonal entry of $\Lambda$ corresponds to the system's response at a specific harmonic frequency:
This is the (unnormalized) DFT of the system's impulse response $h[n]$. These values represent the frequency response of the system.
Frequency-Domain Representation
The matrix $\Lambda$ is diagonal, where:
Summary
From right to left:
This composition maps the action of a linear time-invariant (LTI) system into the frequency domain, applies a diagonal scaling operation, and transforms the result back to the time domain. It highlights the efficiency and interpretability of the Fourier basis.
In more precise terms:
This is the essence of diagonalization: a potentially complex linear transformation becomes a simple element-wise multiplication in the frequency domain.
As a result of this decomposition, one avoids analyzing entangled time-domain interactions. Instead, the transformation reveals independent modes of behavior - one per frequency bin.
After applying the desired frequency-domain scaling (via the diagonal matrix $\Lambda$), the inverse DFT (via $S$) reconstructs the output signal in the time domain.
The overall structure is:
This relationship offers a powerful interpretation: convolution in the time domain corresponds to multiplication in the frequency domain, and the inverse DFT recovers the time-domain output. This insight simplifies both theoretical analysis and practical implementation of LTI systems.
%% DFT without using the built-in function
x = [1 -1 -1 0 0 0 1 -1];
N = length(x);
X = zeros(1,N);
for k = 0:N-1
for n = 0:N-1
X(k+1) = X(k+1) + x(n+1)*exp(-1j*2*pi/N*n*k);
end
end
X
%plot -s 560,600
% plot a discrete-time signal
xn = 0:N-1;
k = 0:N-1;
subplot(3,1,1),
stem(xn,x,'filled'), ylabel('x[n]')
subplot(3,1,2),
stem(k,real(X),'filled'), ylabel('Real of X[k]')
subplot(3,1,3),
stem(k,imag(X),'filled'), ylabel('Imaginary of X[k]')
%plot -s 560,400
% plot a discrete-time signal
subplot(2,1,1),
stem(xn,x,'filled'), ylabel('x[n]')
subplot(2,1,2),
stem(k,abs(X),'filled'), ylabel('|X[k]|')
Unnormalized DFT
function [Xk] = dft(xn,N)
% Computes Discrete Fourier Transform
% [Xk] = dft(xn,N)
% Xk = DFT coeff. array over 0 <= k <= N-1
% xn = N-point finite-duration sequence
% N = Length of DFT
%
n = [0:1:N-1]; % row vector for n
k = [0:1:N-1]; % row vecor for k
WN = exp(-1j*2*pi/N); % Wn factor
nk = n'*k; % creates a N by N matrix of nk values
WNnk = WN.^nk; % DFT matrix
Xk = xn*WNnk; % row vector for DFT coefficients
%plot -s 560,420
k = 3; % index for freqeuncy
N = 8;
n = 0:N-1; % sampling period
x = exp(1j*2*pi/N*k*n); % harmonic complex exponential
plot(real(x),imag(x),'o','MarkerFaceColor','b')
grid on
axis equal; axis([-1.5, 1.5,-1.4 1.4])
%plot -s 560,420
X = dft(x,N);
%X = fft(x,N);
subplot(2,1,1), stem(n,real(x),'filled'), axis tight
xlabel('n'), ylabel('x[n]')
title(['Re(e^{(j2\pi/N kn)}), k = ',num2str(k)])
subplot(2,1,2); stem(n,abs(X),'filled'), axis tight
xlabel('k')
ylabel('Amplitude of X[k]')
title('Result of FFT')
%plot -s 560,600
% Normalized DFT
k = 2; % index for freqeuncy
N = 8;
n = 0:N-1; % sampling period
x = exp(1j*2*pi/N*k*n); % harmonic complex exponential
X = dft(x,N)/N;
subplot(3,1,1), stem(n,real(x),'filled')
xlabel('n'), ylabel('Re\{x[n]\}')
title(['e^{(j2\pi/N kn)}, k = ',num2str(k)],'Fontsize',8)
subplot(3,1,2), stem(n,imag(x),'filled')
xlabel('n'), ylabel('Im\{x[n]\}')
title(['e^{(j2\pi/N kn)}, k = ',num2str(k)],'Fontsize',8)
subplot(3,1,3); stem(n,abs(X),'filled')
xlabel('k','Fontsize',8)
ylabel('Amplitude','Fontsize',8)
title('DFT','fontsize',8)
%plot -s 560,400
k = 1; % index for freqeuncy
N = 8;
n = 0:N-1; % sampling period
x = cos(2*pi/N*k*n); % harmonic complex exponential
X = dft(x,N)/N;
subplot(2,1,1), stem(n,real(x),'filled')
xlabel('n'), ylabel('x[n]'), xlim([0,8])
title(['sin{(2\pi/N kn)}, k = ',num2str(k)],'Fontsize',8)
subplot(2,1,2); stem(n,abs(X),'filled'), ylim([0,1]), xlim([0,8])
xlabel('k','Fontsize',8)
ylabel('Amplitude','Fontsize',8)
title('DFT','fontsize',8)
In the DFT, the frequency index $k$ maps to the discrete frequency variable $\omega_k = \frac{2\pi}{N}k$. Two common conventions are used for representing this frequency range:
Interval 1: Natural Ordering
This is the standard output ordering of most DFT implementations (e.g., fft
in MATLAB or NumPy). Frequencies progress from $0$ up to just below $2\pi$.
Interval 2: Centered (Symmetric) Ordering
This representation centers the zero frequency and is often used for analysis and visualization. It is typically achieved by applying a frequency shift using fftshift
.
Note:
The transformation from natural to centered ordering is purely a re-indexing of the same frequency content, but it provides a symmetric view of positive and negative frequencies around $\omega = 0$.
n = 0:N-1;
k = 0:N-1;
kr = [0:N/2-1 -N/2:-1];
ks = fftshift(kr);
X = fft(x,N)/N;
Xs = fftshift(X);
subplot(2,1,1); stem(n,abs(X),'filled'), ylim([0,1]), xlim([0,8])
xlabel('k','Fontsize',8)
ylabel('Amplitude','Fontsize',8)
title('DFT','fontsize',8)
subplot(2,1,2); stem(ks,abs(Xs),'filled'), ylim([0,1]), xlim([-4,4])
xlabel('k','Fontsize',8)
ylabel('Amplitude','Fontsize',8)
title('Shifted DFT','fontsize',8)
The Discrete Fourier Transform (DFT) and its inverse are defined as:
This defines the DFT pair:
DFT Frequencies
Common Frequency Intervals
Two common conventions are used to interpret the frequency axis of $X[k]$:
This is the default output order of the DFT (e.g., in MATLAB’s fft
).
This form centers the frequency axis around zero and is used for visualization, typically using fftshift
.
%plot -s 560,600
%% DFT (FFT) example
N = 16;
h = zeros(1,N);
h(1:8) = 1;
n = 0:N-1;
k = 0:N-1;
X = fft(h,N)/N;
Xs = fftshift(X);
kr = [0:N/2-1 -N/2:-1];
ks = fftshift(kr);
subplot(3,1,1),
stem(n,h,'filled'), xlabel('n'), ylabel('x[n]')
subplot(3,1,2),
stem(k,abs(X),'filled'), xlabel('k'), ylabel('abs(X[k])')
subplot(3,1,3),
stem(ks,abs(Xs),'filled'), xlabel('k'), ylabel('abs(X[k])'), xlim([-N/2,N/2-1])
DFT and Circular Shift
Let $x[n]$ be a length-$N$ signal, and consider a circular shift of $x[n]$ by $m$ samples:
This means:
In other words, a circular shift in the time domain corresponds to a linear phase shift in the frequency domain, with no change in spectral content.
%plot -s 800,600
%% DFT and circular shift
N = 16;
h = zeros(1,N);
h(1) = 1;
h2 = cirshftt(h,1,N);
n = 0:N-1;
k = 0:N-1;
kr = [0:N/2-1 -N/2:-1];
ks = fftshift(kr);
X = fft(h,N);
Xs = fftshift(X);
X2 = fft(h2,N);
X2s = fftshift(X2);
subplot(3,2,1),
stem(n,h,'filled'), xlabel('n'), ylabel('x[n]')
subplot(3,2,3),
stem(ks,abs(Xs),'filled'), xlabel('k'), ylabel('abs(X[k])'), xlim([-N/2,N/2-1])
subplot(3,2,5),
stem(ks,phase(Xs),'filled'), xlabel('k'), ylabel('phase(X[k])'), ylim([-5,5])
xlim([-N/2,N/2-1]), ylim([-5,5])
subplot(3,2,2),
stem(n,h2,'filled'), xlabel('n'), ylabel('x[n]')
subplot(3,2,4),
stem(ks,abs(X2s),'filled'), xlabel('k'), ylabel('abs(X[k])'), xlim([-N/2,N/2-1])
subplot(3,2,6),
stem(ks,phase(X2s),'filled'), xlabel('k'), ylabel('phase(X[k])'), xlim([-N/2,N/2-1]), ylim([-5,5])
DFT and Modulation
Let $x[n]$ be a length-$N$ signal. Multiplying $x[n]$ by a complex exponential of frequency $\omega_r = \frac{2\pi}{N}r$ results in a frequency shift in the DFT domain:
This means:
This duality mirrors the time-shift property:
%plot -s 800,400
%% DFT and modulation
N = 16;
h = zeros(1,N);
h(1:8) = 1;
h2 = zeros(1,N);
for i = 1:N
h2(i) = (-1)^i*h(i);
end
n = 0:N-1;
k = 0:N-1;
kr = [0:N/2-1 -N/2:-1];
ks = fftshift(kr);
X = fft(h,N);
Xs = fftshift(X);
X2 = fft(h2,N);
X2s = fftshift(X2);
subplot(2,2,1),
stem(n,h,'filled'), xlabel('n'), ylabel('x[n]')
subplot(2,2,3),
stem(ks,abs(Xs),'filled'), xlabel('k'), ylabel('abs(X[k])'), xlim([-N/2,N/2-1])
subplot(2,2,2),
stem(n,h2,'filled'), xlabel('n'), ylabel('x[n]')
subplot(2,2,4),
stem(ks,abs(X2s),'filled'), xlabel('k'), ylabel('abs(X[k])'), xlim([-N/2,N/2-1])
DFT and Circular Convolution
Key property:
Circular convolution in the time domain corresponds to multiplication in the frequency domain.
Proof (Unnormalized DFT):
Let $y[n] = (h \otimes x)[n] = \sum_{m=0}^{N-1} h[(n - m)_N] x[m]$. Then the DFT is:
Thus, the unnormalized DFT of the circular convolution is the pointwise product of the unnormalized DFTs:
A fundamental application of the DFT is to implement filtering by manipulating the signal in the frequency domain.
Let $x[n]$ be the input signal, $h[n]$ the impulse response of the system, and $y[n]$ the output signal. Then:
This circular convolution corresponds to multiplication in the frequency domain:
Compactly:
The following examples show how filtering operations can be efficiently implemented through element-wise multiplication in the frequency domain.
Frequency-Domain Interpretation of Filtering
Consider a simple filter with impulse response:
This filter performs a moving averaging operation over three consecutive samples. It acts as a low-pass filter, meaning it allows low-frequency components of a signal to pass through while attenuating high-frequency components.
%plot -s 560,400
%% low-pass filter
N = 16;
h = zeros(1,N);
h(1:3) = 1;
n = 0:N-1;
kr = [0:N/2-1 -N/2:-1];
ks = fftshift(kr);
X = fft(h,N)/N;
Xs = fftshift(X);
subplot(2,1,1),
stem(n,h,'filled'), xlabel('n'), ylabel('x[n]')
subplot(2,1,2),
stem(ks,abs(Xs),'filled'), xlabel('k'), ylabel('abs(X[k])'), xlim([-N/2,N/2]), ylim([0,0.5])
In the frequency domain, the DFT of $h[n]$ is concentrated around the low-frequency region. When we multiply $H[k]$ with the spectrum of the input signal $X[k]$, the high-frequency components of $X[k]$ are suppressed, while the low-frequency components are preserved.
As a result, the output signal $y[n]$, obtained by taking the inverse DFT of $Y[k] = H[k] \cdot X[k]$, is a smoothed version of the original input $x[n]$.
%plot -s 560,400
%% high-pass filter
N = 16;
h = zeros(1,N);
h(1) = 1;
h(2) = -1;
n = 0:N-1;
kr = [0:N/2-1 -N/2:-1];
ks = fftshift(kr);
X = fft(h,N)/N;
Xs = fftshift(X);
subplot(2,1,1),
stem(n,h,'filled'), xlabel('n'), ylabel('x[n]')
subplot(2,1,2),
stem(ks,abs(Xs),'filled'), xlabel('k'), ylabel('abs(X[k])'), xlim([-N/2,N/2]), ylim([0,0.5])
%plot -s 560,400
%% band-pass filter
N = 16;
h = zeros(1,N);
h(1) = 1;
h(2) = 0;
h(3) = -1;
n = 0:N-1;
kr = [0:N/2-1 -N/2:-1];
ks = fftshift(kr);
X = dft(h,N)/N;
Xs = fftshift(X);
subplot(2,1,1),
stem(n,h,'filled'), xlabel('n'), ylabel('x[n]')
subplot(2,1,2),
stem(ks,abs(Xs),'filled'), xlabel('k'), ylabel('abs(X[k])'), xlim([-N/2,N/2-1]), ylim([0,0.5])
%plot -s 560,800
N = 50;
n = 0:N-1;
s = sin(pi/N*n) .* [ones(1,N/2), -ones(1,N/2)];
subplot(4,1,1)
stem(s,'b','Marker','none','LineWidth',2);
axis([1 N -1.5 1.5])
title('piecewise smooth signal','fontsize',8)
% add noise to the signal
x = s + 0.1*randn(1,N);
subplot(4,1,2)
stem(x,'b','Marker','none','LineWidth',2);
axis([1 N -1.5 1.5])
title('piecewise smooth signal + noise','fontsize',8)
% construct moving average filter impulse response of length M
M = 5;
h = ones(1,M)/M;
subplot(4,1,3)
stem(h,'b','Marker','none','LineWidth',2);
axis([1 N 0 1])
title('impulse response','fontsize',8)
% convolve noisy signal with impulse response
y = cconv(x,h,N);
subplot(4,1,4)
stem(y,'b','Marker','none','LineWidth',2);
axis([1 N -1.5 1.5])
title('output','fontsize',8)
%plot -s 800,400
k = n;
H = fft(h,N);
X = fft(x,N);
Y = H.*X;
yi = ifft(Y);
subplot(2,1,1)
stem(n,y,'b','Marker','none','LineWidth',2);
subplot(2,1,2)
stem(n,yi,'b','marker','none','LineWidth',2)
%%javascript
$.getScript('https://kmahelona.github.io/ipython_notebook_goodies/ipython_notebook_toc.js')