小村軟體有限公司
第 6 章

實作解讀 — 追蹤 1 維的最小實作

把 Python / C 的最小實作與式子、變數名稱、角色一一對照,讓你能追蹤 1 個迴圈。

把目前為止的內容寫成程式碼,1 維卡爾曼濾波器就能寫得非常短。重要的不是「行數」,而是能追出每一行對應到哪個式子。

Python 最小實作

把狀態(x_hatP)和參數(QR)整合在類別中。如果用 global 改寫模組變數,會導致無法同時運行多個濾波器、測試也較不方便,因此避免使用。

class KalmanFilter1D:
    def __init__(self, x_hat=0.0, P=10.0, Q=0.05, R=2.0):
        self.x_hat = x_hat
        self.P = P
        self.Q = Q
        self.R = R

    def step(self, z):
        x_pred = self.x_hat
        P_pred = self.P + self.Q

        K = P_pred / (P_pred + self.R)
        self.x_hat = x_pred + K * (z - x_pred)
        self.P = (1.0 - K) * P_pred
        return self.x_hat, self.P

寫成 (1.0 - K) 是為了避免被當成整數運算。Python 中即使寫 1 - K,只要 K 是 float,結果也會是 float,因此運作上相同;但這樣寫是為了與移植到 C 等其他語言時的行為一致,明確使用 1.0

C 最小實作

C 版同樣將狀態與參數整合進結構體,函式接收結構體並對其進行寫入。不使用全域變數。

typedef struct {
    double x_hat;
    double P;
    double Q;
    double R;
} KalmanFilter1D;

double kf_step(KalmanFilter1D *kf, double z) {
    double x_pred = kf->x_hat;
    double P_pred = kf->P + kf->Q;

    double K = P_pred / (P_pred + kf->R);
    kf->x_hat = x_pred + K * (z - x_pred);
    kf->P = (1.0 - K) * P_pred;
    return kf->x_hat;
}

使用範例:以 KalmanFilter1D kf = { .x_hat = 0.0, .P = 10.0, .Q = 0.05, .R = 2.0 }; 初始化後,每次觀測都呼叫 kf_step(&kf, z)

公式與變數的對應

x_pred
預測值 x̂⁻(方法內的區域變數)
P_pred
預測變異數 P⁻(方法內的區域變數)
K
卡爾曼增益(方法內的區域變數)
self.x_hat / kf->x_hat
更新後的估計 (濾波器的狀態)
self.P / kf->P
更新後的變異數 P(濾波器的狀態)

理解檢核 1 — 用手追蹤 1 個迴圈

Q = 0.5R = 2、前一時刻 x̂ = 4P = 1、觀測 z = 7,依實作的順序追蹤 1 個迴圈。

Q1. 執行第 1 行 x_pred = self.x_hat 後,預測值 x̂⁻ 是多少?

Q2. 執行第 2 行 P_pred = self.P + self.Q 後,預測變異數 P⁻ 是多少?

Q3. 執行第 3 行 K = P_pred / (P_pred + self.R) 後,卡爾曼增益是多少?

Q4. 執行第 4 行 self.x_hat = x_pred + K * (z - x_pred) 後,更新後的估計值 是多少?

Q5. 執行第 5 行 self.P = (1.0 - K) * P_pred 後,更新後的變異數 P 是多少?

解讀時的重點

  1. 先把預測的 2 行與更新的 3 行分開
  2. 確認 K 依賴於什麼
  3. 最後確認變異數 P 是否正確更新

理解檢核 2 — 讀懂程式碼的意義

用文字說明實作的每一行對應到式子的哪個部分。

Q1. 下列哪一行對應「吸收觀測後讓不確定性變小」的處理?

Q2. 實作裡不小心寫成 K = self.R / (P_pred + self.R) 的話,會發生什麼問題?

理解檢核 3 — 觀測與預測的差為 0 的情況

確認觀測與預測一致時這個特殊情況下的行為。

Q1. 預測值 x̂⁻ = 5、觀測 z = 5K = 0.6 時,更新後的 是多少?

Q2. 接著預測變異數 P⁻ = 4 時,更新後的變異數 P 是多少?