一个循环,永远运转
机器人永远无法精确知道自己在哪里。它持有一个信念——一个铺在所有可能位置上的概率分布——而它在每一个时钟节拍要做的全部工作,就是让这个信念保持诚实。贝叶斯滤波正是做到这一点的配方,它只有两个永远重复的动作:预测,然后修正。
想象你在黑暗中穿过自己的家。你朝着你认为门口所在的方向迈出一步——这是预测,依据的是你的腿执行的指令。接着你的手蹭到了墙——这是一次传感器读数,它让你对所处位置的感觉变得更清晰。预测、感知、循环。贝叶斯滤波不过是把这个习惯写得足够精确,让计算机每秒能运行几千次。
滤波器依赖的两个模型
循环的每个动作都由两个模型之一驱动。运动模型(有时称为过程模型)回答的是:在我原本相信的位置上,加上我刚发给轮子的指令,我现在应该出现在哪里?它刻画了状态在一个时间步内如何演化。
观测模型(或测量模型)则朝反方向运转:如果我真的位于某个位置,我的传感器应该产生什么读数?比如一个测墙距的传感器,靠近墙时会报出一个小数值,在空旷处则报出一个大数值。当一个新读数到来时,滤波器会问哪些候选位置能解释这个读数,并偏向它们。
两个模型都不完美,而滤波器对此心知肚明。每条指令都会略有偏差——轮子在灰尘上打滑、齿轮有间隙——每个传感器也都会略微撒谎。这种对不完美的诚实承认就是过程噪声与测量噪声,把这些噪声的大小估个八九不离十,几乎比其他任何事都更重要。
看着信念呼吸:一维走廊
把一切简化成一个待在笔直走廊里的机器人,它唯一在意的就是自己沿走廊的位置。它的信念现在是一条简单的曲线:又高又窄表示「我相当确定自己在这里」,又低又宽表示「我可能在这段走廊的任何地方」。看看这两个步骤各自如何改变这条曲线。
- 预测。机器人发出指令「前进 1 米」。整条信念曲线沿走廊滑动 1 米——同时它也变宽变矮,因为轮子可能打滑了。仅凭自己的猜测移动,总会让你更不确定。
- 感知。一个门检测器触发了,机器人知道走廊上有三处装着门。观测模型在这三个位置附近抬高信念,在别处把它压平。
- 修正。滤波器把预测曲线乘上传感器曲线。两者一致之处,结果又高又窄;两者不一致之处,结果塌缩到接近零。摊开的信念被收紧成一个自信的尖峰。
- 循环。机器人继续行驶,曲线在下一次预测时再次摊开,而下一次看到门又把它收回。经过几个循环,三扇门之间的歧义就收敛成一个唯一而自信的答案。
这种呼吸的节律——预测时变宽、感知时收紧——就是每一个估计器的心跳。预测花掉确定性以在时间上向前迈进;感知则用真实证据把确定性买回来。只会预测的机器人(纯航位推算)只能眼睁睁看着信念模糊到毫无用处;而滤波器能让它始终保持清晰。
loop forever each tick: # 1. PREDICT using motion model + command u belief = move(belief, u) # slides and widens # 2. CORRECT using observation model + reading z belief = belief * likelihood(z) # reweights belief = normalize(belief) # rescale to sum 1
你接下来会遇到的那些滤波器之母
走廊版本把信念存成一列「桶子」,对一条走廊够用,但对一个在二维仓库里游走、有成千上万格子的机器人就毫无指望了。你接下来要学的那些著名滤波器,无非是用更聪明的方式来表示和更新同一个信念,从而绕开这种蛮力网格。
卡尔曼滤波做了一个大胆的假设——信念永远是一条单一的钟形曲线——于是预测和修正就化为几行矩阵代数,快到足以胜任最紧凑的控制回路。当机器人的运动或传感器太「弯」、装不进一条直线钟形曲线的故事时,扩展型和无迹型变体会弯折这个假设来贴合现实。
粒子滤波则走了另一条路:它保留了走廊版本的诚实——一个可以同时拥有好几个峰的信念,正是三扇门看起来一模一样时你所需要的——但用一群采样出来的猜测点而非网格来表示它。同样的预测-修正循环,不同的记账方式。