本文是對(duì)Kalman-and-Bayesian-Filters-in-Python書(shū)里內(nèi)容的概括總結(jié),原文請(qǐng)參考:
Kalman-and-Bayesian-Filters-in-Python
一. 數(shù)據(jù)的取值
我們現(xiàn)在有兩臺(tái)體重秤A和B,但體重秤每次的測(cè)量都是不準(zhǔn)確的,假設(shè)兩次測(cè)量的體重分別為160和170斤,我該怎么選取體重值呢?
- 相信第一次的值160
- 相信第二次的值170
- 選一個(gè)值比兩個(gè)值都大
- 選一個(gè)值比兩個(gè)都小
- 選一個(gè)值在兩者之間
前兩個(gè)選擇是可以的,但我們沒(méi)有理由偏向于一個(gè)。為什么我們選擇相信A而不是B?我們沒(méi)有理由相信這一點(diǎn)。第三和第四選擇是不合理的,體重秤當(dāng)然不是很準(zhǔn)確,但是根本沒(méi)有理由選擇超出兩者均測(cè)量范圍的數(shù)字。最后的選擇是唯一合理的選擇。如果兩個(gè)刻度都不正確,并且結(jié)果可能超過(guò)我的實(shí)際體重,也可能低于我的實(shí)際體重,那么答案通常是在A和B之間。
假設(shè)我們的兩臺(tái)體重秤有它各自的誤差范圍,A的誤差范圍是3,B的誤差范圍是9,如下圖所示:

我們的直覺(jué)告訴我們,選擇兩者重疊的部分是更合理的。兩臺(tái)傳感器,即使其中的一臺(tái)精確度不如另一臺(tái),兩臺(tái)也能提供更可靠的數(shù)據(jù)。我們不應(yīng)該丟棄任何數(shù)據(jù)?。?!
如果我只有一個(gè)體重秤,但可以多次稱重自己該怎么辦? 我們得出的結(jié)論是,如果我們有兩個(gè)精度相等的量表,則應(yīng)平均其測(cè)量結(jié)果。 如果我用一個(gè)秤稱量自己10,000次會(huì)怎樣? 我們會(huì)得到一個(gè)既不會(huì)太大也不會(huì)太小的數(shù)據(jù)。 不難證明大量權(quán)重的平均值將非常接近實(shí)際權(quán)重。就像下圖這樣:

我們?nèi)〉玫闹悼雌饋?lái)不錯(cuò),使用均值是合理的。
二. g-h模型
假設(shè)我們每隔一天使用這臺(tái)體重秤測(cè)試一次自己的體重,如果得到的數(shù)據(jù)是158.0, 164.2, 160.3, 159.9, 162.1, 164.6, 169.6, 167.4, 166.4, 171.0 。這些數(shù)據(jù)參差不齊,是測(cè)量的誤差嗎?但這些數(shù)字看起來(lái)又好像在增加,我們先采用平均值的方式,如下圖

使用平均值不合理,實(shí)際上我們不能畫(huà)一條水平線在所有測(cè)量的誤差內(nèi)。
現(xiàn)在我們假設(shè)體重一直在增加,通過(guò)工具,采用最小二乘法畫(huà)一條線,如圖:

這條線看起來(lái)好多了,覆蓋了所有測(cè)量,更合理。但事實(shí)一定是這樣嗎?我就不能一周增加13斤(最小值158,最大值171)?這可能嗎?
假設(shè)我們就認(rèn)為我每天增加1斤的體重(濾波器模型),第一次測(cè)量158,那么第二天我的體重就是159,讓我們看看體重秤的第二次讀數(shù)164.2。我們遇到了一個(gè)問(wèn)題,我們的預(yù)測(cè)和我們的測(cè)量不一致。 但是,這就是我們所期望的, 如果預(yù)測(cè)始終與測(cè)量完全相同,則它將無(wú)法向過(guò)濾器添加任何信息。 同樣,由于我們的預(yù)測(cè)是完美的,因此沒(méi)有理由進(jìn)行測(cè)量。我們需要將預(yù)測(cè)和測(cè)量以某種方式混合。
混合兩個(gè)值-聽(tīng)起來(lái)很像前面的兩個(gè)體重秤的問(wèn)題。我們不要丟棄任何信息,預(yù)測(cè)值和測(cè)量值都不能丟棄。使用與以前相同的推理,我們可以看到,唯一有意義的是在預(yù)測(cè)和測(cè)量之間選擇一個(gè)數(shù)字。估計(jì)值要介于測(cè)量和預(yù)測(cè)之間嗎?也許可以,總的來(lái)說(shuō),我們的預(yù)測(cè)值比測(cè)量值或多或少是準(zhǔn)確的(因?yàn)檎w趨勢(shì)上是上升的)。我們假設(shè)估計(jì)值是這樣取得的:
estimate = prediction + 4/10 x (measurement - prediction)
我們使預(yù)測(cè)模型的初始值為160,編碼如下:
from kf_book.book_plots import figsize
import matplotlib.pyplot as plt
weights = [158.0, 164.2, 160.3, 159.9, 162.1, 164.6,
169.6, 167.4, 166.4, 171.0, 171.2, 172.6]
time_step = 1.0 # day
scale_factor = 4.0/10
def predict_using_gain_guess(estimated_weight, gain_rate, do_print=False):
# storage for the filtered results
estimates, predictions = [estimated_weight], []
# most filter literature uses 'z' for measurements
for z in weights:
# predict new position
predicted_weight = estimated_weight + gain_rate * time_step
# update filter
estimated_weight = predicted_weight + scale_factor * (z - predicted_weight)
# save and log
estimates.append(estimated_weight)
predictions.append(predicted_weight)
if do_print:
gh.print_results(estimates, predicted_weight, estimated_weight)
return estimates, predictions
initial_estimate = 160.
estimates, predictions = predict_using_gain_guess(
estimated_weight=initial_estimate, gain_rate=1, do_print=True)
執(zhí)行輸出得到
previous estimate: 160.00, prediction: 161.00, estimate 159.80
previous estimate: 159.80, prediction: 160.80, estimate 162.16
previous estimate: 162.16, prediction: 163.16, estimate 162.02
previous estimate: 162.02, prediction: 163.02, estimate 161.77
previous estimate: 161.77, prediction: 162.77, estimate 162.50
previous estimate: 162.50, prediction: 163.50, estimate 163.94
previous estimate: 163.94, prediction: 164.94, estimate 166.80
previous estimate: 166.80, prediction: 167.80, estimate 167.64
previous estimate: 167.64, prediction: 168.64, estimate 167.75
previous estimate: 167.75, prediction: 168.75, estimate 169.65
previous estimate: 169.65, prediction: 170.65, estimate 170.87
previous estimate: 170.87, prediction: 171.87, estimate 172.16
每次用估計(jì)的值進(jìn)行預(yù)測(cè),然后將預(yù)測(cè)的值與測(cè)量值按比例混合,得到新的估計(jì)值,不斷的迭代。請(qǐng)仔細(xì)查看代碼,確保清楚每一個(gè)值的計(jì)算過(guò)程。
我們將數(shù)據(jù)打印到圖表中,如下:

