M2.3 14 分鐘閱讀 2026年9月

M2.3 導航每 30 秒更新一次:Euler 法與它的誤差

本篇重用M0.2導航的三十秒:Taylor 展開與「假設直線」·M2.0河面上的箭頭:Vector Field 與 ODE

一條彎路,一台省電的導航

你的車以時速 60 公里在一條大彎道上行駛:彎道是四分之一圓,半徑 2 公里。導航為了省電,每 30 秒才讀一次車子的行進方向;在兩次讀取之間,它假設你一直沿著上次讀到的方向直走,把位置往前推 30 秒的距離。

走完這個四分之一圓(約 3.1 公里、三分多鐘),導航上的位置和你真正的位置會差多遠?如果換成一條筆直的路呢?

先用直覺回答,並寫下你有多確定、依據是什麼。常見的直覺是「直路完全不會錯;彎路會偏一點,大概幾十公尺吧」。第一句對。第二句對不對——以及「幾十公尺」是怎麼估出來的——直覺說不出來。而且有一個更重要的問題直覺回答不了:如果改成每 10 秒更新一次,誤差會縮成多少?三分之一?九分之一?

課堂提問Q1

翻成數學。「真正的位置」是哪個物件?「導航算出的位置」又是哪個?「每 30 秒直走一段」寫成式子是什麼?我們想知道的量是什麼?

先想一想,再展開看整理後的答案

這一題可以直接對上前一篇的語言:真正的位置是 ODE x˙=u(x,t)\dot x=u(x,t) 的解 x(t)x(t)uu 是「在位置 xx 時車的速度向量」——沿著路的方向、大小 v=60 km/h16.7 m/sv=60\text{ km/h}\approx16.7\text{ m/s}M2.0)。

導航算的是另一串東西。令 h=30h=30 秒,tn=nht_n=nh。導航記錄的位置 xnx_n

xn+1=xn+hu(xn,tn)x_{n+1}=x_n+h\,u(x_n,t_n)

一步一步算出來:在目前的位置看一次方向,往那個方向直走 hh 秒。這條規則叫 Euler 法,它就是 M2.0 結尾那段「順著箭頭走」的程式。

我們想知道的量是全域誤差 eN=x(tN)xNe_N=\|x(t_N)-x_N\|:走完全程(N=T/hN=T/h 步)之後,真實位置與導航位置的距離。以及它怎麼隨 hh 變化。這裡沒有隨機變數;誤差完全來自「兩次讀取之間假設直走」。

先看畫面:切線離開了圓

把彎道畫成一段圓弧,車在圓弧上。Euler 的一步是沿著切線往前走 500 公尺(30 秒 × 16.7 m/s)。切線是直的、圓弧是彎的,走完這一步,導航的點落在圓的外側——這是一步的誤差,叫局部誤差

下一步從那個已經偏外的點出發。它會犯同樣的錯(又沿切線離開),還會多一件事:它現在站在一個「真車從來沒去過」的位置,讀到的方向也不是真車此刻的方向。前面的錯誤會被帶著走,有時還會被放大。全程的誤差就是這兩件事的疊加:每步新犯的錯,加上舊錯被帶著走的方式

直路上切線就是路本身,一步的誤差是零,帶著走的也是零。這就是「直路完全不會錯」的畫面版。

寫成數學:一步的錯、多步的累積

局部誤差。 假設第 nn 步從正確的位置 x(tn)x(t_n) 出發。真實的下一個位置用 Taylor 展開(M0.2):

x(tn+h)=x(tn)+hx˙(tn)+h22x¨(ξn),ξn[tn,tn+h].x(t_n+h)=x(t_n)+h\,\dot x(t_n)+\tfrac{h^2}{2}\,\ddot x(\xi_n),\qquad \xi_n\in[t_n,t_n+h].

Euler 給的是 x(tn)+hu(x(tn),tn)=x(tn)+hx˙(tn)x(t_n)+h\,u(x(t_n),t_n)=x(t_n)+h\,\dot x(t_n)——恰好是 Taylor 的前兩項。兩者相減:

x(tn+h)[x(tn)+hu(x(tn),tn)]=h22x¨(ξn).\big\|x(t_n+h)-\big[x(t_n)+h\,u(x(t_n),t_n)\big]\big\|=\tfrac{h^2}{2}\,\|\ddot x(\xi_n)\|.

