Lab 3.2 — FIR Low-Pass Filtering of IQ Data¶
Lab 3.2 — FIR Low-Pass Filtering of IQ Data¶
Goal¶
Design, apply and evaluate a low-pass FIR filter for complex IQ data.
The lab connects filtering theory with practical SDR processing and prepares the student for a future streaming FIR block in Verilog.
Theory¶
A low-pass FIR filter is commonly used to isolate a baseband signal, suppress adjacent channels, reduce noise bandwidth or prepare a signal for decimation.
Important concepts:
- passband;
- stopband;
- transition bandwidth;
- filter order / number of taps;
- group delay;
- windowed-sinc design;
- convolution;
- complex IQ filtering;
- fixed-point coefficient quantization.
Experiment¶
Generate or load complex IQ data with:
- desired low-frequency component;
- undesired high-frequency component;
- optional additive noise.
Then:
- design a low-pass FIR filter;
- plot filter impulse response;
- plot filter frequency response;
- filter the IQ data;
- compare spectra before and after filtering;
- measure basic signal quality improvement.
Python implementation¶
Minimum expected script structure:
import numpy as np
import matplotlib.pyplot as plt
fs = 2.4e6
n = 32768
t = np.arange(n) / fs
wanted = np.exp(1j * 2*np.pi*120e3*t)
interferer = 0.35 * np.exp(1j * 2*np.pi*620e3*t)
noise = 0.03 * (np.random.randn(n) + 1j*np.random.randn(n))
x = wanted + interferer + noise
num_taps = 129
cutoff = 250e3
m = np.arange(num_taps) - (num_taps - 1) / 2
h = 2 * cutoff / fs * np.sinc(2 * cutoff / fs * m)
h *= np.blackman(num_taps)
h /= np.sum(h)
y = np.convolve(x, h, mode="same")
freq = np.fft.fftshift(np.fft.fftfreq(n, d=1/fs))
X = np.fft.fftshift(np.fft.fft(x))
Y = np.fft.fftshift(np.fft.fft(y))
plt.figure()
plt.plot(freq/1e3, 20*np.log10(np.maximum(np.abs(X), 1e-12)), label="before")
plt.plot(freq/1e3, 20*np.log10(np.maximum(np.abs(Y), 1e-12)), label="after")
plt.grid(True)
plt.xlabel("Frequency, kHz")
plt.ylabel("Magnitude, dB")
plt.legend()
plt.show()
MATLAB implementation¶
Minimum expected script structure:
fs = 2.4e6;
N = 32768;
t = (0:N-1).' / fs;
wanted = exp(1j*2*pi*120e3*t);
interferer = 0.35 * exp(1j*2*pi*620e3*t);
noise = 0.03 * (randn(N,1) + 1j*randn(N,1));
x = wanted + interferer + noise;
numTaps = 129;
cutoff = 250e3;
m = (0:numTaps-1).' - (numTaps-1)/2;
h = 2*cutoff/fs * sinc(2*cutoff/fs * m);
h = h .* blackman(numTaps);
h = h ./ sum(h);
y = conv(x, h, 'same');
freq = fftshift((-floor(N/2):ceil(N/2)-1).' * fs / N);
X = fftshift(fft(x));
Y = fftshift(fft(y));
figure; hold on;
plot(freq/1e3, 20*log10(max(abs(X), 1e-12)), 'DisplayName', 'before');
plot(freq/1e3, 20*log10(max(abs(Y), 1e-12)), 'DisplayName', 'after');
grid on;
xlabel('Frequency, kHz');
ylabel('Magnitude, dB');
legend('Location', 'best');
C++ bridge¶
The same FIR operation should later be implemented as a deterministic C++ primitive:
std::vector<std::complex<float>> fir_filter(
const std::vector<std::complex<float>>& x,
const std::vector<float>& taps);
Minimum C++ validation:
- impulse response test;
- sine/tone attenuation test;
- MATLAB/Python vector comparison;
- coefficient normalization check;
- group delay check.
FPGA / Verilog bridge¶
The FIR filter maps naturally to a streaming RTL block:
clk, rst
in_valid, in_i, in_q
out_valid, out_i, out_q
Hardware questions:
- How many taps are required?
- How many multipliers are available?
- Is the FIR fully parallel or time-multiplexed?
- What is the coefficient word length?
- What is the accumulator width?
- What latency is acceptable?
Expected plots¶
Produce at least:
- FIR impulse response;
- FIR magnitude response;
- spectrum before filtering;
- spectrum after filtering;
- optional time-domain comparison.
Report checklist¶
- [ ] State
Fs, cutoff frequency and number of taps. - [ ] Plot and explain FIR frequency response.
- [ ] Estimate transition bandwidth.
- [ ] Explain group delay.
- [ ] Compare spectrum before/after filtering.
- [ ] Estimate suppression of the interferer.
- [ ] Explain what changes in fixed-point implementation.
- [ ] Describe how this FIR would map to Verilog.
Engineering conclusion template¶
The FIR low-pass filter suppresses the unwanted component by approximately ____ dB.
The cost is ____ samples of group delay and ____ taps, which directly affects
FPGA multiplier count, accumulator width and latency.