为什么维纳滤波器不是最优的?

信息处理 过滤器 Python lms 维纳滤波器
2022-02-21 23:54:11

我正在研究频域中的维纳滤波器,由 $$ W(\omega) = \frac{S_{ud}(\omega)}{S_{uu}(\omega)}$$ where $S_{xy} (\omega)$是交叉功率谱密度 (CPSD),请参见scipy.signal.csdMATLAB cpsd我使用 Pythonscipy.signal.csd来估计$S_{xy}$

这里$d[n]$是所需信号(“mic”),$u[n]$(“ref”)是参考信号。

现在,在这里我描述了如何生成信号(在 Python 中)。我生成了一个 10 秒的白噪声,还生成了一个 FIR 传递函数true_h(有两种生成方法:一种是设计 FIR 带通滤波器并使用它,第二种是从真实房间实验中测量的)。

from scipy import signal

# Generate filter
true_L = 150 # filter size for simulation
true_h = signal.firwin(true_L, cutoff=[1000, 3000], pass_zero="bandpass", fs=FS)
fft_h = np.fft.rfft(true_h)

# Generate 10 seconds of white noise
np.random.seed(0)
ref = np.random.randn(10*FS)/100
mic = signal.lfilter(true_h, 1, ref)

目标是估计$w = \mathcal{F}^{-1}(W)$其中$W$是估计的 Wiener 滤波器频率,$\mathcal{F}^{-1}$是逆离散傅里叶变换。

频域中的维纳计算如下:

from scipy import signal
# ref = reference signal
# mic = desired signal
freqs, Pxy = signal.csd(ref, mic, fs=FS, nperseg=nfft)
freqs, Pxx = signal.csd(ref, ref, fs=FS, nperseg=nfft)
   
wiener = Pxy / Pxx

估计滤波器$w$的应用如下:

# Inverse FFT for Wiener filter
wiener_taps = np.fft.irfft(wiener)

# Apply Wiener
error_wiener = mic - signal.lfilter(wiener_taps, 1, ref)

期望的结果是$e[n] = d[n] - w[n] \ast u[n]$几乎是$0$但这种情况并非如此。我得到的残差只有 -10 到 -20 dB 左右。

当我使用频率/快速块 LMS(FBLMS 或 FLMS)时,我得到一个残差$e[n]$,它约为 -40 dB,即 的估计true_h值几乎是完美的。

我还绘制了与真实传递函数(在抽头和频域中)相比的 Wiener 和 FLMS 估计值,true_h并获得了非常好的匹配,但 FLMS 中的匹配比 Wiener 中的更好)。

这很奇怪,因为 Wiener 被认为是 MSE(均方误差)意义上的最佳滤波器。但在这个例子中,Wiener 的表现比 FLMS 差。请参阅以下结果:

结果:

图 1:回波回波损耗增强 (ERLE)

图 1:回波回波损耗增强 (ERLE)。黑色 = 原始,绿色 = Wiener 之后,蓝色 = LMS 之后。

图 4:残差 (e = d - w * u)。 绿色:维纳滤波器,红色:FLMS 滤波器。 蓝色:自适应 FLMS(与此问题无关)。

图 2:残差 (e = d - w * u)。绿色:维纳滤波器,红色:FLMS 滤波器。蓝色:自适应 FLMS(与此问题无关)。

编辑时添加: 在这里我进一步研究维纳。我生成了一个 150 抽头的 FIR,并将其应用于白噪声信号(由正态分布生成):

# Generate filter
true_L = 150 # filter size for simulation
true_h = signal.firwin(true_L, cutoff=[1000, 3000], pass_zero="bandpass", fs=FS)
# Generate 10 seconds of white noise
np.random.seed(0)
ref = np.random.randn(10*FS)/100
mic = signal.lfilter(true_h, 1, ref)

然后通过以下方式计算维纳:

  1. scipy 的默认 CSD 参数。
f1, Pxy = signal.csd(ref, mic, fs=FS)
f1, Pxx = signal.csd(ref, ref, fs=FS)
wiener_freq = Pxy/Pxx

图 3:维纳 图 3:维纳后的错位和残差(默认框架)

  1. 对整个信号(一个“帧”)进行一次长 FFT:
f1, Pxy = signal.csd(ref, mic, fs=FS, nperseg=len(ref))
f1, Pxx = signal.csd(ref, ref, fs=FS, nperseg=len(ref))
wiener_freq = Pxy/Pxx

图 4: 图 4:维纳后的错位和残差(一个大框架)

正如我们所见,第二种方法产生了更好的结果,但仍然不是一个完美的 0 残差(即残差 < -100 dB)。

在编辑中添加: 当信号是合成的时,似乎就是这种情况:即参考是由 生成的白噪声,numpy.random.randn而传递函数是由scipy.signal.firwin大约 50-250 个抽头生成的。对于真实数据,维纳似乎表现更好。

在另一个编辑中添加: 图 5 图 5:合成白噪声信号和 FIR 传递函数的 Wiener(橙色)与 FBLMS(绿色)。

图 6 图 6:Wiener(橙色)与 FBLMS(绿色)的真实信号(使用音频设备录制)

可以看出,对于合成情况,FBLMS 优于 Wiener,而对于真实情况,反之亦然,Wiener 更好,FBLMS 收敛于 Wiener。

参考:

1个回答

维纳滤波器在一系列假设下最小化 MSE,这些假设通常与现实不符。这意味着,在实践中,它不会给出具有最小 MSE 的解决方案。

使用 Wiener 滤波器进行反卷积是您可以做的最简单的事情,还有许多其他更复杂的反卷积算法可以产生更好的结果。