我們藍(lán)色曲線模擬的效果非常好,它比單一的測(cè)量和預(yù)測(cè)值都更符合實(shí)際。也許我們的預(yù)測(cè)模型剛好符合實(shí)際,那如果我們的預(yù)測(cè)模型是每天減少1斤呢?
e, p = predict_using_gain_guess(initial_estimate, -1.)
#打印
gh.plot_gh_results(weights, estimates, predictions, [160, 172])
如下圖所示:

濾波器沒(méi)有上次好,但是!濾波器在調(diào)整自己,只不過(guò)調(diào)整的速度有點(diǎn)慢。如果體重的增加或者減少也是從預(yù)測(cè)和測(cè)量中計(jì)算出來(lái)呢?我么現(xiàn)在第二天的預(yù)測(cè)值是
(160+1)+4 /10*(158-161) = 159.8
我們的測(cè)量值是164.2,增加了4.4(164.2-159.8=4.4)而不是1,我么是否可以利用這個(gè)信息呢? 我們不要丟棄任何信息,我們得預(yù)測(cè)的增量是1,而測(cè)量增量是4.4,我們是否可以混合這兩個(gè)值?這和前面的問(wèn)題是一樣的。我們假設(shè)增加值是這樣的:
new gain = old gain + 1/3 (measurement - predicted) / day
重新編碼如下:
weight = 160. # initial guess
gain_rate = -1.0 # initial guess
time_step = 1.
weight_scale = 4./10
gain_scale = 1./3
estimates = [weight]
predictions = []
for z in weights:
# prediction step
weight = weight + gain_rate*time_step
gain_rate = gain_rate
predictions.append(weight)
# update step
residual = z - weight
gain_rate = gain_rate + gain_scale * (residual/time_step)
weight = weight + weight_scale * residual
estimates.append(weight)
gh.plot_gh_results(weights, estimates, predictions, [160, 172])
打印數(shù)據(jù)如下:

Great! 這就是g-h濾波器 (這里4/10就是g, 3/10就是h)
該濾波器是包括Kalman濾波器在內(nèi)的眾多濾波器的基礎(chǔ)。換句話說(shuō),卡爾曼濾波器是g-h濾波器的一種形式??偨Y(jié)一下該算法(這里采用原文):
Initialization
- Initialize the state of the filter
- Initialize our belief in the state
Predict
- Use system behavior to predict state at the next time step
- Adjust belief to account for the uncertainty in prediction
Update
- Get a measurement and associated belief about its accuracy
- Compute residual between estimated state and measurement
- New estimate is somewhere on the residual line

三. g,h的選擇
g的取值代表我們對(duì)預(yù)測(cè)和測(cè)量的信任程度。

g越大濾波器更靠近測(cè)量值,越小越靠近預(yù)測(cè)值。
h反應(yīng)的是濾波器的變化速度,這里不詳細(xì)講述,請(qǐng)參考原文。

實(shí)際應(yīng)用中對(duì)g和h的選擇具體分析,這里不做討論,相關(guān)請(qǐng)查看原文,重在理解g-h濾波模型的思想。
本節(jié)講述了g-h濾波,是大部分濾波的核心思想,通過(guò)不斷的在模型基礎(chǔ)上預(yù)測(cè)和測(cè)量而得到估計(jì)值,筆者認(rèn)為,濾波器的本質(zhì)是得到可能的值,某一時(shí)刻的真實(shí)值是不知道的,但我們對(duì)濾波器的估計(jì)值有很高的信任度,就像文章開(kāi)頭我們使用兩次測(cè)量的中間值一樣。
實(shí)際的應(yīng)用中單點(diǎn)的真實(shí)值意義不大,估計(jì)值很多情況能滿足我們的需求。最后,不要丟棄任何數(shù)據(jù)。