M3.2 一千片葉子在亂流裡:Fokker–Planck 方程式
本篇重用M0.1閘門的進出:Divergence 與通量·M3.1水流加亂流:SDE 是加了噪聲的 ODE·M2.2站內人數變化 = 進 − 出:Continuity Equation·M0.2導航的三十秒:Taylor 展開與「假設直線」
一千片葉子,有亂流的河
M2.2 問過:一群葉子在沒有亂流的河裡,分佈怎麼演化?答案是 continuity equation——不追葉子,每個位置記帳「進 − 出」。M3.1 則把亂流加回河裡,但只追了一片葉子,看到它的路變成一把扇子。
現在兩件事合起來:一千片葉子,從橋下一小塊水面出發,河裡既有主流也有亂流。一分鐘後,這一千片葉子的分佈是什麼樣子?
先用直覺回答,並寫下你有多確定。多數人會說「整團被主流帶到下游,同時被亂流攤開、變寬變扁」。這個描述是對的。但它沒有回答:變寬的速度是多少?主流不均勻(有地方快有地方慢)時,「搬」與「攤」會怎麼互相影響?以及——能不能像 continuity equation 那樣,寫下一條分佈自己滿足的方程式,不用模擬一千片葉子就算出答案?
課堂提問Q1
翻成數學。「一千片葉子的分佈」是什麼物件?把 continuity equation 的「進 − 出」記帳法套到有亂流的河上,多出了什麼?
先想一想,再展開看整理後的答案
這一題可以直接對上前面的語言:一千片葉子是從 抽出的樣本,每片各自照 SDE 走(M3.1),一分鐘後它們是 的樣本。我們要的是密度 隨時間的方程式。
記帳法還能用,但一塊地磚上的人數變化現在有兩種來源。第一種和以前一樣:drift 讓葉子以確定的速度穿過地磚的邊,淨流入是 。第二種是新的:亂流讓葉子隨機跨過邊界——隔壁地磚葉子多,隨機跳過來的就多;這塊葉子多,隨機跳出去的也多。所以亂流造成的淨流入,正比於「隔壁比我多多少」,也就是密度的二階導數(M0.2:一點與它兩側平均值的差,就是二階導數)。密度凹下去的地方(局部低谷)會被填、凸起來的地方(局部高峰)會被削——這就是「攤平」。
所以要找的方程式長得像:,第一項是 ,第二項與 (Laplacian,二階導數的總和)成正比,係數要算。
先看畫面:一坨顏料在流水裡
把一千片葉子想成一滴顏料滴進河裡。主流把整滴顏料搬到下游——形狀跟著水流變形,這是 M2.2 已經處理過的事。亂流則讓顏料滲開:邊緣越來越淡、範圍越來越大,中心的濃度越來越低,但顏料的總量不變。
兩件事同時發生:被搬走的同時也在滲開。關鍵是它們可以分開算再加起來——因為在一小步 內,drift 的位移是 、噪聲的位移是 ,兩者對密度的影響到 的一階是各自獨立的。
寫成數學:一步之內,搬與攤各貢獻多少
先算攤的係數。一維、:在一小步 內每片葉子被隨機推 ,所以新密度是舊密度與 的 convolution:
把 對 Taylor 展開(M0.2)到二階、再對 取期望: 殺掉一階項, 留下二階項:
兩邊減 、除以 、令 :。這就是「攤」的係數:。
搬的部分就是 continuity equation(M2.2):。一步之內兩者的貢獻都是 ,交叉影響是更高階的小量,所以相加:
這就是 Fokker–Planck 方程式(也叫 forward Kolmogorov equation)[1–4]。它是 SDE 的「守格子」版本:M3.1 追一片葉子,這裡直接演化整個分佈——正如 M2.2 之於 M2.0。
代入驗證的技巧。 解 PDE 很難,但驗證一個候選解很容易:把它代進兩邊,看是否相等。純 Brownian motion(、)從原點出發,M3.0 說 。驗證:
右邊 。✓ 兩邊逐項相等, 確實是解。這個技巧會反覆用到:不推導、只驗證。
展開細節有 drift 的驗證:f = c 常數、g 常數,p_t = N(ct, g²t)
記 m = ct、s = g²t,p = (2πs)^(−1/2) exp(−(x−m)²/(2s))。 ∂ₓp = −((x−m)/s)·p;∂ₓₓp = (−1/s + (x−m)²/s²)·p。 ∂ₜp:對 log p 微分,m′ = c、s′ = g²,得 ∂ₜp = [−g²/(2s) + c(x−m)/s + g²(x−m)²/(2s²)]·p。 右邊:−∂ₓ(cp) = c(x−m)/s·p;(g²/2)∂ₓₓp = [−g²/(2s) + g²(x−m)²/(2s²)]·p。相加恰為 ∂ₜp。✓ 這也是 SDE 那一篇「x_T ~ N(x₀+cT, g²T)」的 PDE 版證明。
順帶一提:(g²/2)Δp = ∇·((g²/2)∇p) = ∇·(p·(g²/2)∇log p),所以 Fokker–Planck 也可以寫成 continuity equation 的形式 ∂ₜp + ∇·(p·u) = 0,u = f − (g²/2)∇log p。同一條 p_t,可以由「SDE 的一群葉子」產生,也可以由「ODE 的一群葉子」產生——這是 continuity equation 那一篇「同一分佈路徑有多個速度場」的又一個例子,只是這次其中一個速度場藏在噪聲裡。
回到河面:直覺對了,多了三個數字
起點問題的答案:分佈的中心被 帶著走,寬度的 variance 以 的速率線性增加(標準差按 長),總質量守恆。直覺的「搬過去同時攤開」完全正確;它補不上的是攤開的速率 、以及「攤開」的精確意思——密度的 Laplacian 為正的地方上升、為負的地方下降,所以高峰被削、低谷被填,多峰的分佈會被抹成單峰。
主流不均勻時兩項會互動:收攏的 drift()把分佈壓窄,噪聲把它攤寬,最後可能達到平衡——下一篇(M3.3)就是這件事。
依賴的假設:每一步的噪聲零均值、variance 有限,而且更高階的矩不會太大(Taylor 展開裡 以上的項才會消失得夠快。Gaussian 只是最常見的例子,不是必要條件——下面的 quiz c 會問這件事;真正會壞的是重尾噪聲,偶爾一跳很遠、 無限,二階項就不夠描述),以及 不依賴 (否則二階項變成 , 要進到微分裡面,見 M3.1 展開框的 Itô 討論)。
回到河面:直方圖對上 PDE,再換一種噪聲
import numpy as np
rng = np.random.default_rng(0)
c, g, T, h = 0.5, 0.3, 60.0, 0.1
x = np.zeros(20000)
for _ in range(int(T/h)): # 一千片(這裡兩萬片)葉子各走 SDE
x = x + h*c + g*np.sqrt(h)*rng.standard_normal(x.size)
hist, edges = np.histogram(x, bins=60, density=True)
mid = 0.5*(edges[1:] + edges[:-1])
p_theory = np.exp(-(mid - c*T)**2/(2*g**2*T))/np.sqrt(2*np.pi*g**2*T) # Fokker–Planck 的解
print(np.abs(hist - p_theory).max()) # 小,且隨葉子數增加而縮小
# 違反假設:把 standard_normal 換成 standard_cauchy,直方圖尾巴變厚、方差不收斂
直方圖與 Fokker–Planck 的解 重合。把噪聲換成 Cauchy(重尾),直方圖的尾巴遠比 Gaussian 厚、中央反而更尖,而且加更多葉子也不會收斂到任何 Gaussian——「攤平」不再由二階導數描述。
先消化一下
參考文獻
- Särkkä, S., Solin, A. Applied Stochastic Differential Equations. Cambridge University Press, 2019.(第 5 章:Fokker–Planck 方程式的推導與 Gaussian 情形的 closed form。)
- Pavliotis, G. A. Stochastic Processes and Applications: Diffusion Processes, the Fokker–Planck and Langevin Equations. Springer, 2014.(第 4 章:forward Kolmogorov 方程式與其性質。)
- Risken, H. The Fokker–Planck Equation: Methods of Solution and Applications. Springer, 2nd ed., 1989.(專書;第 4 章推導,第 5 章一維解法。)
- Gardiner, C. Stochastic Methods: A Handbook for the Natural and Social Sciences. Springer, 4th ed., 2009.(第 3、4 章:從 Kramers–Moyal 展開到 Fokker–Planck;本篇 Taylor 展開的來源。)