M3.2 14 分鐘閱讀 2026年9月

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 的「進 − 出」記帳法套到有亂流的河上,多出了什麼?

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

這一題可以直接對上前面的語言:一千片葉子是從 p0p_0 抽出的樣本,每片各自照 SDE dx=fdt+gdWdx=f\,dt+g\,dW 走(M3.1),一分鐘後它們是 p60p_{60} 的樣本。我們要的是密度 p(x,t)p(x,t) 隨時間的方程式。

記帳法還能用,但一塊地磚上的人數變化現在有兩種來源。第一種和以前一樣:drift ff 讓葉子以確定的速度穿過地磚的邊,淨流入是 (fp)-\nabla\cdot(fp)。第二種是新的:亂流讓葉子隨機跨過邊界——隔壁地磚葉子多,隨機跳過來的就多;這塊葉子多,隨機跳出去的也多。所以亂流造成的淨流入,正比於「隔壁比我多多少」,也就是密度的二階導數M0.2:一點與它兩側平均值的差,就是二階導數)。密度凹下去的地方(局部低谷)會被填、凸起來的地方(局部高峰)會被削——這就是「攤平」。

所以要找的方程式長得像:tp=(drift 搬)+(噪聲攤)\partial_tp=(\text{drift 搬})+(\text{噪聲攤}),第一項是 (fp)-\nabla\cdot(fp),第二項與 Δp=p\Delta p=\nabla\cdot\nabla p(Laplacian,二階導數的總和)成正比,係數要算。

先看畫面:一坨顏料在流水裡

把一千片葉子想成一滴顏料滴進河裡。主流把整滴顏料到下游——形狀跟著水流變形,這是 M2.2 已經處理過的事。亂流則讓顏料滲開:邊緣越來越淡、範圍越來越大,中心的濃度越來越低,但顏料的總量不變。

兩件事同時發生:被搬走的同時也在滲開。關鍵是它們可以分開算再加起來——因為在一小步 hh 內,drift 的位移是 fhfh、噪聲的位移是 ghεg\sqrt h\,\varepsilon,兩者對密度的影響到 hh 的一階是各自獨立的。

寫成數學:一步之內,搬與攤各貢獻多少

先算的係數。一維、f=0f=0:在一小步 hh 內每片葉子被隨機推 ghεg\sqrt h\,\varepsilon,所以新密度是舊密度與 N(0,g2h)\mathcal N(0,g^2h) 的 convolution:

p(x,t+h)=Eε[p(xghε,t)].p(x,t+h)=\mathbb E_\varepsilon\big[p(x-g\sqrt h\,\varepsilon,\,t)\big].

p(xy)p(x-y)yy Taylor 展開(M0.2)到二階、再對 ε\varepsilon 取期望:E[ε]=0\mathbb E[\varepsilon]=0 殺掉一階項,E[ε2]=1\mathbb E[\varepsilon^2]=1 留下二階項:

p(x,t+h)=pghE[ε]xp+g2h2E[ε2]xxp+O(h3/2)=p+g2h2xxp+O(h3/2).p(x,t+h)=p-\,g\sqrt h\,\mathbb E[\varepsilon]\,\partial_xp+\tfrac{g^2h}{2}\,\mathbb E[\varepsilon^2]\,\partial_{xx}p+O(h^{3/2}) =p+\tfrac{g^2h}{2}\,\partial_{xx}p+O(h^{3/2}).

兩邊減 pp、除以 hh、令 h0h\to0tp=g22xxp\partial_tp=\tfrac{g^2}{2}\partial_{xx}p。這就是「攤」的係數:g2/2g^2/2\square