一步的誤差是 h2h^2 的量級,係數是加速度 x¨\ddot x。沿著解,x¨=ddtu(x(t),t)=tu+(u)u\ddot x=\tfrac{d}{dt}u(x(t),t)=\partial_t u+(\nabla u)\,uM0.3);對等速轉彎的車,x¨=v2/R\|\ddot x\|=v^2/R

全域誤差。en=x(tn)xne_n=x(t_n)-x_n。第 nn 步 Euler 不是從正確位置出發,而是從 xnx_n

en+1=x(tn)+hu(x(tn),tn)+h22x¨(ξn)x(tn+1)[xn+hu(xn,tn)]xn+1=en+h[u(x(tn),tn)u(xn,tn)]+h22x¨(ξn).e_{n+1}=\underbrace{x(t_n)+h\,u(x(t_n),t_n)+\tfrac{h^2}{2}\ddot x(\xi_n)}_{x(t_{n+1})}-\underbrace{\big[x_n+h\,u(x_n,t_n)\big]}_{x_{n+1}} = e_n+h\big[u(x(t_n),t_n)-u(x_n,t_n)\big]+\tfrac{h^2}{2}\ddot x(\xi_n).

中括號裡是「在兩個相距 en\|e_n\| 的位置讀到的方向差」,Lipschitz 條件(M2.0)說它不超過 LenL\|e_n\|。所以

en+1(1+hL)en+h22Mn,Mn=max[tn,tn+1]x¨.\|e_{n+1}\|\le(1+hL)\,\|e_n\|+\tfrac{h^2}{2}M_n,\qquad M_n=\max_{[t_n,t_{n+1}]}\|\ddot x\|.

這就是離散版 Grönwall 不等式的形狀:每步舊誤差乘上 (1+hL)(1+hL)、再加上新的局部誤差。從 e0=0e_0=0 展開,用 (1+hL)kekhLeLT(1+hL)^k\le e^{khL}\le e^{LT}

eN    n=0N1(1+hL)N1nh22Mn    eLTh2n=0N1hMn      h2eLT0Tx¨(t)dt  \|e_N\|\;\le\;\sum_{n=0}^{N-1}(1+hL)^{N-1-n}\,\tfrac{h^2}{2}M_n \;\le\;e^{LT}\,\tfrac{h}{2}\sum_{n=0}^{N-1}h\,M_n \;\approx\;\boxed{\;\frac{h}{2}\,e^{LT}\int_0^T\|\ddot x(t)\|\,dt\;}

\square(最後一步把黎曼和換成積分。)三個因子各有意思:hh——步長縮一半、誤差縮一半,Euler 是一階方法;x¨dt\int\|\ddot x\|dt——整條路的加速度總量,路越彎、轉得越急,誤差越大;直路是零。eLTe^{LT}——場對位置越敏感(LL 越大),舊誤差被放大得越凶。這是一個上界,不是等式:前兩個因子通常抓得很準,eLTe^{LT} 常常太悲觀。

展開細節連續版 Grönwall 不等式與它的證明(四行)

連續版:若 φ(t) ≥ 0 滿足 φ(t) ≤ A + L∫₀ᵗ φ(s) ds,則 φ(t) ≤ A·e^(Lt)。 證明:令 Ψ(t) = A + L∫₀ᵗ φ。則 Ψ′ = Lφ ≤ LΨ,所以 d/dt [Ψ e^(−Lt)] = (Ψ′ − LΨ)e^(−Lt) ≤ 0,Ψ(t)e^(−Lt) ≤ Ψ(0) = A,故 φ ≤ Ψ ≤ A e^(Lt)。□ 用法:兩條從相距 δ 的起點出發的軌跡,其距離 φ(t) = ‖x(t) − y(t)‖ 滿足 φ(t) ≤ δ + L∫₀ᵗ φ,所以 φ(t) ≤ δ e^(Lt)——起點的差距至多指數放大。Euler 的舊誤差被「帶著走」時放大的就是這個倍數;離散版只是把積分換成和、把 e^(Lh) 換成 (1+hL)。

