The Wiener filter cleans a noisy spectrogram, the short-time Fourier transform (STFT) of a clip, by multiplying each bin by a gain between 0 and 1. The gain makes the cleaned value as close as possible to the clean speech on average (the smallest mean squared error), and it comes out as the share of the bin’s power that is speech. That share is unknown and is guessed frame by frame.
Figure 1. The method in order, 1 to 6. Only 3 and 4 differ from spectral subtraction.
1 The gain from two PSDs
As in Spectral Subtraction for Denoising, each STFT frame and bin holds a noisy value, speech plus noise, and the noise power spectral density (PSD) PD, its power per hertz, is learned in the pauses. For example, a bin with speech power 3 and noise power 1 is three-quarters speech. The Wiener gain is that share, 0.75. It scales the bin’s amplitude by 0.75, so about 0.56 of its power is left.
What one noisy bin holds.
Y = S + D
Y is the noisy value in one frame and bin, S its speech part and D its noise part. Speech and noise are unrelated, so on average their powers add: the example bin holds power 3 + 1 = 4. Every gain on this page acts on Y.
The Wiener gain for one bin.
G = PSPS + PD
PS and PD are the speech and noise power in this bin, and G is the speech share of the power, between 0 and 1. G multiplies the bin’s amplitude, so the power left is G²: the example bin gets G = 34 and keeps 916 of its power. A bin that is mostly noise is turned down.
ξ = PSPD
ξ, the a priori SNR, is how much the speech outweighs the noise in this bin; the example has ξ = 3.
G = ξ1 + ξ
Divide top and bottom by PD. A large ξ gives G near 1 (keep the bin), a small ξ gives G near 0, and ξ = 1 (0 dB) gives G = 12. It builds on the PSD, and Sections 2 to 6 all use it.
Figure 2 also draws power subtraction, the rule of Spectral Subtraction for Denoising that takes the noise power off the noisy power.
0 dB
Figure 2. The noisy bin’s speech and noise, then what is left. 1Its Wiener gain.
G multiplies the amplitude, so the power left is G². Power subtraction keeps more at the same SNR. At ξ = 1 Wiener’s amplitude gain is 0.5 and power subtraction’s 0.707; at ξ = 10 they are 0.909 and 0.953.
Power subtraction’s share at the average noisy power.
1 − PD|Y|² ≈ξ1 + ξ = G
Power subtraction keeps the power share 1 − PD|Y|². It equals G exactly when |Y|² equals its average, (1 + ξ) PD, so its amplitude gain is √G, above Wiener’s G. It builds on the Wiener gain card and is used by the comparison in Section 4.
2 The gain across frequency
Each bin gets its own gain, so across frequency the gain follows the voice: high where a harmonic, one of the evenly spaced peaks of a voiced sound, stands above the noise, low in between.
Figure 3.1Speech PSD. 2Noise PSD, flat. 3The gain, high on harmonics, low between.
A Bayesian estimate per bin treats the speech value S, before Y is seen, as a Gaussian (a bell curve) centered on 0 with power PS, the prior, and the noise as another Gaussian with power PD. Once Y is seen, Bayes’ rule gives the posterior, the bell of values S could still have; the Gaussian conditioning example is on Probability and Bayes Rule.
Figure 4.1The prior. 2The posterior given Y; its center G·Y is the Wiener output.
The best guess in mean squared error.
Ŝ = E[ S | Y ]
A hat marks an estimate, so Ŝ is the guess of S. E[ · ] is an average (an expectation) and the bar reads “given” (not a magnitude here): the best guess in mean squared error is the average of S over the posterior.
E[ S | Y ] = G · Y
With Gaussian speech and noise that average is Y scaled by the same Wiener gain G, so it shrinks toward 0 more when the noise is relatively bigger. The prior pulls the guess toward 0 and the measurement pulls it toward Y. Each pull is weighted by the other one’s uncertainty. The measurement gets the weight PSPS + PD, which is G. A wide prior (large PS) knows little about S, so Y counts more. The prior gets the rest, 1 − G, because loud noise (large PD) makes Y less reliable. So the guess sits the share G of the way from 0 to Y. With speech 3 times the noise, G = 0.75 and the guess is close to Y. With speech a third of the noise, G = 0.25 and it is close to 0 (Figure 4). It builds on Bayes’ rule and is used by Section 4, where ξ has to be guessed.
So under the Gaussian assumption no other per-bin rule has a smaller mean squared error; Wang and Chen (2018) call the Wiener filter the optimal estimator of speech in the power spectrum.
4 Wiener next to subtraction
PS is unknown, so ξ has to be guessed, and the simplest guess uses this frame alone. It reads γ, this frame’s bin power over the noise estimate. On average γ is 1 + ξ, since the noise alone gives the 1, so γ − 1 is the guess, written ξ because the hat marks a guess. With it every rule becomes a curve in γ. Magnitude subtraction takes the noise amplitude, the square root of PD, off the noisy amplitude, so it turns bins down harder than power subtraction.
γ, the a posteriori SNR, is this frame’s bin power over the noise estimate.
ξ =max(γ − 1, 0)
The noisy power minus the noise, over the noise, never below zero.
G =1 − 1γ
Put into G = ξ1 + ξ, the guess gives this gain for γ ≥ 1. It is exactly the square of power subtraction’s gain, so the same noise bins survive, only dimmer, and the gain shape alone does not remove musical noise, the short random tones left by noise peaks, heard as twinkling. It builds on the gain of Section 1 and is used by the smoothed guess in Section 5.
5 Guessing the SNR, and smoothing it
The one-frame guess jumps with every noise spike. Ephraim and Malah (1984) steadied it by mixing in last frame’s cleaned output, the decision-directed estimate, written here in the form Chinaev and Haeb-Umbach (2016) give. For example, take a = 0.98, last frame’s cleaned power at 4 times the noise, and a noise spike of γ = 10 this frame, so this frame alone says 9. The table compares the two guesses.
Guess
Weight on last frame’s 4
Weight on this frame’s 9
ξ
One-frame
0
1
9
Decision-directed
0.98
0.02
4.1
Illustrative values, from the decision-directed card at a = 0.98.
The decision-directed SNR guess for frame m.
ξm = a · |Ŝm−1|²PD
The first term trusts last frame's cleaned power over the noise; m − 1 is the previous frame and a is a weight near 1 (0.98 in the decision-directed paper). Speech changes slowly from frame to frame, so that cleaned estimate is a steadier guide than one noisy frame.
+ (1 − a) · max(γm − 1, 0)
Add a little of this frame’s own evidence, never below zero; with a = 0.98 a lone noise spike adds only 2% of its γ − 1 for that frame. It is the one-pole smoother from How FIR and IIR Filters Shape Magnitude and Phase, run across frames.
Noise suppressors in phones and hearing aids face this trade-off on every call. A weight close to 1 removes the twinkling in the pauses, but it is slow to follow the start of each word (Nahma et al. 2019). In Figure 6 a word start lags while the guess sits more than 10 dB under the true SNR; red marks those frames.
0.98
Figure 6. Toy speech. 1Wiener output. 2SNR guess; dashed, the true SNR.
Figure 7. Pauses of Figure 6. 1Power subtraction. 2, 3Wiener.
6 Undoing a known filter
Sometimes noise is not the only damage. A lavalier microphone clipped under a shirt muffles the voice, and if that muffling was measured, the filter’s frequency response H is known.
The muffled, noisy recording.
y = s ∗ h + d
y is the recording, s the clean speech, h the muffling filter, ∗ convolution and d the noise.
Y = H · S + D
In each frequency bin convolution becomes a product, so the speech S is scaled by H and the noise D adds. Dividing by H would undo the filter, except where H is nearly 0. If the shirt keeps |H| = 0.01 at 8 kHz, dividing boosts that band 100 times, noise included. It builds on convolution and is used by the Wiener deconvolution gain card.
The Wiener deconvolution gain W divides by H only where the voice still stands above the noise; the card after Figure 8 writes it out. Four illustrative values of H show the trade-off, with ξ = 100 (20 dB) in every bin.
Band
|H|
Share of the voice restored
500 Hz
1
0.99
2 kHz
0.5
0.96
4 kHz
0.1
0.5
8 kHz
0.01
0.01
Illustrative values; the share is how much of the voice comes back.
Figure 8. Illustrative H, ξ = 20 dB. 1At 8 kHz, no 100 times boost. 2That band stays erased.
The Wiener deconvolution gain W for one bin.
W = H* PS|H|² PS + PD
H* is H with the sign of its phase flipped, which undoes the filter’s phase shift. PS and PD are the speech and noise PSDs of Section 1. W is complex, unlike the real gain G. The thesis writes the PSDs Px and Pv (Anushiravani 2016).
W = 1H ·ξ|H|²ξ|H|² + 1
The same gain with ξ = PSPD, the SNR of Section 1, top and bottom divided by PD: the plain inverse times a Wiener gain whose SNR is ξ|H|², the SNR left after the muffling. It is near 1 where ξ|H|² is well above 1 and near 0 below; at 8 kHz in the table ξ|H|² = 0.01. With H = 1 it is ξ1 + ξ again.
What comes out of one bin.
Ŝ = W · Y
Ŝ estimates the clean speech; its speech part is WHS, so kept bands come back and erased bands stay erased. Why a room cannot be undone this way is on the Reverberation and Dereverberation page.
20 dB
Figure 9.Gain against |H|, plain inverse dashed. 1It turns where the SNR left is 1.
Raising ξ lets the gain follow 1/|H| further down; lowering it makes the gain turn earlier. ξ has no default; it is measured per recording, from PS and PD.
This code undoes the measured muffling of the lavalier recording.
import numpy as np
# y: the lavalier recording; h: its measured muffling; xi: P_S / P_D per bin
n = len(y) + len(h) - 1
Y, H = np.fft.rfft(y, n), np.fft.rfft(h, n)
W = np.conj(H) / (np.abs(H) ** 2 + 1 / xi)
S_hat = W * Y
s_hat = np.fft.irfft(S_hat, n)[:len(y)]
1FFTs long enough that the filter does not wrap around, then the gain W, line 1 of the deconvolution gain card with top and bottom divided by PS.
2The estimate Ŝ = W · Y (the output card).
3The inverse FFT, trimmed to the recording’s length.
5Applies the gain and rebuilds the audio (marker 6 in Figure 1).
The decision-directed guess as a function that runs one frame at a time, with a = 0.98.
import numpy as np
def dd_wiener(Y, P_D, A=0.98, XI_MIN=1e-3):
S_hat = np.zeros_like(Y)
prev = np.zeros(Y.shape[0]) # last frame's cleaned power
for m in range(Y.shape[1]):
gamma = np.abs(Y[:, m]) ** 2 / P_D
xi = A * prev / P_D + (1 - A) * np.maximum(gamma - 1, 0)
xi = np.maximum(xi, XI_MIN)
G = xi / (1 + xi)
S_hat[:, m] = G * Y[:, m]
prev = np.abs(S_hat[:, m]) ** 2
return S_hat
1The smoothing weight a = 0.98 and the −30 dB floor.
2The output and last frame’s cleaned power, which starts at zero.
3One frame at a time, because each guess needs the frame before.
4γ for this frame.
5The decision-directed guess, both lines of the eq card in Section 5.
6The floor on ξ.
7The Wiener gain from the guess.
8Applies the gain and keeps this frame’s cleaned power for the next frame.
The dd_wiener function, run on the toy recording of the first code block.
# Y, P_D, HOP and y come from the first code block
S_hat = dd_wiener(Y, P_D[:, 0]) # one noise value per bin
s_hat = librosa.istft(S_hat, hop_length=HOP, length=len(y))
1The decision-directed guess from dd_wiener, with PD as one value per bin.
2Rebuilds the audio by inverse STFT.
Knob, where it enters
Raise it
Lower it
Default
Smoothing a, the weight on last frame in the decision-directed card
Steadier ξ and less musical noise, but onsets lag, so the first frames of a syllable come out quieter; a = 1 never updates
Weak speech in low-SNR bins is turned down with the noise
Accept it, or raise the floor on ξ
Modern denoisers train a network to predict a gain like this per bin, called a mask; the ideal ratio mask of supervised speech separation (References) is the speech share of the power, usually square-rooted; without the root, and with expected powers, it equals the Wiener gain. What does such a model read instead of the raw spectrum? MFCC and Other Audio Features.
9 References
Wiener, N. (1949). Extrapolation, Interpolation, and Smoothing of Stationary Time Series. MIT Press (where the filter comes from).
Ephraim, Y., and Malah, D. (1984). Speech Enhancement Using a Minimum Mean-Square Error Short-Time Spectral Amplitude Estimator. IEEE Transactions on Acoustics, Speech, and Signal Processing, 32(6), 1109 to 1121 (formula as summarized in Chinaev and Haeb-Umbach 2016).
Chinaev, A., and Haeb-Umbach, R. (2016). A Priori SNR Estimation Using a Generalized Decision Directed Approach. Interspeech 2016. PDF.
Loizou, P. C. (2013). Speech Enhancement: Theory and Practice, 2nd ed. CRC Press (its MATLAB code logmmse.m floors the SNR guess at −25 dB).
R. Anushiravani, “Example-based audio editing,” M.S. thesis, University of Illinois at Urbana-Champaign, 2016, section 5.3 (Wiener deconvolution, eqs 5.2 to 5.4). hdl.handle.net/2142/95331.
NumPy documentation for numpy.fft (opened 2026-11-05).
Nahma, L., Yong, P. C., Dam, H. H., and Nordholm, S. (2019). An Adaptive A Priori SNR Estimator for Perceptual Speech Enhancement. EURASIP Journal on Audio, Speech, and Music Processing, 2019:7 (noise suppression in mobile phones and hearing aids; the decision-directed weight close to 1 is slow at speech onsets). Springer.
Wang, D. L., and Chen, J. (2018). Supervised Speech Separation Based on Deep Learning: An Overview. IEEE/ACM Transactions on Audio, Speech, and Language Processing, 26(10), 1702 to 1726. PMC.