[翻譯][學習卡爾曼與貝葉斯濾波器][前言]

[翻譯][學習卡爾曼與貝葉斯濾波器——基於Python實踐][前言]

譯者:王偉韻
QQ : 352707983
項目鏈接:Github
:這是一個互動式教程,博客只能顯示靜態頁面。需要得到完整功能請下載項目並按照指導運行

這是一本卡爾曼濾波器和貝葉斯濾波器入門教材。這本書使用Jupyter Notebook編寫,因此你可以在瀏覽器中閱讀這本書,還可以運行和修改書中的代碼並實時查看結果。還有比這更好的學習方法嗎?

卡爾曼與貝葉斯濾波器

所有傳感器都有噪聲。這個世界充滿了各種我們想要測量和跟蹤的數據與事件,但我們並不能依靠傳感器來得到完美準確的信息。我車上的GPS顯示高度,每次我經過同一個位置,它報告的高度略有不同。如果我使用廚房秤稱同一個物體的重量兩次,會得到不同的讀數。

在簡單的情況下,解決方案是顯而易見的,如果測量儀器給出的讀數只是稍有不同,我可以多讀幾次然後取其平均值,或者我可以使用更高精度的測量儀器。但是,但傳感器噪聲很大,或者在某些環境下采集數據比較困難時,我們該怎麼做呢?我們可能想嘗試跟蹤一架低空飛行器的飛行軌跡,也可能想給無人機設計一個自動駕駛儀,亦或者想確保農場的拖拉機能夠毫無遺漏地播種整個田地。我的工作與計算機視覺有關,需要跟蹤圖像中的運動物體,而計算機視覺算法會產生充滿噪聲且不太可靠的結果。

這本書教你如何解決這些濾波問題。我使用了許多不同的算法,但它們均基於貝葉斯概率。簡單地說,貝葉斯概率根據過去的信息來判斷未來可能發生的事。

如果我讓你說出我車子現在的方向,你可能會一臉懵逼。你最多隻能提供一個介於1到360°之間的數字,那麼只有1/360的機會是正確的。現在假設我告訴你,2秒前我車子的航向是243°,而2秒內車子的方向變化不太可能會很大,因此你便能得出一個更精確的預測。你用過去的信息更準確地推斷出當前或未來的信息。

這個世界也是充滿噪聲的。上面的預測有助於你做出更好的估計,但它也會受到噪聲的影響。我可能會爲了一條狗而突然剎車,或者繞着一個坑洞轉彎。路上的強風和結冰是影響我汽車行駛路徑的外部因素。在控制相關文獻中,我們稱這些爲噪聲,儘管你可能不會這麼認爲。

關於貝葉斯概率還不止這些,但可能你已經瞭解其主要概念了。知識是不確定的,我們根據現象的強度來改變我們的置信度。卡爾曼與貝葉斯濾波器將我們對系統如何運行的嘈雜且有限的認知和同樣嘈雜且有限的傳感器測量結合起來,以得到對系統狀態的最優估計。我們的原則是永遠不要丟棄信息。

假設我們正在追蹤一個物體,傳感器告訴我們它突然改變方向了。是真的改變了,還只是傳感器數據有噪聲?這得看情況而定,如果這時一架噴氣式戰鬥機,我們會非常傾向於相信它的確發生了一個瞬時機動,而如果這是一輛直線軌道上的貨運列車,那我們會降低數據的可信度,同時我們會進一步根據傳感器的精度來修正它的置信度。也就是說,置信度取決於我們對正在跟蹤的系統的認知程度以及傳感器特性。

卡爾曼濾波器最初是由Rudolf Emil Kálmán發明的,用數學上的最優方法來解決這類問題。它最初用於阿波羅登月任務,從那時起,它就被廣泛用於各種領域。飛機、潛艇和巡航導彈上都使用了卡爾曼濾波器。它們被華爾街用於跟蹤金融市場,還被用於機器人、物聯網傳感器和實驗室儀器中。化工廠用它來控制和監測化學反應,醫學成像中用於去除心臟信號中的噪聲。在涉及傳感器和時間序列數據的應用中,通常都會運用到卡爾曼濾波器或者相似方法。

