Nanfeng

Notes on software development, code, and curious ideas

Speech Denoising with a Flat-Top-Window FIR Filter in MATLAB

Abstract

This course project designs a finite impulse response filter with the window method and applies it to a speech recording contaminated by a single sinusoidal tone. Time-domain waveforms and spectra before and after filtering are compared to evaluate noise suppression and speech distortion.

The original project used MATLAB 7.0; the workflow below uses current function forms while preserving the experiment.

Load and inspect the signal

1
2
3
4
5
6
7
8
9
10
11
12
[speech, fs] = audioread("speech.wav");
speech = mean(speech, 2); % mono
t = (0:numel(speech)-1)' / fs;

toneFrequency = 7000;
noisy = speech + 0.08 * sin(2*pi*toneFrequency*t);

nfft = 2^nextpow2(numel(noisy));
f = (0:nfft/2)' * fs / nfft;
spectrum = abs(fft(noisy, nfft));
plot(f, spectrum(1:nfft/2+1));
xlabel("Frequency (Hz)");

The added tone must be below the Nyquist frequency and outside the speech band that the selected low-pass filter is intended to preserve.

Design the FIR filter

1
2
3
4
5
6
7
order = 160;
cutoffHz = 4000;
window = flattopwin(order + 1);
b = fir1(order, cutoffHz/(fs/2), "low", window);

freqz(b, 1, 2048, fs);
filtered = filter(b, 1, noisy);

An order-N linear-phase FIR filter introduces approximately N/2 samples of group delay. Compensate for it when aligning plots or listening comparisons. A flat-top window is valued for amplitude accuracy in spectral measurement, but it has a wide main lobe; compare it with Hamming, Blackman, or a specification-driven design rather than assuming it is optimal for every denoising task.

Evaluate the result

Plot the noisy and filtered spectra using identical axes, listen at a safe normalized level, and measure passband distortion and attenuation at the tone frequency. Do not claim general speech denoising from this experiment: a fixed low-pass filter removes a known out-of-band tone, while broadband or in-band noise requires different methods.

Save output with audiowrite, keeping samples within [-1, 1] to avoid clipping.

+