03 · Signal Processing Basics¶
Verification note
MATLAB was not available in the environment used to write this page.
Signal Processing Toolbox behavior (fft, filter, designfilt) is
hand-traced against documented MATLAB semantics and cross-checked
against NumPy/SciPy equivalents where feasible, rather than run in
MATLAB itself.
A signal is just a vector of samples taken over time. Everything in this module — analyzing frequency content, removing noise, designing filters — is standard MATLAB numeric work applied to that one idea, using functions that have been production-stable for decades.
Sampling and the sample rate¶
A continuous physical signal becomes a MATLAB vector by sampling it at a
fixed rate Fs (samples/second, Hz). The vector alone has no notion of
time — you must track Fs alongside it to interpret the data correctly:
Fs = 1000; % 1000 samples per second
t = (0:1/Fs:1-1/Fs)'; % 1 second of time stamps
f0 = 50; % a 50 Hz tone
x = sin(2*pi*f0*t) + 0.5*randn(size(t)); % signal + noise
The Nyquist theorem: a sampling rate Fs can only faithfully
represent frequencies up to Fs/2 (the Nyquist frequency). Sample a
120 Hz tone at Fs = 100 and it does not simply disappear — it
aliases, reappearing disguised as a lower, wrong frequency
(|120 - 100| = 20 Hz). This is why every signal-processing pipeline
starts by confirming Fs is at least twice the highest frequency of
interest.
Frequency-domain view: the FFT¶
fft converts a time-domain vector into its frequency-domain
representation — how much of the signal's energy sits at each frequency:
N = length(x);
X = fft(x);
f = (0:N-1)*(Fs/N); % frequency axis, 0 to Fs
mag = abs(X)/N; % magnitude, normalized by length
% Single-sided spectrum: real signals are symmetric about Fs/2,
% so the informative half is 1:N/2+1
halfN = floor(N/2)+1;
f_half = f(1:halfN);
mag_half = mag(1:halfN);
mag_half(2:end-1) = 2*mag_half(2:end-1); % account for folded energy
plot(f_half, mag_half);
xlabel('Frequency (Hz)'); ylabel('Magnitude');
For the x built above, mag_half shows a clear peak near f = 50 (the
injected tone) sitting above a noise floor spread across all
frequencies — exactly what random Gaussian noise plus one sinusoid looks
like in the frequency domain. abs() discards phase and keeps magnitude;
angle(X) recovers phase when it matters (e.g., aligning signals).
fftshift re-centers the spectrum around 0 Hz instead of running 0→Fs,
convenient when a signal has meaningful negative-frequency content
(complex-valued signals, common in communications work) rather than the
real-valued case above.
Filtering: keeping or removing frequency bands¶
A filter passes some frequencies and attenuates others. MATLAB's
designfilt builds a filter from a frequency-domain specification
without hand-deriving coefficients:
d = designfilt('lowpassiir', ...
'FilterOrder', 8, ...
'HalfPowerFrequency', 100, ... % Hz, the -3dB cutoff
'SampleRate', Fs);
y = filter(d, x); % apply the filter to the signal
'lowpassiir' keeps frequencies below the cutoff and attenuates above;
'highpassiir', 'bandpassiir', 'bandstopiir' cover the other common
shapes. filtfilt(d, x) applies the same filter forward and backward,
canceling the phase distortion a single-pass filter introduces —
preferred whenever a shifted-in-time output would corrupt downstream
analysis (e.g., detecting exact event timing) and only unsuitable for
real-time/streaming use, where the whole signal isn't available yet to
run backward over.
FIR vs. IIR, briefly¶
FIR ('lowpassfir') |
IIR ('lowpassiir') |
|
|---|---|---|
| Impulse response | Finite length | Theoretically infinite (feedback) |
| Phase | Can be made exactly linear | Generally nonlinear |
| Cost for a given sharpness | Higher order needed | Lower order suffices |
| Stability | Always stable | Can be unstable if poles land outside the unit circle |
IIR filters are cheaper (lower order for the same cutoff sharpness) but distort phase and carry a stability condition; FIR filters cost more compute for equivalent sharpness but are always stable and can preserve linear phase — the right choice depends on whether phase fidelity or computational cost dominates for the application.
Moving average: the simplest filter of all¶
Before reaching for designfilt, a moving average is often enough to
smooth noisy data and is trivial to reason about:
This is literally filter with FIR coefficients [1/5 1/5 1/5 1/5 1/5]
and denominator 1 — every output sample is the average of the current
and previous four input samples. It attenuates high-frequency noise (a
crude low-pass filter) at the cost of a slight delay and softened edges,
which is why designfilt exists for anything needing a controlled,
specified cutoff rather than "whatever a 5-point average happens to do."
movmean, movmedian, smoothdata — the convenience layer¶
For quick smoothing without building a formal filter object:
ySmooth = movmean(x, 5); % same idea as the manual filter above
yDenoise = movmedian(x, 5); % robust to spike outliers, mean isn't
ySmooth2 = smoothdata(x, 'gaussian', 11); % weighted, smoother rolloff
movmedian matters specifically because a single large spike (a sensor
glitch) drags a moving average window's output toward the spike for its
whole width, while a moving median ignores an isolated outlier
entirely — the same mean-vs-median robustness trade-off from basic
statistics, applied along a sliding window.
Spectrogram: frequency content that changes over time¶
fft describes one snapshot's overall frequency content; a signal whose
frequency content changes over time (a chirp, speech, a machine spinning
up) needs spectrogram, which computes the FFT over many short
overlapping windows and shows a frequency-vs-time image:
The three numeric arguments after x are the window length, overlap, and
FFT length — a common choice is roughly 75–80% overlap, trading time
resolution against frequency resolution the same way choosing a coarser
or finer FFT window always does.
How It Actually Works¶
The Fast Fourier Transform (fft) computes the same result as the naive
Discrete Fourier Transform (a dense matrix-vector multiply against the
DFT matrix, costing O(n^2)) but via the Cooley-Tukey divide-and-conquer
algorithm, which recursively splits the transform into even- and
odd-indexed subsequences, bringing the cost down to O(n log n) — this is
why fft is dramatically faster for large n, and specifically why
MATLAB's FFT implementation is fastest when n is a power of 2 (or at
least highly composite): the recursive splitting factors n into its
prime factors, and a prime (or near-prime) length forces the algorithm
back toward O(n^2)-like behavior for that portion of the transform,
which is the real mechanical reason zero-padding a signal to the next
power of 2 before an fft call is a genuine, not superstitious,
performance practice.
The frequency-bin spacing after an n-point FFT sampled at rate Fs is
Fs/n Hz per bin, a direct consequence of the DFT's definition (it probes
frequencies at integer multiples of the fundamental Fs/n) — this is why
increasing FFT length gives you finer frequency resolution, not more
signal information, and why interpreting bin index k as frequency k *
Fs/n (accounting for the Nyquist fold at n/2) is required to read fft
output correctly. Filtering (filter, conv) is literally the same
discrete convolution operation defined mathematically as a sliding
weighted sum — MATLAB's filter implements a difference-equation
recursion (efficient O(n) per output sample for FIR/IIR filters)
rather than an explicit O(n*m) convolution sum, which is why long FIR
filters are sometimes implemented via FFT-based "fast convolution"
instead, trading the O(n*m) direct convolution cost for O(n log n).
Note: cross-checked against the documented Cooley-Tukey FFT algorithm and
DFT theory (and consistent with NumPy's equivalent fft/convolve
routines); not executed in MATLAB itself.
Summary¶
- A signal is a sampled vector plus its sample rate
Fs; Nyquist (Fs ≥ 2×highest frequency`) is the first thing to check before trusting any analysis. fftmoves a signal into the frequency domain;abs(fft(x))gives magnitude, and only the first half (1:N/2+1) of a real signal's spectrum is independent information.designfilt+filter/filtfiltbuild and apply low/high/band-pass filters from a frequency spec;filtfiltremoves phase distortion at the cost of needing the whole signal up front.- FIR filters cost more per unit of sharpness but are always stable and can have exactly linear phase; IIR filters are cheaper but can be unstable and generally distort phase.
movmean/movmedian/smoothdatacover quick smoothing without a formal filter design;movmedianspecifically resists outlier spikes that would drag a moving average off course.spectrogramextendsfftto signals whose frequency content changes over time.