寫這本書的動機

我是一名軟件工程師,在航空航天領域工作了近20年,所以我經常會在卡爾曼濾波器上碰壁,但卻從未實現過一個,畢竟它們是出了名的困難。這個理論很優美,但是如果你在信號處理、控制理論、概率和統計以及制導和控制理論等方面還沒有比較好的訓練的話,學習起來就很困難。隨着我開始使用計算機視覺來解決跟蹤問題,自己來實現卡爾曼濾波器的需求也變得迫切了。

這個領域並不缺少優秀的教科書,如Grewal和Andrew的《Kalman Filtering》。但是,如果不瞭解一些必要的背景知識,那坐下來直接閱讀這些書籍只會讓你感到沮喪和厭煩。一般來說,前幾章會概述需要數年學習的大學數學課程內容,輕描淡寫地讓你參考有關微積分的教科書,並在幾個簡短的段落中展示需要整個學期來學習的結論。它們是高年級本科或研究生課程的教科書,也是研究人員和專業人士的寶貴參考資料,但對於更一般的讀者來說,確實學習起來會很困難。引入的數學符號沒有註釋,不同的文檔中可能會使用不同的單詞和變量名來表示同一個概念,並且這些書中幾乎沒有實例或解決一些實際問題。我經常發現自己能看懂每一個單詞並瞭解那些數學定義,卻完全不能理解這些單詞和數學公式試圖描述的真實世界現象是什麼,我會反覆思考:“但這些是什麼意思呢?”。以下是曾經讓我困惑的典型例子:
x^k=Φkx^k1+Gkuk1+Kk[zkHΦkx^k1HGkuk1]Pkk=(IKkHk)cov(xkx^kk1)(IKkHk)T+Kkcov(vk)KkT \hat{x}_{k} = \Phi_{k}\hat{x}_{k-1} + G_k u_{k-1} + K_k [z_k - H \Phi_{k} \hat{x}_{k-1} - H G_k u_{k-1}] \\ \mathbf{P}_{k\mid k} = (I - \mathbf{K}_k \mathbf{H}_{k})\textrm{cov}(\mathbf{x}_k - \hat{\mathbf{x}}_{k\mid k-1})(I - \mathbf{K}_k \mathbf{H}_{k})^{\text{T}} + \mathbf{K}_k\textrm{cov}(\mathbf{v}_k )\mathbf{K}_k^{\text{T}}

然而,當我終於理解卡爾曼濾波器後,才意識到這些基本概念是非常簡單的。如果你熟悉一些簡單的概率定理,並且對如何融合不確定事物有一定直覺,那便能理解卡爾曼濾波器的概念。卡爾曼濾波器以困難著稱,但是拋棄很多專業術語後,我愈發清晰看到它本質和數學上的美麗,於是我愛上了它。

更多的困難出現在我嘗試開始去理解這些數學和理論的時候,一本書或者一篇論文會去陳述事實並提供圖表以證明,但不幸的是,我仍然不清楚這個陳述爲什麼是正確的,又或者我無法重現其圖表。或有時我想知道“這是否成立如果R=0?”,作者可能會提供一些比較高層次的僞代碼以至於無法輕易實現。有些書提供Matlab代碼, 但可惜我沒有使用這種昂貴商業軟件所需要的許可證。另外 ,還有很多書在每一章末尾提供了許多有用的練習,如果你想要自己實現卡爾曼濾波器,那麼便要去理解這些沒有答案的練習。如果你在課堂上使用這本書,那可能關係不大,但對於獨立讀者來說這便很糟糕了,我討厭作者對我隱瞞信息,大概他是爲了避免學生在課堂上作弊吧。

所有的這些都會阻礙學習。我想在屏幕上追蹤一張圖像,或者爲我的Arduino項目寫一些代碼,因此我想知道這些書中的圖表是如何產生的,並且想選擇一些與作者所提供的不一樣的參數。我想仿真運行,看看濾波器在信號中加入更多噪聲時是如何表現的。在每天的代碼中都有成千上萬使用卡爾曼濾波器的機會,而這些相當直觀簡單的項目也是火箭科學家和學者誕生的源頭。

