1. 程式人生 > >音訊噪聲抑制(4):普通最小均方誤差(LMS)演算法

音訊噪聲抑制(4):普通最小均方誤差(LMS)演算法

引言

前面講了基於Weiner濾波器的噪聲抑制方法。

維納濾波器有一些假設條件,比如訊號平穩(這就導致解方程算濾波器係數的時候,自相關矩陣與絕對時間無關)、噪聲和有用訊號不相關…

其實,這些條件在實際中並不是那麼容易滿足的。

因此,用維納濾波器來實現訊號去噪,效果不是特別理想。

於是就有人提出自適應濾波器,“自動”去更新濾波器的係數,使它自己去“適應”訊號的一些特性。

自適應濾波器有許多種,這裡挑最簡單的基於“最小均方誤差”準則的自適應濾波器來講了。

LMS濾波器基本原理

原理的話,每一本現代訊號處理的書上都講得很清楚了。歸根結底:這是一個需要“訓練”(或者說“學習”)的濾波器,在“學習”的過程中,希望把濾波器的輸出與期望訊號(訓練訊號)之差,作為演算法的反饋,不斷地更新濾波器的係數,以使得在某種意義下,實現最優濾波。LMS,顧名思義,最小均方誤差。另外,利用梯度下降法,可以簡單地求出目標函式(均方誤差是關於濾波器係數w)的極值。一系列簡單推導,可得出LMS演算法。

w是濾波器係數,x是濾波器輸入,d是訓練訊號,x和w的內積(濾波器與輸入訊號的卷積)是濾波器的輸出,u是步長(1個正數)。理論上,u越小,最終求出的極值點結果越精確,但所需要達到極值點的時間就變長了。有最優的一個u,但其實吧,我感覺也就是理論上提供一種可能性,意思是,u在每一次迭代的過程中,在理論上都有個最優值。但實際上,為了求最優值,又需要一大堆的已知條件,而這些條件其實並不是那麼好“知道”;就算是知道了,求最優的u,也會耗費大量的時間。所以,自己看著辦了……有資料建議,
濾波器階數,初值,自己設定了。有可能陷入區域性極值。這不知道了。試,效果出來就OK了。Tail & error。

舉例:噪聲抑制


1. LMS的訓練過程。
%% LMS濾波去噪
% 作者:qcy
% 版本號:v1.0
% 版本說明:本M檔案提供訓練階段。
% 時間:2016年10月29日19:02:44

% 好像提升並不是很明顯啊!!
% why...?????? and 如何改進???
%【問】 是不是不應該用非語音段進行濾波???

close all;clear; clc; 

%% 匯入音訊
filedir=[];                             % 設定路徑
filename='bluesky1.wav';                % 設定檔名
fle=[filedir filename];                 % 構成完整的路徑和檔名
[s, fs] = audioread(fle);               % 讀入資料檔案

s=s-mean(s);                            % 消除直流分量
s=s/max(abs(s));                        % 幅值歸一
N=length(s);                            % 語音長度
time=(0:N-1)/fs;                        % 設定時間刻度
SNR = 5;                                % 設定信噪比
r2=randn(size(s));                      % 產生隨機噪聲
b=fir1(32,0.5);                         % 設計FIR濾波器,代替H
r21=filter(b,1,r2);                     % FIR濾波
[r1,r22]=add_noisedata(s,r21,fs,fs,SNR);% 產生帶噪語音,信噪比為SNR 

%% 訓練階段
h_length = 100;
h = zeros(h_length,1); % 濾波器的初始化
miu = 1e-4;

y_out = zeros(size(s));
Ntimes = 3;
err2 = zeros(length(s)*Ntimes,1);
counter = 1;
% 開始濾波
for kk = 1:Ntimes
    for k = h_length : N
        idx = k: -1 :(k-h_length+1);
        r1_in_sub = r1(idx);
        filter_out = h.' * r1_in_sub;
        y_out(k) = filter_out;
        dk = s(k);
        err = dk - filter_out;
        err2(counter) = err^2;
        h = h + miu * err * r1_in_sub;
        counter = counter + 1;
    end
end


% sound(s,fs);
% sound(r1,fs);
% sound(y_out,fs);

%% 作圖
figure
plot(err2);
grid on;
title('均方誤差');

figure;
subplot 311; plot(time,s,'k'); ylabel('幅值') 
ylim([-1 1 ]); title('原始語音訊號');
subplot 312; plot(time,r1,'k'); ylabel('幅值') 
ylim([-1 1 ]); title('帶噪語音訊號');
subplot 313; plot(time,y_out,'k'); 
ylim([-1 1 ]); title('LMS濾波輸出語音訊號');
xlabel('時間/s'); ylabel('幅值')
儘管聽起來,似乎有一定的改良,但是去噪效果還是不明顯!我暫時不知道為什麼。而且,很多書上都回避了普通LMS來去噪的例子。連去噪前後訊號波形圖都沒有給出。更不要說什麼均方誤差了。我在想,是不是在訓練的過程中,整個語音訊號中,說話不能有停頓啊?從我的均方誤差的圖中,似乎看得出來,似乎有一個逐漸變小的過程,但是突然又會變大。假設,期望訊號中,有非常微弱的部分(說話間隙),基本就是0了。這時濾波器為了讓均方誤差最小,是不是係數要全為0啊?那這樣的訓練過程……是不是最終導致去噪效果不佳的原因?

所以,是不是還需要做一個端點檢測,把真正的語音段全部提取出來,以此作為訓練訊號呢?