的部分就是 continuity equation(M2.2):tp=x(fp)\partial_tp=-\partial_x(fp)。一步之內兩者的貢獻都是 O(h)O(h),交叉影響是更高階的小量,所以相加:

  tp=x(fp)+g22xxp  (多維: tp=(fp)+g22Δp\boxed{\;\partial_tp=-\partial_x(f\,p)+\tfrac{g^2}{2}\,\partial_{xx}p\;}\qquad \text{(多維:}\ \partial_tp=-\nabla\cdot(f\,p)+\tfrac{g^2}{2}\,\Delta p\text{)}

這就是 Fokker–Planck 方程式(也叫 forward Kolmogorov equation)[1–4]。它是 SDE 的「守格子」版本:M3.1 追一片葉子,這裡直接演化整個分佈——正如 M2.2 之於 M2.0

代入驗證的技巧。 解 PDE 很難,但驗證一個候選解很容易:把它代進兩邊,看是否相等。純 Brownian motion(f=0f=0g=1g=1)從原點出發,M3.0pt=N(0,t)p_t=\mathcal N(0,t)。驗證:

p=12πtex2/2t,xp=xtp,xxp=(1t+x2t2)p,tp=(12t+x22t2)p.p=\frac{1}{\sqrt{2\pi t}}e^{-x^2/2t},\qquad \partial_xp=-\frac{x}{t}\,p,\qquad \partial_{xx}p=\Big(-\frac1t+\frac{x^2}{t^2}\Big)p,\qquad \partial_tp=\Big(-\frac{1}{2t}+\frac{x^2}{2t^2}\Big)p .

右邊 12xxp=(12t+x22t2)p=tp\tfrac12\partial_{xx}p=\big(-\tfrac{1}{2t}+\tfrac{x^2}{2t^2}\big)p=\partial_tp。✓ 兩邊逐項相等,N(0,t)\mathcal N(0,t) 確實是解。這個技巧會反覆用到:不推導、只驗證。

展開細節有 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 那一篇「同一分佈路徑有多個速度場」的又一個例子,只是這次其中一個速度場藏在噪聲裡。

回到河面:直覺對了,多了三個數字

起點問題的答案:分佈的中心被 ff 帶著走,寬度的 variance 以 g2g^2 的速率線性增加(標準差按 gtg\sqrt t 長),總質量守恆。直覺的「搬過去同時攤開」完全正確;它補不上的是攤開的速率 g2/2g^2/2、以及「攤開」的精確意思——密度的 Laplacian 為正的地方上升、為負的地方下降,所以高峰被削、低谷被填,多峰的分佈會被抹成單峰

主流不均勻時兩項會互動:收攏的 drift(xf<0\partial_xf<0)把分佈壓窄,噪聲把它攤寬,最後可能達到平衡——下一篇(M3.3)就是這件事。

依賴的假設:每一步的噪聲零均值、variance 有限,而且更高階的矩不會太大(Taylor 展開裡 E[ε3]\mathbb E[\varepsilon^3] 以上的項才會消失得夠快。Gaussian 只是最常見的例子,不是必要條件——下面的 quiz c 會問這件事;真正會壞的是重尾噪聲,偶爾一跳很遠、E[ε2]\mathbb E[\varepsilon^2] 無限,二階項就不夠描述),以及 gg 不依賴 xx(否則二階項變成 12xx(g2p)\tfrac12\partial_{xx}(g^2p)gg 要進到微分裡面,見 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 的解 N(cT,g2T)\mathcal N(cT,g^2T) 重合。把噪聲換成 Cauchy(重尾),直方圖的尾巴遠比 Gaussian 厚、中央反而更尖,而且加更多葉子也不會收斂到任何 Gaussian——「攤平」不再由二階導數描述。

先消化一下

想一想

一杯靜水裡滴一滴墨水(沒有攪動)。三十秒後墨水的濃度分佈,該用哪個工具描述?

想一想

你把 pt=N(0,t)p_t=\mathcal N(0,t) 代進 tp=12xxp\partial_tp=\tfrac12\partial_{xx}p 驗證成功。若改用 pt=N(0,t2)p_t=\mathcal N(0,t^2)(標準差按 tt 長)代進去:

想一想

把 SDE 的 Gaussian noise 換成同樣 variance 的均勻分佈噪聲(每步 ghεg\sqrt h\,\varepsilonε\varepsilon 均勻於 [3,3][-\sqrt3,\sqrt3]),Fokker–Planck 方程式:

參考文獻

  1. Särkkä, S., Solin, A. Applied Stochastic Differential Equations. Cambridge University Press, 2019.(第 5 章:Fokker–Planck 方程式的推導與 Gaussian 情形的 closed form。)
  2. Pavliotis, G. A. Stochastic Processes and Applications: Diffusion Processes, the Fokker–Planck and Langevin Equations. Springer, 2014.(第 4 章:forward Kolmogorov 方程式與其性質。)
  3. Risken, H. The Fokker–Planck Equation: Methods of Solution and Applications. Springer, 2nd ed., 1989.(專書;第 4 章推導,第 5 章一維解法。)
  4. Gardiner, C. Stochastic Methods: A Handbook for the Natural and Social Sciences. Springer, 4th ed., 2009.(第 3、4 章:從 Kramers–Moyal 展開到 Fokker–Planck;本篇 Taylor 展開的來源。)