最近時間在研究濾波算法,目的是為了更好的識別音頻數(shù)據(jù)轩拨。因?yàn)橛行┮纛l數(shù)據(jù)里面的雜波太多,很難識別院喜,所以需要先對其進(jìn)行過濾亡蓉,才能解析識別。為此喷舀,我先在matlab上做了仿真.采用的很多濾波算法砍濒,最后選擇了對我這個效果最好的,滑動均值濾波硫麻。
什么是滑動均值濾波
滑動平均濾波就是把連續(xù)取得的N個采樣值看成一個隊(duì)列爸邢,隊(duì)列的長度固定為N,每次采樣得到一個新數(shù)據(jù)放到隊(duì)尾拿愧,并丟掉原來隊(duì)首的一次數(shù)據(jù)杠河,把隊(duì)列中的N個數(shù)據(jù)進(jìn)行平均運(yùn)算,就可以獲得新的濾波結(jié)果
具體的matlab代碼
clear
clc
load boxinfo.mat %載入音頻數(shù)據(jù)
T = data;
figure(1)
plot(T,'-*')
title('原始數(shù)據(jù)')
hold on;
%%
%滑動平滑濾波
L = length(T);
N=10; % 窗口大下
k = 0;
m =0 ;
for i = 1:L
m = m+1;
if i+N-1 > L
break
else
for j = i:N+i-1
k = k+1;
W(k) = T(j) ;
end
T1(m) = mean(W);
k = 0;
end
end
plot(T1,'r-o')
grid
legend('原始數(shù)據(jù)','濾波之后')
濾波前后對比圖
簡單分析一下
經(jīng)過滑動濾波之后浇辜,波形整體變得平滑券敌,這里我們重點(diǎn)關(guān)注一下x軸附近的點(diǎn),可以發(fā)現(xiàn)奢赂,在波形與x軸交叉的地方陪白,波形都平穩(wěn)過度,這極大方便的我們后期進(jìn)行統(tǒng)計(jì)膳灶。
窗口大小選擇
從代碼中我們可以發(fā)現(xiàn)窗口大小我們選擇的是10咱士,如何選擇窗口大小立由,這里我們需要進(jìn)行一些簡單的分析和測試。如果x軸附近的噪點(diǎn)數(shù)量(一上一下)比較多序厉,那么窗口大小就應(yīng)該大一些锐膜,反之,小一些弛房。但是過大又會出現(xiàn)過擬合的現(xiàn)象道盏,所以可以多取幾個值,然后對比一下文捶,選擇一個最好的即可荷逞。
不同的窗口大小對比圖
簡單分析一下
從圖中我們可以很明顯的看出,當(dāng)N=4的時候粹排,濾波效果還不是很好种远,在x軸附近依然有噪點(diǎn)(一上一下),當(dāng)N=7的時候顽耳,已經(jīng)基本滿足我們的要求坠敷,圖形已經(jīng)可以很平穩(wěn)的過度了,但是從右邊的標(biāo)記處可以看出還是不是很平穩(wěn)射富,所以可以繼續(xù)提高N值膝迎,當(dāng)N=10的時候,波形就完全能夠達(dá)到我們的要求胰耗,所以取10即可限次。
滑動濾波的Java實(shí)現(xiàn)
/*
* 功能 對音頻數(shù)據(jù)進(jìn)行滑動濾波,使其更好的識別 時間:2015/9/11
*/
public class MovingAverageFilter implements IAudioSignalFilter {
private static final int WINDOWS = 1;
private short[] mTemp = null; // 只聲明暫時不初始化,用來記錄最后得不到均值處理的點(diǎn)
private short[] mBufout = null;
private int mWindowSize = WINDOWS;
public MovingAverageFilter(int size) {
mWindowSize = size;
}
// 均值濾波方法宪郊,輸入一個buf數(shù)組掂恕,返回一個buf1數(shù)組,兩者下表不一樣弛槐,所以定義不同的下表,buf的下表為i依啰,buf1的下表為buf1Sub.
// 同理乎串,臨時的winArray數(shù)組下表為winArraySub
public short[] movingAverageFilter(short[] buf) {
int bufoutSub = 0;
int winArraySub = 0;
short[] winArray = new short[mWindowSize];
if (mTemp == null) {
mBufout = new short[buf.length - mWindowSize + 1];
for (int i = 0; i < buf.length; i++) {
if ((i + mWindowSize) > buf.length) {
break;
} else {
for (int j = i; j < (mWindowSize + i); j++) {
winArray[winArraySub] = buf[j];
winArraySub = winArraySub + 1;
}
mBufout[bufoutSub] = mean(winArray);
bufoutSub = bufoutSub + 1;
winArraySub = 0;
}
}
mTemp = new short[mWindowSize - 1];
System.arraycopy(buf, buf.length - mWindowSize + 1, mTemp, 0,
mWindowSize - 1);
return mBufout;
} else {
short[] bufadd = new short[buf.length + mTemp.length];
mBufout = new short[bufadd.length - mWindowSize + 1];
System.arraycopy(mTemp, 0, bufadd, 0, mTemp.length);
System.arraycopy(buf, 0, bufadd, mTemp.length, buf.length); // 將temp和buf拼接到一塊
for (int i = 0; i < bufadd.length; i++) {
if ((i + mWindowSize) > bufadd.length)
break;
else {
for (int j = i; j < (mWindowSize + i); j++) {
winArray[winArraySub] = bufadd[j];
winArraySub = winArraySub + 1;
}
mBufout[bufoutSub] = mean(winArray);
bufoutSub = bufoutSub + 1;
winArraySub = 0;
System.arraycopy(bufadd, bufadd.length - mWindowSize + 1,
mTemp, 0, mWindowSize - 1);
}
}
return mBufout;
}
}
public short mean(short[] array) {
long sum = 0;
for (int i = 0; i < array.length; i++) {
sum += array[i];
}
return (short) (sum / array.length);
}
}