我寫這本書便是爲了滿足所有上述需求。但如果你在設計軍用雷達,這並不能成爲你唯一的參考資料,你更需要的是去一所很棒的STEM學校攻讀碩士或博士學位。這本書提供給那些需要濾波或平滑一些數據的愛好者,好奇者和正在工作的工程師。如果你是一個愛好者,這本書應該能提供你所需要的一切。如果你想深入專研卡爾曼濾波器,那你還需要學習更多,我意圖介紹足夠的概念和數學基礎,讓你更容易去學習教科書和論文。

這本書是交互式的,雖然你也可以把它當成靜態內容直接在線閱讀,但我強烈建議你按照預期來使用它。基於Jupyter Notebook,讓我可以在書中任何地方組織文本、數學公式、Python代碼和其輸出。本書中每一個數據和圖表都是由notebook中的Python生成的。想成倍修改某個參數值?只需要更改參數的值,然後按CTRL-ENTER,便會生成新的圖表或者打印輸出。

這本書有練習,但也都有答案。我信任你。如果你只是需要一個答案,那就直接閱讀答案。而如果你想更深刻理解這些知識,那麼在這之前先嚐試去實現那些練習吧。因爲這本書具有交互性,你可以直接在本書中輸入並運行你的答案,而不必要遷移到其它不一樣的環境,也不用在開始前導入大量內容。

這本書是免費的。我曾經花了數千美元去購買卡爾曼相關書籍,這對於那些手頭拮据的學生來說幾乎是不可能的事情。我從諸如Python之類的免費軟件和Allen B. Downey [1]的那些免費書籍中獲益頗多,是時候回報了。因此,這本書是免費的,它託管在Github的免費服務器上,並且只用到了免費和開源的軟件如IPython和MathJax。

在線閱讀

GitHub

這本書託管在Github上,你可以通過點擊章節名字來閱讀任何一章。Github只能靜態呈現Jupyter Notebooks,你可以閱讀所有內容,但無法運行和修改代碼。

這個項目的GitHub鏈接如下

https://github.com/rlabbe/Kalman-and-Bayesian-Filters-in-Python

binder

binder提供notebooks在線交互服務,所以你可以直接在瀏覽器上修改和運行代碼,而不必下載這本書或者安裝Jupyter。使用下面的鏈接在binder上獲取這本書:

http://mybinder.org/repo/rlabbe/Kalman-and-Bayesian-Filters-in-Python

nbviewer

nbviewer網站可以將任何一本Notebook轉換爲靜態格式。我發現它比Github提供的轉換器要更好一些,只是用起來有點不太方便。它可以直接接入Github,任何我在Github上的修改都可以被nbviewer所同步。

你可以使用下面的鏈接在nbviewer上獲取這本書:

http://nbviewer.ipython.org/github/rlabbe/Kalman-and-Bayesian-Filters-in-Python/blob/master/table_of_contents.ipynb

PDF 版本

我會定期通過notebooks生成這本書的一個PDF版本,你可以通過這個鏈接訪問:

https://drive.google.com/file/d/0By_SW19c1BfhSVFzNHc0SjduNzg/view?usp=sharing

下載和運行這本書

不管怎樣,這本書設計成了交互式的,我也建議以這種形式來使用它。做成這樣花費了一番功夫,但這是很值得的。如果你在電腦上安裝了IPython和一些支持庫,那可以把這本書clone下來,你將能夠自己運行書中的所有代碼。你可以執行實驗,觀察濾波器對於不同數據的表現,等等。我發現這種即時反饋不僅很重要而且會讓人充滿動力,你不用去懷疑“如果會怎樣”,放手去試吧!

安裝說明見安裝附錄,見此處

安裝軟件後,你可以進入到安裝目錄並在終端中通過命令行運行juptyer notebook

jupyter notebook

它將會打開一個瀏覽器窗口,顯示根目錄的內容。這本書分成許多章,每個章節都命名爲xx-name.ipynb,其中xx是章節號,.ipynb是Notebook文件的擴展名。要閱讀第二章,請單擊第二章的鏈接,瀏覽器將會打開那個子目錄。每個子目錄中將會有一個或多個IPython Notebooks(所有notebooks都有.ipynb文件擴展名)。章節內容在notebook中,與章節名稱同名。每章中還會有許多實現相關功能如生成顯示動畫的supporting notebooks,每個用戶沒必要去閱讀這些,但如果你對於動畫是如何製作的比較好奇,那就看一眼吧。