回到彎道:直覺對了一半,數字對不上

用界估一次。v=16.7v=16.7 m/s、R=2000R=2000 m,x¨=v2/R0.139\|\ddot x\|=v^2/R\approx0.139 m/s²,全程 T188T\approx188 s,所以 x¨dt26\int\|\ddot x\|dt\approx26 m/s。h=30h=30h2×26390\tfrac{h}{2}\times26\approx390 m。LL 是場對位置的敏感度:方向隨位置改變的速率約 v/R0.008v/R\approx0.008 /s,LT1.6LT\approx1.6eLT4.8e^{LT}\approx4.8,上界約 1900 m。

真實跑出來(下一節)是 486 公尺。所以:直覺的「幾十公尺」錯了一個數量級——隱含的假設是「每步只偏一點」,忘了六步會累積、還會被帶著放大;「直路不會錯」則完全正確,因為 x¨=0\ddot x=0。上界 1900 m 抓到了正確的數量級,但 eLTe^{LT} 把它撐大了四倍——這正是理論常見的處境:它告訴你誤差隨哪些量、以什麼速率變化,但常數要靠實作校準。

而那個直覺回答不了的問題現在有答案:更新間隔改成 10 秒,hh 縮三倍,誤差也縮三倍(不是九倍);要縮九倍得每 3.3 秒更新一次。

還有一件容易忘的假設:x¨\ddot x加速度,不只是轉彎。直路上如果你一直在加減速,x¨0\ddot x\ne0,Euler 也會錯——只是錯在沿路的前後位置,不是偏出路面。

回到彎道:跑一次,再把 hh 調到壞掉

import numpy as np
R, v = 2000.0, 60/3.6
T = (np.pi/2)*R/v                          # 走完四分之一圓的時間
def u(x): r = np.hypot(*x); return v*np.array([-x[1], x[0]])/r   # 沿圓切線
def euler(h):
    N = int(round(T/h)); x = np.array([R, 0.0])
    for _ in range(N): x = x + (T/N)*u(x)
    return np.linalg.norm(x - np.array([0.0, R]))   # 與真實終點 (0, R) 的距離
for h in [30, 10, 3, 1]: print(h, round(euler(h)))
# 486, 161, 49, 17:h 縮三倍、誤差縮三倍——一階

四個數字每次縮三倍,符合「一階」。再把 hh 往另一邊推:對 x˙=kx\dot x=-kx(往路中央拉回的修正力,kk 大表示拉得急),Euler 一步是 xn+1=(1hk)xnx_{n+1}=(1-hk)x_nhk<1hk<1 時單調收斂;1<hk<21<hk<2 時來回震盪但仍收斂;hk>2hk>21hk>1|1-hk|>1,每步放大,發散——這對應到界裡的 (1+hL)N(1+hL)^N 真的爆掉,界不再「太悲觀」,而是老實地預告了災難。步長不只影響精度,還影響穩定。

先消化一下

想一想

一台掃地機器人每 0.5 秒讀一次自己的速度、中間假設等速直走,藉此估計自己的位置。哪種情況下它的位置估計會最準?

想一想

你把導航的更新間隔從 30 秒改成 10 秒,發現終點誤差從 486 m 降到 161 m。若再改成 1 秒,最合理的預期是:

想一想

誤差界 h2eLT ⁣x¨dt\tfrac{h}{2}e^{LT}\!\int\|\ddot x\|dt 裡,若場的 Lipschitz 常數 LL 很大(方向對位置極敏感,例如在岔路口附近),會發生什麼?

參考文獻

  1. Hairer, E., Nørsett, S. P., Wanner, G. Solving Ordinary Differential Equations I: Nonstiff Problems. Springer, 2nd ed., 1993.(第 I.7 節與第 II.3 節:Euler 法的局部與全域誤差、Grönwall 型的累積論證。)
  2. Butcher, J. C. Numerical Methods for Ordinary Differential Equations. Wiley, 3rd ed., 2016.(第 2 章:Euler 法的收斂與穩定性。)
  3. Grönwall, T. H. Note on the Derivatives with Respect to a Parameter of the Solutions of a System of Differential Equations. Annals of Mathematics 20(4), 1919.(Grönwall 不等式的原始出處。)