最近在作數據平滑相關的工做,正好讀到該篇博客,感受不錯,就翻譯了一下。原連接:An Introduction to Signal Smoothingmarkdown
噪聲無處不在,不論是在採集手機遊戲的加速度數據仍是在測量房間的溫度,都會引入偏差。即便咱們有能力消除全部的偏差,測量的結果依舊包含必定程度的不肯定性。假如玩家隨意點擊了一下手機屏幕,他們到底想點擊哪裏是不肯定的。全部這些問題都強迫咱們從新思考數據的採集和預處理。函數
濾波器是尋找產生觀測數據最可能信號的數學工具。它能夠對滲透進傳感器的噪聲和不肯定性進行消除。當前的各類設備,如觸屏、遊戲手柄、手機和遊戲控制器等都是經過傳感器採集用戶的輸入,因此這些設備都不可避免地會引入噪聲。因此濾波器在用戶體驗上扮演着很是重要的角色。
本博客會介紹關於平滑濾波器的基本知識。將這些知識應用到遊戲中會極大提高遊戲體驗。工具
用一個簡單例子來解釋噪聲是如何幹擾信號的。假設一個傳感器每隔固定時間採樣一下數據,在時刻i產生觀測值
Input.GetAxis("Vertical")
。若是你是一個電子工程師,這個傳感器多是電位計,用來測量電壓: analogRead(3)
。這些時間序列都有一個共同點:都被噪聲干擾。下圖展現了一個被噪聲污染的信號:
在這個例子中,噪聲被人工添加到原始信號中。針對原始信號的每個點
ui
是否能重構被噪聲污染的信號呢?答案是:看狀況。這依賴於噪聲的類型和幅度。減弱噪聲的最簡單方法被稱爲滑動平均。該方法基於這樣一個假設:獨立的噪聲不會改變信號的基本結構。若是假設成立,則求幾個連續點的平均值就能夠減弱噪聲。正如其名字所表示的,滑動平均就是求給定點和其鄰居的平均值做爲信號值。例如,咱們對三個點求平均值,則過濾以後的信號爲:
atom
public float [] MovingAverage (float [] data, int size)
{
float [] filter = new float [data.length];
for (int i = points/2; i < data.length-points/2; i++)
{
float mean = 0;
for (var j = -points/2; j < points/2; j++)
mean += data[i + j];
filter[i] = mean / size;
}
return filter;
}
增長窗長能夠進一步減弱噪聲的影響,但同時也會使原始信號過分平滑。滑動平均特別適合於連續和平穩的信號。若是信號變化較爲劇烈,滑動平都可能會使原始信號的變化大於噪聲的消除(也即功不抵過)。
上圖中,雖然滑動平均減少了信號的變化程度,可是完美地重構了信號的線性部分。當咱們在處理包含可加性噪聲的線性信號時,滑動平均是最好的選擇。固然,上面的例子也過於理想化,在實際中很難出現。spa
上面介紹的滑動平均有個限制:窗口長度N必須爲奇數。這樣計算的平均值就知足對稱性。假如窗口長度N=2k爲偶數,此時咱們有兩種平滑方法(假定k=2):
翻譯
滑動平均中每一個點的權重是相同的,一個更加合理的選擇是對靠近
code
for (var j = -points/2; j < points/2; j++)
mean += data[i + j] * weights[j+points/2];
回過頭來重看中心化的滑動平均,咱們就能夠說2×4MA其實就是權重爲1/8,1/4,1/4,1/4,1/8的加權滑動平均。
加權的方法難以想象得有效,可是引入了更多的參數。若是你對泛函分析很瞭解,可能很容易將上面的操做聯想到卷積操做符上。經過仔細地挑選權重能夠帶來不少有趣的性質,例如實現邊緣檢測或者高斯模糊等。
舉一個邊緣檢測的例子,咱們對一個方波執行墨西哥帽小波的卷積操做,須要作的就是將權重設置爲下述函數上的點:
遊戲
float[] kernel = new float[10];
for (int i = 0; i <= kernel.length; t ++)
{
float t = i +4;
kernel[i] = (1-(t*t)) * Math.exp(-(t*t)/2);
}
上述卷積函數能夠用來進行邊緣檢測。若是你是一個遊戲開發者,上述方法能夠用來檢測玩家的忽然移動,這一般是運動檢測的第一步。
ip
本博客介紹了信號中的噪聲問題以及兩種解決方法。須要記住一點,沒有一種方法是完美的,每一個方法都有其優缺點,咱們須要知道它們的適用範圍。