誠然,對於一本書來說這個界面過於繁瑣。我正在跟隨其它幾個項目的腳步,這些項目將Jupyter Notebook重新設計以生成完整的一本書。我覺得這些繁瑣的事情會有巨大的回報——當你讀一本書的時候,不必下載一個單獨的代碼庫並在一個IDE中運行它,所有的代碼和文檔都會在同一個地方。如果你想修改代碼,你可以立即這麼做並即時看到修改的效果。你可以修復一個你發現的bug,然後推送到我的倉庫中,這樣全世界的人們都能受益。當然,你也永遠不會遇到我在傳統書籍中一直需要面臨的問題——書籍和其代碼彼此不同步,你需要絞盡腦汁去判斷哪個來源更可靠些。

Jupyter

首先,簡單介紹一下如何使用Jupyter Notebooks來閱讀這本書。這本書是交互式的,如果你想運行示例代碼,尤其是想觀察波形動畫時,則需要運行代碼單元。我不能教會你Jupyter Notebooks的一切。然而有一些地方可能會讓讀者產生困惑,你可以訪問http://jupyter.org/獲取詳細文檔。

首先,你必須要運行最頂層的代碼單元, 即帶有註釋 #format the book的那個,就在最上方。這一步不僅設置了一些你不用關心的格式,還加載了一些必要模塊,進行了一些有關繪圖和打印的全局設置。所以,必須要運行這個單元,除非你只是單純地被動閱讀。import from __future__ 可以讓 Python 2.7 像 Python 3.X 那樣工作。整數的除法將會返回一個 float (3/10 == 0.3) ,而不是一個 int (3/10 == 0),並且打印函數需要加上括弧: print(3), 非 print 3. 這一行

%matplotlib inline

會讓繪圖顯示在notebook的範圍內。Matplotlib是一個繪圖包,下面將會描述。出於某種理由讓我無法理解爲什麼Jupyter Notebooks的默認設置會在一個額外的窗口中進行繪圖。

%matplotlib 中的百分比符號用於 IPython magic - 這是核心實現的一些命令而不是Python語言中的一部分。還有很多有用的魔法命令(magic commands),你可以在這裏瞭解到更多: http://ipython.readthedocs.io/en/stable/interactive/magics.html

在單元格里運行代碼很容易,單擊它使其被選中(會出現一個圍繞它的外框),然後按下 CTRL-Enter。

其次,單元格必須按順序運行。我將問題分解到數個單元格中,如果你嘗試跳過並直接運行第十個代碼單元格,那幾乎可以肯定它不會工作。如果你還沒有運行任何內容,只需要從單元格 菜單中選擇 運行所有單元格 ,這是確保一切能順利工作的最簡單方式。

一旦全部單元格被運行,你便可以經常進行跳轉並以不同的順序重新運行各個單元格,但有時候可能會出現問題,我正在嘗試解決,不過還有一個折衷的辦法。舉個例子,我在單元格10中定義一個變量,然後在單元格11和12中運行修改該變量的代碼,如果你返回並再次運行單元格11,變量已經在單元格12中被賦值,然而代碼所期望的是這個變量應該是在單元格10中被賦值。所以你如果不按照順序運行單元格,有時候會得到奇怪的結果。我的建議是再回退一步,重新運行單元格以恢復到正確的狀態。這比較煩人,但Jupyter notebooks的互動功能依然彌蓋了這個不足。更好的是,你可以再Github上提交一個issue,這樣我就知道這個問題並修復它了!

最後,已經有一些讀者報告了在某些瀏覽器中動畫繪圖功能的問題,我還不能復現這個。在本書中的某些部分,我使用了%matplotlib notebook magic 以實現交互式繪圖。如果這些繪圖在你那裏無法生效,請嘗試將其更改讀取 %matplotlib inline。 你將會失去繪圖動畫,不過這樣似乎在所有平臺和瀏覽器上都能工作。

SciPy, NumPy, and Matplotlib

Scipy是一個開源的數學軟件集,其中包含了提供數組對象、線性代數、隨機數等功能的NumPy。Matplotlib給NumPy數組提供繪圖功能。Scipy的模塊複製了NumPy的一些功能,同時添加了優化、圖像處理等功能。

爲了保持我對這本書投入的精力是可控的,我選擇假設你瞭解如何使用Python編程,並且熟悉這些packages。儘管如此,我還是會花一些時間來說明每一個的特性,實際上你必須去尋找其它外部資源來學習更多細節。SciPy的主頁,https://scipy.org ,是一個完美的起點,儘管你可能很快會想去搜索相關的教程或視頻。

Python的發行版中並不默認包含NumPy,SciPy以及Matplotlib,如果你還沒安裝這些,請參見安裝附錄。

我在書中通篇使用了NumPy的數組元素類型,所以現在讓我們來了解一下它們。我會教夠你足夠多的知識以便開始學習這本書,如果你想更深入,請參考NumPy的文檔。

numpy.array 實現了單維或者多維數組,它的類型是numpy.ndarray,簡稱爲ndarray。你可以用任何類似列表的對象來構造它。下面從一個列表中構造一個一維數組:

import numpy as np
x = np.array([1, 2, 3])
print(type(x))
x

<class ‘numpy.ndarray’>
array([1, 2, 3])

使用import numpy as np已經成爲了一個行業標準。
你也可以使用元組:

x = np.array((4,5,6))
x

array([4, 5, 6])

使用嵌套括號創建多維數組:

x = np.array([[1, 2, 3],
              [4, 5, 6]])
print(x)

[[1 2 3]
[4 5 6]]

你可以創建三維或者更高維的數組,但這裏沒有這個需求,所以我便不再贅述。

默認情況下,數組使用列表中變量的數據類型,如果有多種類型,則它將選擇能夠最精確表示所有變量的類型。例如,如果列表包含 intfloat這兩種類型,那麼數組的數據類型將是 float,不過你仍可以使用dtype參數來指定具體類型。

x = np.array([1, 2, 3], dtype=float)
print(x)

[1. 2. 3.]

可以使用數組下標來訪問數組元素:

x = np.array([[1, 2, 3],
              [4, 5, 6]])

print(x[1,2])

6

你可以使用切片(slices)來訪問某一列或某一行。 冒號 (:) 作爲下標,可以用於表示那一行或者列的所有數據,所以x[:,0] 返回一個包含第一列(0指定第一列)所有數據的數組:

x[:, 0]

array([1, 4])

我們可以用這種方式獲取第二行:

x[1, :]

array([4, 5, 6])

獲取第二行的最後兩個元素:

x[1, 1:]

array([5, 6])

與Python的列表一樣,可以使用負索引來引用數組的尾部,-1表示最後一個索引,因此獲得第二行(最後一行)最後兩個元素的另一種方法爲:

x[-1, -2:]

array([5, 6])

可以使用 +運算符來執行矩陣加法,但矩陣乘法需要 dot 方法或函數, * 運算符表示的是元素乘法( element-wise multiplication),而不是你想要的那種線性代數中的相乘。

x = np.array([[1., 2.],
              [3., 4.]])
print('加法:\n', x + x)
print('\元素乘法\n', x * x)
print('\乘法\n', np.dot(x, x))
print('\dot 也是 np.array 的一個成員\n', x.dot(x))

加法:
[[2. 4.]
[6. 8.]]
元素乘法
[[ 1. 4.]
[ 9. 16.]]
乘法
[[ 7. 10.]
[15. 22.]]
dot 也是 np.array 的一個成員
[[ 7. 10.]
[15. 22.]]

Python 3.5 爲矩陣乘法引入了 @ 運算符。

x @ x

[[ 7.0 10.0]
[ 15.0 22.0]]

只有在使用Python 3.5+時,這個乘法運算符纔有效。所以,在這本書裏我不會用它,儘管相比np.dot(x, x) 而言我更喜歡這個符號。

你可以使用.T得到矩陣轉置, 並使用numpy.linalg.inv對矩陣求逆。 SciPy 包也提供了求逆函數。

import scipy.linalg as linalg
print('transpose\n', x.T)
print('\nNumPy ninverse\n', np.linalg.inv(x))
print('\nSciPy inverse\n', linalg.inv(x))

transpose
[[1. 3.]
[2. 4.]
NumPy ninverse
[[-2. 1. ]
[ 1.5 -0.5]
SciPy inverse
[[-2. 1. ]
[ 1.5 -0.5]]

還有許多輔助函數,如 zeros 用來構造全零矩陣(所有元素爲0), ones構造全一矩陣,而 eye可以構造單位矩陣。如果需要多維數組,請用元組指定形狀。

print('zeros\n', np.zeros(7)
print('\nzeros(3x2)\n', np.zeros((3, 2)
print('\neye\n', np.eye(3))

zeros
[0. 0. 0. 0. 0. 0. 0.]
zeros(3x2)
[[0. 0.]
[0. 0.]
[0. 0.]
eye
[[1. 0. 0.]
[0. 1. 0.]
[0. 0. 1.]]

我們有創建等差數據的函數。 arange 的工作原理與Python的 range 函數非常相似, 除了返回值爲NumPy數組。linspace 稍有區別,你可以使用linspace(start, stop, num)調用它,其中 num 是所需數組的長度。

np.arange(0, 2, 0.1)

array([0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1. , 1.1,
1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9])

np.linspace(0, 2, 20)

array([0. , 0.105, 0.211, 0.316, 0.421, 0.526, 0.632, 0.737, 0.842,
0.947, 1.053, 1.158, 1.263, 1.368, 1.474, 1.579, 1.684, 1.789,
1.895, 2. ])

現在讓我們來繪製一些數據,大多數情況下都是比較簡單的。 Matplotlib 包含了一個繪圖庫 pyplot,將其import爲plt 是一個行業標準。import後,使用列表或數組作爲參數,調用 plt.plot 可以繪製出這些數字。如果你多次調用,它將繪製多個曲線,利用不同顏色加以區分。

import matplotlib.pyplot as plt
a = np.array([6, 3, 5, 2, 4, 1])
plt.plot([1, 4, 2, 5, 3, 6])
plt.plot(a)"

在這裏插入圖片描述

輸出[<matplotlib.lines.Line2D at 0x2ba160bed68>] 是因爲 plt.plot 會返回剛創建的對象。通常我們不想看到這個,所以我在最後一個繪圖命令中加入了一個 ; 來禁止其輸出。

默認情況下plot假定X座標軸按1遞增,你可以通過同時傳入x和y來設置自己的X座標軸

在這裏插入圖片描述

練習 - 創建數組

我希望你創建一個由10個元素組成的NumPy數組,其中每個元素的值爲1/10。有數種方法可以做到這一點,請儘可能多的實現你能想到的方法。

解決方案

這裏有三種實現方法,第一種是我想讓你瞭解的那個。我使用了 ‘/’ 運算符將數組的所有元素除以10,我們會很快使用這個方式將一個數組的單位從米轉換爲公里。

print(np.ones(10) / 10.)
print(np.array([.1, .1, .1, .1, .1, .1, .1, .1, .1, .1])
print(np.array([.1]*10))

[0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1]
[0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1]
[0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1]

這個我還沒有提到過,numpy.asarray()函數可以將其傳入的參數轉換爲ndarray(如果它原先還不是的話),如果是,則數據不變。這是編寫一個可以接受Python列表或ndarrays參數的函數的一種簡便方式,而且如果本身類型已經是ndarray,那它是非常高效的,因爲沒有創建新的東西。

def one_tenth(x):
    x = np.asarray(x)
    return x / 10.
print(one_tenth([1, 2, 3]))            # I work!
print(one_tenth(np.array([4, 5, 6])))  # so do I!

[0.1 0.2 0.3]
[0.4 0.5 0.6]

配套軟件

我正在編寫一個名爲FilterPy的開源貝葉斯濾波python庫,上面給出了安裝說明。

這本書的特定代碼與書存放在一起,位於子目錄 /kf_book 中。它包含了格式化書籍的代碼,還包含名爲 xxx_internal.py 的Python文件,我使用這些文件存儲對特定章節有效的函數。這允許我能夠隱藏那些你可能不太感興趣的Python代碼——我可能生成了一個波形圖表,但我希望你能夠關注圖表的內容,而不是我如何使用Python生成它的方法。如果你對其非常好奇,那隻需去瀏覽源代碼即可。

一些章節介紹了對本書其餘部分有用的函數,這些函數最初是在Notebook本身中定義的,但是代碼也存儲在 /kf_book 的Python文件中,如果後續章節需要,那可以導入這些文件。我編寫文檔來註明這些函數首次被調用的地方,不過這仍是一項正在進行的工作。我儘量避免這麼做,因爲這樣總是會讓我面臨目錄中的代碼與書中的代碼不同步的問題。然而,Jupyter Notebook並沒有給我們提供一種方法來引用其它notebooks中的代碼單元,所以這是我知道的在notebooks中共享函數的唯一技巧。

有一個名爲 /experiments的未註明目錄,這是我在將代碼放入書中之前編寫和測試代碼的地方。裏面有一些有趣的東西,你可以隨意看看。隨着這本書的發展,我計劃創建一些實例和項目,其中很多材料最終都會出現在那裏。小測試最終都會被刪除,如果你只是對讀這本書感興趣,可以放心地忽略這個目錄。

目錄 /kf_book 中有一個包含書籍樣式指南的css文件,Jupyter Notebook的默認外觀非常簡單,我參考了一些書籍的例子,如Probabilistic Programming and Bayesian Methods for Hackers [2],我也深受Lorena Barba教授的精彩著作的影響,該書見此處 [3]。本書的外觀及樣式方面的成果都歸功於這些項目。

關於Python和編程數學的思考

大多數卡爾曼濾波和其它工程類教科書都是由數學家或學者編撰的,甚少涉及到程序,即使有,其質量也比較低下。以Paul Zarchan的《Fundamentals of Kalman Filtering》爲例,這是一本很棒並值得你收藏的書,是爲數不多的爲每個例子和圖表提供代碼的書之一。但使用的代碼是Frotran,除了調用MATMUL之類的函數外沒有任何子程序。卡爾曼濾波器在整本書中被重複實現,同樣的清單中將仿真和濾波代碼混到了一起,讓人很難區分它們。有一些章節使用稍有區別的方式來實現相同的濾波器,並使用粗體文本突出顯示更改的幾行。如果需要用到Runge Kutta算法,它會被直接嵌入到代碼中,沒有任何註釋。

存在着更好的方法。如果我想執行調用被我稱之爲 ode45 的Runge Kutta算法,我不會直接在代碼中嵌入Runge Kutta,我不想多次重複實現Runge Kutta並多次調試它。如果我真的找到了一個bug,我可以只修復一次,並確保它現在可以在我所有不同的項目中正常工作。而且這麼做使得代碼可讀性更好,事實上我很少關心Runge Kutta的實現。

這是一本關於卡爾曼濾波的教科書,你可能會說我們只關心卡爾曼濾波器的實現。這是事實,但是隻需要大約10行代碼用於濾波器的執行,實現數學的代碼相當簡單,卡爾曼濾波器需要做的大部分工作是設計輸入數學模型中的矩陣。

可能還存在一個缺點,即執行濾波的方程隱藏在函數中,不過可以說這只是教學文本中的一個缺失。或者說,我想讓你學會如何在現實世界中使用卡爾曼濾波器,而不只是到處複製粘貼已經寫好的算法。

我使用Python類。但我主要使用類來組織濾波器所需的數據,而不是實現如繼承之類的面向對象特性(OO)。例如,KalmanFilter 類存儲了名爲 x, P, R, Q, S, y, K的矩陣和向量。 我見過卡爾曼濾波器的過程實現庫,不過它們要求程序員維護所有這些矩陣。這對於一個玩具程序來說或許不壞,但是編寫大量卡爾曼濾波器時,你將不會喜歡必須要管理這些矩陣和其它相關數據。在我自己的工作中偶爾會派生出這些類,且發現它很方便,但我不想強行安利OO,據我所知很多人反感這麼做。

資源

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章