微分方程计算方法初步

7 小时前
2

微分方程计算方法初步

📑 目录

  1. 微分方程数值解概览
  2. Euler 法与 Taylor 展开法
  3. Runge-Kutta 方法族
  4. Predictor-Corrector 多步法
  5. 微分方程组与 Lorenz 混沌
  6. 高阶微分方程的降阶处理
  7. 刚性微分方程(Stiff ODE)
  8. 边值问题与打靶法(Shooting)
  9. Numerov 方法
  10. Schrödinger 方程数值求解
  11. Green 函数与 Wronskian
  12. 有限差分法(Finite Difference)
  13. 应用实例:TOV 方程与中子星
  14. 总结对比表

1. 微分方程数值解概览

两大问题类型

类型 给定条件 物理例子 主要方法
初值问题 (IVP) 已知 y(t0)y(t_0), 求后续 行星轨道、电路暂态 Euler, RK, Adams
边值问题 (BVP) 已知两边界条件 量子束缚态、热传导稳态 打靶法, 有限差分

💡 物理直觉:初值问题是"知道现在,推演未来"(动力学),边值问题是"知道两端,反推中间"(稳态分布)。


2. Euler 法与 Taylor 展开法

2.1 Euler 法 — 最朴素的一阶方法

核心思想:用切线近似曲线。

对于一阶 ODE:

dydt=f(t,y),y(t0)=y0\frac{dy}{dt} = f(t, y), \quad y(t_0) = y_0

等间距离散化:取步长 hh,定义 ti=t0+iht_i = t_0 + i \cdot h,$i = 0,1,2,...,N$

Euler 递推公式

yi+1=yi+hf(ti,yi)y_{i+1} = y_i + h \cdot f(t_i, y_i)

说人话:下一步 = 当前值 + 步长 × 当前斜率。就像盲人走路,每步朝着当前方向走固定距离,完全不看前面弯不弯。

📐 数值例子: y=2y+1, y(0)=1y' = -2y + 1,\ y(0)=1

精确解: y(t)=0.5+0.5e2ty(t) = 0.5 + 0.5e^{-2t}

# Euler 法手算演示,h=0.2
import numpy as np

def f(t, y): return -2*y + 1
y0, h = 1.0, 0.2
t_vals = np.arange(0, 1.01, h)
y_euler = [y0]

for i in range(len(t_vals)-1):
    y_next = y_euler[-1] + h * f(t_vals[i], y_euler[-1])
    y_euler.append(y_next)


观察:Euler 法在 t=1.0t=1.0 时误差约 12%。步长太大!

2.2 高阶 Taylor 展开法

递推公式

yi+1=yi+hyi+h22!yi+h33!yi+y_{i+1} = y_i + h y'_i + \frac{h^2}{2!}y''_i + \frac{h^3}{3!}y'''_i + \cdots

局部截断误差 (Local Truncation Error)

  • Euler 法(1阶 Taylor):$O(h^2)$ 每步
  • kk 阶 Taylor:$O(h^{k+1})$ 每步

y=2y+1y'=-2y+1 用二阶 Taylor

y=2y=2(2y+1)=4y2y'' = -2y' = -2(-2y+1) = 4y-2

# 二阶 Taylor,同一步长 h=0.2
y_taylor2 = [y0]
for i in range(len(t_vals)-1):
    y = y_taylor2[-1]
    yp = -2*y + 1          # y'
    ypp = 4*y - 2          # y''
    y_next = y + h*yp + h**2/2 * ypp
    y_taylor2.append(y_next)

# t=1.0: y≈0.559592 → 误差从 12% 降到约 1.4%!
tt 精确解 Euler (h=0.2) 二阶 Taylor (h=0.2) Euler (h=0.1)
0.4 0.7247 0.7200 0.7244 0.7568
0.8 0.6009 0.5968 0.6003 0.6334
1.0 0.5677 0.4982 0.5596 0.5838

💡 结论:提高阶数比缩小步长更有效!二阶 Taylor 用 h=0.2h=0.2 的精度已经超过 Euler 用 h=0.1h=0.1


3. Runge-Kutta 方法族

在科学计算、航空航天轨道计算、乃至游戏物理引擎中,90% 以上的常微分方程初值问题,其底层默认的算法都是龙格-库塔法。

3.1 核心思想

Taylor 展开法需要手动求各阶导数

(麻烦! + 阶数越高 手动求偏导的项数呈现指数级爆炸 —— 工程上不可以承受的 + 导数无具体解析解 需要数值手段)

Runge-Kutta 的巧思:

能否不求导,仅仅是通过在当前步长的不同位置 多算几次斜率,然后将其“加权平均”,来拼凑出来和Taylor一样的高阶精度效果

用多点函数值的组合来模拟高阶导数效果,无需显式求导。 我们无需去求那些复杂的偏导数,我们只需要在区间 [ti,ti+1][t_{i}, t_{i+1}] 之间 ,多选取

一般形式

yi+1=yi+hj=1sbjkj y_{i+1} = y_i + h \sum_{j=1}^{s} b_j k_j

其中 k就是我们在这一步里,通过不同位置的“试探”得到的斜率。每一个k,都依赖于前面已经算出来的斜率

kj=f(ti+cjh, yi+hl=1j1ajlkl) k_j = f\left(t_i + c_j h,\ y_i + h \sum_{l=1}^{j-1} a_{jl} k_l\right)

这些系数 ajla_{jl}bjb_jcjc_j 是通过与泰勒级数展开进行复杂的代数比对(Taylor matching)强行解出来

3.2 二阶 Runge-Kutta:中点法与改进 Euler 法

🔹 中点法 (Midpoint Method) 先探路 再迈步

k1=f(ti,yi) k2=f(ti+h2, yi+h2k1) yi+1=yi+hk2 k_1 = f(t_i, y_i) \\ \space \\ k_2 = f\left(t_i + \frac{h}{2},\ y_i + \frac{h}{2}k_1\right) \\ \space \\ y_{i+1} = y_i + h \cdot k_2

说人话:先用半步走到的中点斜率,再拿这个斜率走一整步。比直接走精度高了一阶。

k1就是 起点的斜率 , k2就是中点处预测的斜率

你蒙着眼睛在一座山上往下走。如果直接用起点斜率 k1k_1 走一整步(欧拉法),由于山坡在弯曲,你很容易偏离轨道。 中点法的策略是:我先用起点的斜率 k1k_1 试探着走半步h2\frac{h}{2}),到达“中点”。我测出中点处的斜率 k2k_2,然后我回到起点,手持这个中点斜率 k2k_2 跨出完整的一整步。由于中点斜率代表了这一小段路程的“平均趋势”,这样跨出的一步,精度直接从一阶跃升到了二阶(全局误差 O(h2)O(h^2))!

🔹 改进 Euler 法 (Modified Euler / Heun's Method)

k1=f(ti,yi) k2=f(ti+h, yi+hk1) yi+1=yi+h2(k1+k2) k_1 = f(t_i, y_i) \\ \space \\ k_2 = f(t_i + h,\ y_i + h k_1) \\ \space \\ y_{i+1} = y_i + \frac{h}{2}(k_1 + k_2)

说人话:取"起点斜率"和"用 Euler 走到终点的斜率"的平均。相当于预测-校正。

中点法 是去中间探路 而 改进的欧拉法 则是两头兼顾

可以先用 起点的斜率 k1 算一个“预期的终点”,接着 我们测量这个预期终点处斜率k2,最后将起点与终点的斜率进行算术平均 得出最终迈步的依据 —— 预测-校正

Predictor- Corrector 思想!!!

3.3 四阶 Runge-Kutta (RK4) — 工业标准

公式(经典 RK4)

k1=f(ti,yi) k2=f(ti+h2, yi+h2k1) k3=f(ti+h2, yi+h2k2) k4=f(ti+h, yi+hk3) yi+1=yi+h6(k1+2k2+2k3+k4)\begin{aligned} k_1 &= f(t_i, y_i) \\ \space \\ k_2 &= f\left(t_i + \frac{h}{2},\ y_i + \frac{h}{2}k_1\right) \\ \space \\ k_3 &= f\left(t_i + \frac{h}{2},\ y_i + \frac{h}{2}k_2\right) \\ \space \\ k_4 &= f(t_i + h,\ y_i + h k_3) \\ \space \\ y_{i+1} &= y_i + \frac{h}{6}(k_1 + 2k_2 + 2k_3 + k_4) \end{aligned}

本质上其代数逻辑 与 Simpson 积分 惊人的相似!!!

与数值积分里的 Simpson 公式权重16,46,16\frac{1}{6}, \frac{4}{6}, \frac{1}{6})极其相似!

k1k_1(起点斜率)权重为 1/61/6

k2,k3k_2, k_3(两个在中点不同试探方式得到的斜率)权重合起来是 4/64/6

k4k_4(终点斜率)权重为 1/61/6

本质

是常微分方程数值解和数值积分 在深层代数逻辑上 合流的必然结果

一、 终极源头:将 ODE 降维成“纯积分”

要理解为什么它们会发生碰撞,我们先做一个数学实验: 假设我们有一个一阶常微分方程: dydt=f(t,y),y(ti)=yi\frac{dy}{dt} = f(t, y), \quad y(t_i) = y_i

如果我们对两边在区间 [ti,ti+h][t_i, t_i + h] 上进行精确求导积分,由微积分基本定理可以得到: y(ti+h)y(ti)=titi+hf(t,y(t))dty(t_i + h) - y(t_i) = \int_{t_i}^{t_i+h} f(t, y(t)) dt

所以,下一步的精确值一定是: yi+1=yi+titi+hf(t,y(t))dty_{i+1} = y_i + \int_{t_i}^{t_i+h} f(t, y(t)) dt

这是一个无法直接计算的积分,因为被积函数里的 y(t)y(t) 本身就是我们正在求解的未知数!

降维假设:如果斜率不依赖于 yy

现在,我们假设一种最简单、最特殊的物理场景:斜率 f(t,y)f(t, y) 仅仅与时间 tt 有关,与 yy 无关。 比如,一个物体的加速度只随时间变化: dydt=f(t)\frac{dy}{dt} = f(t)

此时,上面的方程直接变成了一个纯积分问题yi+1=yi+titi+hf(t)dty_{i+1} = y_i + \int_{t_i}^{t_i+h} f(t) dt


二、 辛普森公式(Simpson's Rule)是如何处理这个积分的?

如果要计算 titi+hf(t)dt\int_{t_i}^{t_i+h} f(t) dt,辛普森公式的思路是:在区间 [ti,ti+h][t_i, t_i+h] 里,取三个等距点来做二次抛物线插值:

  1. 左端点tit_i,对应的函数值为 f(ti)f(t_i)
  2. 中点ti+h2t_i + \frac{h}{2},对应的函数值为 f(ti+h2)f(t_i + \frac{h}{2})
  3. 右端点ti+ht_i + h,对应的函数值为 f(ti+h)f(t_i + h)

根据辛普森公式的求积权重($1:4:1$ 比例),这个积分的近似值为: titi+hf(t)dth6[f(ti)+4f(ti+h2)+f(ti+h)]\int_{t_i}^{t_i+h} f(t) dt \approx \frac{h}{6} \left[ f(t_i) + 4 f\left(t_i + \frac{h}{2}\right) + f(t_i + h) \right]

因此,我们得到下一步的预测值为:

yi+1yi+h6[f(ti)+4f(ti+h2)+f(ti+h)]y_{i+1} \approx y_i + \frac{h}{6} \left[ f(t_i) + 4 f\left(t_i + \frac{h}{2}\right) + f(t_i + h) \right]


三、 经典 RK4 此时在干什么?

现在,我们把相同的“降维假设”($f$ 不依赖于 yy)代入到经典 RK4 的公式里,看看它会退化成什么样3

  1. 计算 k1k_1(起点斜率)k1=f(ti,yi)    k1=f(ti)k_1 = f(t_i, y_i) \implies k_1 = f(t_i)
  2. 计算 k2k_2(中点试探斜率 1)k2=f(ti+h2, yi+h2k1)    k2=f(ti+h2)k_2 = f\left(t_i + \frac{h}{2},\ y_i + \frac{h}{2}k_1\right) \implies k_2 = f\left(t_i + \frac{h}{2}\right)
  3. 计算 k3k_3(中点试探斜率 2)k3=f(ti+h2, yi+h2k2)    k3=f(ti+h2)k_3 = f\left(t_i + \frac{h}{2},\ y_i + \frac{h}{2}k_2\right) \implies k_3 = f\left(t_i + \frac{h}{2}\right)
  4. 计算 k4k_4(终点试探斜率)k4=f(ti+h, yi+hk3)    k4=f(ti+h)k_4 = f(t_i + h,\ y_i + h k_3) \implies k_4 = f(t_i + h)

因为 ffyy 无关,我们惊奇地发现:在中点算出来的两个试探斜率 k2k_2k3k_3 居然完全相等了2 k2=k3=f(ti+h2)k_2 = k_3 = f\left(t_i + \frac{h}{2}\right)

现在,我们把它们代入 RK4 的最后一步加权平均式中: yi+1=yi+h6(k1+2k2+2k3+k4)=yi+h6[f(ti)+2f(ti+h2)+2f(ti+h2)+f(ti+h)]=yi+h6[f(ti)+4f(ti+h2)+f(ti+h)]\begin{aligned} y_{i+1} &= y_i + \frac{h}{6} (k_1 + 2k_2 + 2k_3 + k_4) \\ &= y_i + \frac{h}{6} \left[ f(t_i) + 2f\left(t_i + \frac{h}{2}\right) + 2f\left(t_i + \frac{h}{2}\right) + f(t_i + h) \right] \\ &= y_i + \frac{h}{6} \left[ f(t_i) + 4f\left(t_i + \frac{h}{2}\right) + f(t_i + h) \right] \end{aligned}

两套公式完全合二为一,分毫不差!


四、 这个“巧合”背后的深刻含义
1. RK4 是 辛普森公式在 ODE 领域的“非线性推广”
  • 辛普森公式:只能处理函数只与时间 tt 相关的静态积分
  • RK4:当函数不仅与 tt 有关,还与当前状态 yy 动态耦合时,RK4 通过巧妙的多步迭代预测(用 k1k_1 预测出 yi+h2k1y_{i} + \frac{h}{2}k_1,进而算 k2k_2;再用 k2k_2 修正出 yi+h2k2y_{i} + \frac{h}{2}k_2,进而算 k3k_3),在非线性空间里重建了辛普森公式所需要的“中点斜率”(在泰勒展开的代数精度上,RK4 巧妙地通过这两步试探,将非线性耦合带来的高阶误差一项一项全部抵消掉,从而在代数精度上达到了与辛普森公式完全匹配的四阶精度 O(h4)O(h^4)

  • 因此,RK4 本质上就是“带有动态状态修正的辛普森积分”

补充

一、 核心痛点:辛普森公式需要“真正的中点斜率”

如果我们把 ODE 的精确积分形式写出来: yi+1=yi+titi+hf(t,y(t))dty_{i+1} = y_i + \int_{t_i}^{t_i+h} f(t, y(t)) dt 如果我们想用辛普森公式来算这个积分,我们需要知道三个值:

  1. 起点斜率: f(ti,yi)f(t_i, y_i) —— 已知,就是 k1k_1
  2. 终点斜率: f(ti+h,y(ti+h))f(t_i + h, y(t_i+h)) —— 未知,因为我们不知道终点的精确状态 y(ti+h)y(t_i+h)
  3. 中点真正的斜率f(ti+h2,y(ti+h2))f\left(t_i + \frac{h}{2}, y\left(t_i + \frac{h}{2}\right)\right) —— 未知,因为我们不知道中点精确状态 y(ti+h2)y\left(t_i + \frac{h}{2}\right)

因为我们不知道中点精确状态 y(ti+h2)y\left(t_i + \frac{h}{2}\right),所以我们无法直接算出真正的中点斜率


二、 RK4 是如何用 k1,k2,k3,k4k_1, k_2, k_3, k_4 逐步逼近这个“真中点斜率”的?

RK4 的精妙之处在于,它通过三次接力(预测-校正-再预测),把这个“真正的中点斜率”给强行“套”了出来。

根据泰勒展开,函数 y(t)y(t)tit_i 处的半步($\frac{h}{2}$)展开为: y(ti+h2)=y(ti)+(h2)y(ti)+12!(h2)2y(ti)+O(h3)y\left(t_i + \frac{h}{2}\right) = y(t_i) + \left(\frac{h}{2}\right) y'(t_i) + \frac{1}{2!} \left(\frac{h}{2}\right)^2 y''(t_i) + O(h^3) 整理一下系数: y(ti+h2)=yi+h2y(ti)+h28y(ti)+O(h3)— (式 A)y\left(t_i + \frac{h}{2}\right) = y_i + \frac{h}{2} y'(t_i) + \frac{h^2}{8} y''(t_i) + O(h^3) \quad \text{--- (式 A)}

因为我们的常微分方程是 y=f(t,y)y' = f(t, y),所以利用全微分(链式法则)求二阶导数 yy''y(t)=ddt[f(t,y(t))]=ft+fydydt=ft+fyfy''(t) = \frac{d}{dt}[f(t, y(t))] = \frac{\partial f}{\partial t} + \frac{\partial f}{\partial y} \cdot \frac{dy}{dt} = f_t + f_y f (为了书写简洁,我们用偏导数简写 ft=ftf_t = \frac{\partial f}{\partial t},$fy = \frac{\partial f}{\partial y}$,且它们都在 $(ti, y_i)$ 处取值)。

y(ti)=fy'(t_i) = fy(ti)=ft+fyfy''(t_i) = f_t + f_y f 代回 (式 A),得到真正的中点状态的精确展开式y(ti+h2)=yi+h2f+h28(ft+fyf)+O(h3)— (式 A-精确版)y\left(t_i + \frac{h}{2}\right) = y_i + \frac{h}{2} f + \frac{h^2}{8} (f_t + f_y f) + O(h^3) \quad \text{--- (式 A-精确版)}

在 RK4 中,我们第一步用 k1k_1(即 ff)预测的中点状态为: ymid,1=yi+h2k1=yi+h2fy_{\text{mid}, 1} = y_i + \frac{h}{2} k_1 = y_i + \frac{h}{2} f

我们用它去计算 k2k_2k2=f(ti+h2, yi+h2f)k_2 = f\left(t_i + \frac{h}{2}, \ y_i + \frac{h}{2} f\right)

这是一个二元函数 f(t,y)f(t, y)。我们将它在点 (ti,yi)(t_i, y_i) 处进行二元泰勒展开。 二元泰勒展开公式为: f(ti+Δt, yi+Δy)=f(ti,yi)+Δtft+Δyfy+O(Δ2)f(t_i + \Delta t, \ y_i + \Delta y) = f(t_i, y_i) + \Delta t \cdot f_t + \Delta y \cdot f_y + O(\Delta^2)

k2k_2 的计算中:

  • 时间增量 Δt=h2\Delta t = \frac{h}{2}
  • 状态增量 Δy=h2f\Delta y = \frac{h}{2} f

代入二元泰勒展开式: k2=f+(h2)ft+(h2f)fy+O(h2)k_2 = f + \left(\frac{h}{2}\right) f_t + \left(\frac{h}{2} f\right) f_y + O(h^2) 提取公因子 h2\frac{h}{2} k2=f+h2(ft+fyf)+O(h2)— (式 B)k_2 = f + \frac{h}{2} (f_t + f_y f) + O(h^2) \quad \text{--- (式 B)}

现在,我们用这个含有更高阶误差信息的 k2k_2 重新代入到第二次中点预测值 ymid,2y_{\text{mid}, 2} 中: ymid,2=yi+h2k2y_{\text{mid}, 2} = y_i + \frac{h}{2} k_2

(式 B) 的展开式直接代入到 k2k_2 的位置: ymid,2=yi+h2[f+h2(ft+fyf)+O(h2)]y_{\text{mid}, 2} = y_i + \frac{h}{2} \left[ f + \frac{h}{2} (f_t + f_y f) + O(h^2) \right]

把括号外面的 h2\frac{h}{2} 乘进去: ymid,2=yi+h2f+h24(ft+fyf)+O(h3)— (式 C)y_{\text{mid}, 2} = y_i + \frac{h}{2} f + \frac{h^2}{4} (f_t + f_y f) + O(h^3) \quad \text{--- (式 C)}

在 RK4 公式中,第三步是在第二次中点预测状态 ymid,2y_{\text{mid}, 2} 处计算斜率: k3=f(ti+h2, ymid,2)k_3 = f\left(t_i + \frac{h}{2}, \ y_{\text{mid}, 2}\right)

我们将 (式 C) 的结果: ymid,2=yi+h2f+h24(ft+fyf)+O(h3)y_{\text{mid}, 2} = y_i + \frac{h}{2} f + \frac{h^2}{4} (f_t + f_y f) + O(h^3) 代入到 k3k_3 中: k3=f(ti+h2, yi+h2f+h24(ft+fyf)+O(h3))k_3 = f\left(t_i + \frac{h}{2}, \ y_i + \frac{h}{2} f + \frac{h^2}{4} (f_t + f_y f) + O(h^3)\right)

此时,我们需要对二元函数 f(ti+Δt, yi+Δy)f(t_i + \Delta t, \ y_i + \Delta y) 进行泰勒展开,其中:

  • 时间增量 Δt=h2\Delta t = \frac{h}{2}
  • 状态增量 Δy=h2f+h24(ft+fyf)+O(h3)\Delta y = \frac{h}{2} f + \frac{h^2}{4} (f_t + f_y f) + O(h^3)

为了计算到 O(h2)O(h^2) 项,我们的二元泰勒展开需要保留到二阶偏导数项: f(ti+Δt, yi+Δy)=f+Δtft+Δyfy+12[Δt2ftt+2ΔtΔyfty+Δy2fyy]+O(h3)f(t_i + \Delta t, \ y_i + \Delta y) = f + \Delta t f_t + \Delta y f_y + \frac{1}{2} \left[ \Delta t^2 f_{tt} + 2 \Delta t \Delta y f_{ty} + \Delta y^2 f_{yy} \right] + O(h^3) (注:这里所有的偏导数 ft,fy,ftt,fty,fyyf_t, f_y, f_{tt}, f_{ty}, f_{yy} 都在 (ti,yi)(t_i, y_i) 处取值)。

我们分项把它们代入展开:

  • 一阶时间项Δtft=h2ft\Delta t f_t = \frac{h}{2} f_t
  • 一阶状态项Δyfy=[h2f+h24(ft+fyf)+O(h3)]fy=h2ffy+h24fy(ft+fyf)+O(h3)\Delta y f_y = \left[ \frac{h}{2} f + \frac{h^2}{4} (f_t + f_y f) + O(h^3) \right] f_y = \frac{h}{2} f f_y + \frac{h^2}{4} f_y (f_t + f_y f) + O(h^3)
  • 二阶偏导数项(由于我们只需要保留到 O(h2)O(h^2),所以 Δy\Delta y 里的 O(h2)O(h^2) 项在平方后会变成 O(h3)O(h^3) 以上,可以省去):

    12Δt2ftt=12(h2)2ftt=h28ftt\frac{1}{2} \Delta t^2 f_{tt} = \frac{1}{2} \left(\frac{h}{2}\right)^2 f_{tt} = \frac{h^2}{8} f_{tt} 122ΔtΔyfty=(h2)(h2f+O(h2))fty=h24ffty\frac{1}{2} \cdot 2 \Delta t \Delta y f_{ty} = \left(\frac{h}{2}\right) \left(\frac{h}{2} f + O(h^2)\right) f_{ty} = \frac{h^2}{4} f f_{ty} 12Δy2fyy=12(h2f+O(h2))2fyy=h28f2fyy\frac{1}{2} \Delta y^2 f_{yy} = \frac{1}{2} \left(\frac{h}{2} f + O(h^2)\right)^2 f_{yy} = \frac{h^2}{8} f^2 f_{yy}

在 RK4 中,我们用最新的精细中点斜率 k3k_3 跨出完整的一整步,预测终点的状态 yendy_{\text{end}}yend=yi+hk3y_{\text{end}} = y_i + h k_3

(式 D) 代入 yendy_{\text{end}} 的计算中: yend=yi+h(f+h2(ft+fyf)+O(h2))y_{\text{end}} = y_i + h \left( f + \frac{h}{2} (f_t + f_y f) + O(h^2) \right)hh 乘进去,得到预测的终点状态yend=yi+hf+h22(ft+fyf)+O(h3)— (式 E)y_{\text{end}} = y_i + h f + \frac{h^2}{2} (f_t + f_y f) + O(h^3) \quad \text{--- (式 E)}

现在,我们在终点计算最后一个斜率 k4k_4k4=f(ti+h, yend)=f(ti+h, yi+hf+h22(ft+fyf)+O(h3))k_4 = f(t_i + h, \ y_{\text{end}}) = f\left(t_i + h, \ y_i + h f + \frac{h^2}{2} (f_t + f_y f) + O(h^3)\right)

我们再次对二元函数进行展开,此时:

  • 时间增量 Δt=h\Delta t = h
  • 状态增量 Δy=hf+h22(ft+fyf)+O(h3)\Delta y = h f + \frac{h^2}{2} (f_t + f_y f) + O(h^3)

代入二元泰勒展开公式: f(ti+Δt, yi+Δy)=f+Δtft+Δyfy+12[Δt2ftt+2ΔtΔyfty+Δy2fyy]+O(h3)f(t_i + \Delta t, \ y_i + \Delta y) = f + \Delta t f_t + \Delta y f_y + \frac{1}{2} \left[ \Delta t^2 f_{tt} + 2 \Delta t \Delta y f_{ty} + \Delta y^2 f_{yy} \right] + O(h^3)

  • 一阶时间项Δtft=hft\Delta t f_t = h f_t
  • 一阶状态项Δyfy=[hf+h22(ft+fyf)+O(h3)]fy=hffy+h22fy(ft+fyf)+O(h3)\Delta y f_y = \left[ h f + \frac{h^2}{2} (f_t + f_y f) + O(h^3) \right] f_y = h f f_y + \frac{h^2}{2} f_y (f_t + f_y f) + O(h^3)
  • 二阶偏导数项(省去 O(h3)O(h^3) 阶): 12Δt2ftt=12h2ftt\frac{1}{2} \Delta t^2 f_{tt} = \frac{1}{2} h^2 f_{tt} 122ΔtΔyfty=h(hf+O(h2))fty=h2ffty\frac{1}{2} \cdot 2 \Delta t \Delta y f_{ty} = h (h f + O(h^2)) f_{ty} = h^2 f f_{ty} 12Δy2fyy=12(hf+O(h2))2fyy=12h2f2fyy\frac{1}{2} \Delta y^2 f_{yy} = \frac{1}{2} (h f + O(h^2))^2 f_{yy} = \frac{1}{2} h^2 f^2 f_{yy}
  • hh 的一阶项hft+hffy=h(ft+fyf)h f_t + h f f_y = h (f_t + f_y f)
  • hh 的二阶项h22fy(ft+fyf)+h22ftt+h2ffty+h22f2fyy\frac{h^2}{2} f_y (f_t + f_y f) + \frac{h^2}{2} f_{tt} + h^2 f f_{ty} + \frac{h^2}{2} f^2 f_{yy} 我们通分并提取公因子 h22\frac{h^2}{2}h22[ftt+2ffty+f2fyy+fy(ft+fyf)]\frac{h^2}{2} \left[ f_{tt} + 2 f f_{ty} + f^2 f_{yy} + f_y (f_t + f_y f) \right]

因此,我们得到了 k4k_4 的完整展开式k4=f+h(ft+fyf)+h22[ftt+2ffty+f2fyy+fy(ft+fyf)]+O(h3)— (式 F)k_4 = f + h (f_t + f_y f) + \frac{h^2}{2} \left[ f_{tt} + 2 f f_{ty} + f^2 f_{yy} + f_y (f_t + f_y f) \right] + O(h^3) \quad \text{--- (式 F)}

现在,四个斜率 k1k_1、$k2$、$k3$、$k_4$ 已经全部列阵完毕。我们把它们毫无保留地写在一起:

  1. k1=fk_1 = f
  2. k2=f+h2(ft+fyf)+h28[ftt+2ffty+f2fyy]+O(h3)k_2 = f + \frac{h}{2} (f_t + f_y f) + \frac{h^2}{8} \left[ f_{tt} + 2 f f_{ty} + f^2 f_{yy} \right] + O(h^3)
  3. k3=f+h2(ft+fyf)+h28[ftt+2ffty+f2fyy+2fy(ft+fyf)]+O(h3)k_3 = f + \frac{h}{2} (f_t + f_y f) + \frac{h^2}{8} \left[ f_{tt} + 2 f f_{ty} + f^2 f_{yy} + 2 f_y (f_t + f_y f) \right] + O(h^3)
  4. k4=f+h(ft+fyf)+h22[ftt+2ffty+f2fyy+fy(ft+fyf)]+O(h3)k_4 = f + h (f_t + f_y f) + \frac{h^2}{2} \left[ f_{tt} + 2 f f_{ty} + f^2 f_{yy} + f_y (f_t + f_y f) \right] + O(h^3)

现在,我们将它们代入 RK4 最终的加权表达式: yi+1=yi+h6(k1+2k2+2k3+k4)y_{i+1} = y_i + \frac{h}{6} (k_1 + 2k_2 + 2k_3 + k_4)

为了让你看清楚每一部分是如何抵消和合并的,我们把求和部分 k1+2k2+2k3+k4k_1 + 2k_2 + 2k_3 + k_4hh 的阶数 拆成三部分算:

  1. 零阶项(常数 ff 的加权)

零阶项和=f+2(f)+2(f)+f=6f\text{零阶项和} = f + 2(f) + 2(f) + f = 6f 代回最终公式中,再乘以外面的 h6\frac{h}{6}h6(6f)=hf\frac{h}{6} (6f) = \mathbf{h f}

  1. 一阶项(含 ft+fyff_t + f_y f 的加权)

一阶项和=0+2(h2(ft+fyf))+2(h2(ft+fyf))+h(ft+fyf)=h(ft+fyf)+h(ft+fyf)+h(ft+fyf)=3h(ft+fyf)\begin{aligned} \text{一阶项和} &= 0 + 2 \left( \frac{h}{2} (f_t + f_y f) \right) + 2 \left( \frac{h}{2} (f_t + f_y f) \right) + h (f_t + f_y f) \\ &= h (f_t + f_y f) + h (f_t + f_y f) + h (f_t + f_y f) \\ &= 3h (f_t + f_y f) \end{aligned} 代回最终公式中,再乘以外面的 h6\frac{h}{6}h6[3h(ft+fyf)]=h22(ft+fyf)\frac{h}{6} \left[ 3h (f_t + f_y f) \right] = \mathbf{\frac{h^2}{2} (f_t + f_y f)}

  1. 二阶项(含 ftt,fty,fyyf_{tt}, f_{ty}, f_{yy}fy(ft+fyf)f_y(f_t+f_y f) 的加权)

这里是整个代数魔术最核心的高潮。我们把 2k22k_2、$2k3$ 和 $k4$ 的二阶项展开相加:

  • 对于不含 fyf_y 的偏导数组合 [ftt+2ffty+f2fyy]\left[ f_{tt} + 2 f f_{ty} + f^2 f_{yy} \right](我们简记为 PP): P 的系数和=2(h28P)+2(h28P)+h22P=h24P+h24P+h22P=h2P\begin{aligned} P \text{ 的系数和} &= 2 \left( \frac{h^2}{8} P \right) + 2 \left( \frac{h^2}{8} P \right) + \frac{h^2}{2} P \\ &= \frac{h^2}{4} P + \frac{h^2}{4} P + \frac{h^2}{2} P \\ &= h^2 P \end{aligned}
  • 对于带有交叉项 fy(ft+fyf)f_y (f_t + f_y f) 的部分(我们简记为 QQ):
    • 2k22k_2 里面没有这一项(系数为 0);
    • 2k32k_3 里面含有这一项,系数为 2×h28×2=h222 \times \frac{h^2}{8} \times 2 = \frac{h^2}{2}
    • k4k_4 里面含有这一项,系数为 h22\frac{h^2}{2}Q 的系数和=0+h22Q+h22Q=h2Q\begin{aligned} Q \text{ 的系数和} &= 0 + \frac{h^2}{2} Q + \frac{h^2}{2} Q \\ &= h^2 Q \end{aligned}

PPQQ 合并: 二阶项和=h2(P+Q)=h2[ftt+2ffty+f2fyy+fy(ft+fyf)]\text{二阶项和} = h^2 (P + Q) = h^2 \left[ f_{tt} + 2 f f_{ty} + f^2 f_{yy} + f_y (f_t + f_y f) \right]

代回最终公式中,乘以外面的 h6\frac{h}{6}h6(h2[ftt+2ffty+f2fyy+fy(ft+fyf)])=h36[ftt+2ffty+f2fyy+fy(ft+fyf)]\frac{h}{6} \left( h^2 \left[ f_{tt} + 2 f f_{ty} + f^2 f_{yy} + f_y (f_t + f_y f) \right] \right) = \mathbf{\frac{h^3}{6} \left[ f_{tt} + 2 f f_{ty} + f^2 f_{yy} + f_y (f_t + f_y f) \right]}

现在,我们将上面三个部分的加权计算结果全部拼起来,得到 RK4 计算得到的数值解展开yi+1=yi+hf+h22(ft+fyf)+h36[ftt+2ffty+f2fyy+fy(ft+fyf)]+O(h4)— (RK4 的展开)y_{i+1} = y_i + h f + \frac{h^2}{2} (f_t + f_y f) + \frac{h^3}{6} \left[ f_{tt} + 2 f f_{ty} + f^2 f_{yy} + f_y (f_t + f_y f) \right] + O(h^4) \quad \text{--- (RK4 的展开)}

接着,我们写出真实的微分方程精确解 y(ti+h)y(t_i+h) 展开到 h3h^3真实泰勒展开y(ti+h)=yi+hy(ti)+h22y(ti)+h36y(ti)+O(h4)y(t_i + h) = y_i + h y'(t_i) + \frac{h^2}{2} y''(t_i) + \frac{h^3}{6} y'''(t_i) + O(h^4)

我们用全微分(链式法则)求出精确解的各阶导数:

  1. 一阶导数y(ti)=fy'(t_i) = f
  2. 二阶导数y(ti)=ft+fyfy''(t_i) = f_t + f_y f
  3. 三阶导数:对 y=ft+fyfy'' = f_t + f_y f 再次关于时间 tt 求导: y(ti)=ddt[ft(t,y)+fy(t,y)f(t,y)]=(ftt+ftyy)+(fyt+fyyy)f+fy(ft+fyf)=ftt+ftyf+(fty+fyyf)f+fy(ft+fyf)(因 y=f,fyt=fty)=ftt+2ffty+f2fyy+fy(ft+fyf)\begin{aligned} y'''(t_i) &= \frac{d}{dt} \left[ f_t(t, y) + f_y(t, y) \cdot f(t, y) \right] \\ &= (f_{tt} + f_{ty} y') + (f_{yt} + f_{yy} y') f + f_y (f_t + f_y f) \\ &= f_{tt} + f_{ty} f + (f_{ty} + f_{yy} f) f + f_y (f_t + f_y f) \quad (\text{因 } y'=f, f_{yt}=f_{ty}) \\ &= f_{tt} + 2 f f_{ty} + f^2 f_{yy} + f_y (f_t + f_y f) \end{aligned}

把这些精确导数代入精确解的泰勒展开式: y(ti+h)=yi+hf+h22(ft+fyf)+h36[ftt+2ffty+f2fyy+fy(ft+fyf)]+O(h4)— (精确泰勒展开)y(t_i + h) = y_i + h f + \frac{h^2}{2} (f_t + f_y f) + \frac{h^3}{6} \left[ f_{tt} + 2 f f_{ty} + f^2 f_{yy} + f_y (f_t + f_y f) \right] + O(h^4) \quad \text{--- (精确泰勒展开)}

🏁 惊人的结论:

现在,请将 (RK4 的展开)(精确泰勒展开) 放在一起进行对比。

它们在 hh 的零阶项、一阶项、二阶项、三阶项(甚至包含复杂的交叉偏导数 ftyf_{ty}fy(ft+fyf)f_y(f_t+f_y f))上,所有的代数项和系数全部一模一样,分毫不差!

这也就意味着,通过这四个斜率的巧妙试探和最终 1:2:2:11:2:2:1 的加权平均:

  • 局部截断误差中的 h1,h2,h3,h4h^1, h^2, h^3, h^4 阶误差全部被完全消去(抵消)
  • 残余的第一项误差出现在 h5h^5 阶,即局部截断误差为 O(h5)O(h^5)
  • 经过区间累积,全局累积误差为 O(h4)O(h^4)
精度奇迹的代数根源

为什么 RK4 只需要 4 个点就能达到全局四阶精度 ?

  • 因为它退化后的辛普森公式本身就是一个具有“代数奇迹”的方法:辛普森公式虽然只用了 33 个点(相当于二次多项式插值),但由于对称性抵消,它对任意三次多项式的积分都是绝对精确的!
  • 这种“免费赠送一阶精度”的对称性优势,通过 k2k_2k3k_3 在中点的双重采样,被完美遗传给了 RK4。这使得 RK4 拥有极高的代数稳定性,成为了不需要高阶导数就能运行的性价比之王。

局部截断误差O(h5)O(h^5),全局误差 O(h4)O(h^4)

🧮 完整数值示例:用 RK4 解 y=2y+1, y(0)=1y' = -2y+1,\ y(0)=1

import numpy as np
import matplotlib.pyplot as plt

def f(t, y):
    return -2*y + 1

def rk4_step(f, t, y, h):
    k1 = f(t, y)
    k2 = f(t + h/2, y + h/2 * k1)
    k3 = f(t + h/2, y + h/2 * k2)
    k4 = f(t + h,   y + h * k3)
    return y + h/6 * (k1 + 2*k2 + 2*k3 + k4)

# 参数
y0, h = 1.0, 0.2
t_vals = np.arange(0, 2.01, h)
y_rk4 = [y0]
for i in range(len(t_vals)-1):
    y_rk4.append(rk4_step(f, t_vals[i], y_rk4[-1], h))

# 精确解
y_exact = 0.5 + 0.5 * np.exp(-2 * t_vals)

# 结果对比
print(f"{'t':>6}  {'RK4':>10}  {'Exact':>10}  {'Error':>12}")
for t, yr, ye in zip(t_vals, y_rk4, y_exact):
    print(f"{t:6.2f}  {yr:10.6f}  {ye:10.6f}  {abs(yr-ye):12.2e}")

输出(部分)

t RK4 精确解 误差
0.40 0.724665 0.724664 4.5e-07
0.80 0.600896 0.600895 4.8e-07
1.00 0.567669 0.567668 5.0e-07
1.60 0.520423 0.520423 5.7e-07
2.00 0.509158 0.509158 5.9e-07

💡 惊人的精度:RK4 用 h=0.2h=0.2,误差约 5×1075\times 10^{-7}。Euler 法要达到同样精度需要步长约 10710^{-7} 级别!

3.4 自适应步长:Runge-Kutta-Fehlberg (RKF45)

核心想法:每步同时计算 4 阶和 5 阶结果,利用差值估计误差,自动调整步长。

  • RKF: 局部截断误差 O(h6)O(h^6)(5阶),可用作误差控制
  • Runge-Kutta-Verner: 达到 6 阶

伪代码

while t < t_end:
    计算 RK4 和 RK5 结果 y4, y5
    误差 err = |y5 - y4|
    if err > tolerance:
        h = h/2; 重算
    else if err < tolerance/10:
        h = 2*h  (放大步长)
    接受结果,前进

💡 物理直觉:解变化慢的地方(平坦区)自动放大步长,变化快的地方(陡峭区)自动缩小步长。就像开车——高速路上踩油门,拐弯处踩刹车。


4. Predictor-Corrector 多步法

4.1 与 Runge-Kutta 的对比

RK4 就是在单步内多点探路 然后代数消去高阶项 达到精度

P-C 预测校正多步法 则是 通过 “不抛弃历史 用插值和积分 重构过去与未来” 来实现 长距离、高效率的稳定计算!!!

RK4 的思路:为了近似这个积分,在当前区间 [ti,ti+h][t_i, t_i+h] 里临时计算 4 个测试点的斜率 k1,k2,k3,k4k_1, k_2, k_3, k_4,把旧的信息全部扔掉。这需要每前进一步就重复计算 4 次 f(t,y)f(t,y)

多步法的思路:既然我们在前面已经算过了 ti,ti1,ti2t_i, t_{i-1}, t_{i-2} 等处的斜率,为什么还要在每一步里重复去算新测试点?我们直接利用这些现成的历史斜率,用多项式把 f(t,y(t))f(t, y(t)) 在过去及当下的曲线“描绘(插值)”出来,然后直接对这个多项式进行精确求积分!

特性 Runge-Kutta 多步法 (Adams 族)
步数依赖 单步法(只用上一步) 多步法(用前面多步)
计算量 每步多次函数求值 每步 1-2 次函数求值
起步 自动起步 需 RK4 起步(算前几步)
典型应用 通用 长时间演化(如 TDDFT)

4.2 Adams-Bashforth (显式预测)

三步显式公式

yi+1=yi+h12[23f(ti,yi)16f(ti1,yi1)+5f(ti2,yi2)]y_{i+1} = y_i + \frac{h}{12}\left[23f(t_i, y_i) - 16f(t_{i-1}, y_{i-1}) + 5f(t_{i-2}, y_{i-2})\right]

具体推导

我们要推导三步显式公式: yi+1=yi+h12[23f(ti,yi)16f(ti1,yi1)+5f(ti2,yi2)]y_{i+1} = y_i + \frac{h}{12}\left[23f(t_i, y_i) - 16f(t_{i-1}, y_{i-1}) + 5f(t_{i-2}, y_{i-2})\right]

1. 待定系数法的泰勒展开设定

假设时间步长 hh 是恒定的(即 titi1=ht_i - t_{i-1} = htiti2=2ht_i - t_{i-2} = 2h)。为了简洁,我们将已知的历史斜率记为:

  • fi=f(ti,yi)f_i = f(t_i, y_i)
  • fi1=f(ti1,yi1)f_{i-1} = f(t_{i-1}, y_{i-1})
  • fi2=f(ti2,yi2)f_{i-2} = f(t_{i-2}, y_{i-2})

我们希望寻找三个系数 a,b,ca, b, c,使得以下线性组合在代数上具有最高精度: y(ti+1)y(ti)+h[afi+bfi1+cfi2]— (式 1)y(t_{i+1}) \approx y(t_i) + h \left[ a f_i + b f_{i-1} + c f_{i-2} \right] \quad \text{--- (式 1)}

由于 y(t)=f(t,y(t))y'(t) = f(t, y(t)),我们把这三项写成导数形式:

  • fi=y(ti)f_i = y'(t_i)
  • fi1=y(ti1)f_{i-1} = y'(t_{i-1})
  • fi2=y(ti2)f_{i-2} = y'(t_{i-2})
2. 将所有历史点在当下的 tit_i 处进行泰勒展开

我们将 y(ti+1)y(t_{i+1}),以及历史导数 y(ti1)y'(t_{i-1})、$y'(t{i-2})$ 全部在 $ti$ 处展开到 h3h^3 阶:

  1. 左端点 y(ti+1)y(t_{i+1})tit_i 处的展开(向前走一步 hh): y(ti+1)=y(ti)+hy(ti)+h22y(ti)+h36y(ti)+O(h4)— (式 2)y(t_{i+1}) = y(t_i) + h y'(t_i) + \frac{h^2}{2} y''(t_i) + \frac{h^3}{6} y'''(t_i) + O(h^4) \quad \text{--- (式 2)}
  2. 历史一阶导数 y(ti1)y'(t_{i-1})tit_i 处的展开(向后退一步 h-h): y(ti1)=y(ti)hy(ti)+h22y(ti)+O(h3)— (式 3)y'(t_{i-1}) = y'(t_i) - h y''(t_i) + \frac{h^2}{2} y'''(t_i) + O(h^3) \quad \text{--- (式 3)}
  3. 历史一阶导数 y(ti2)y'(t_{i-2})tit_i 处的展开(向后退两步 2h-2h): y(ti2)=y(ti)(2h)y(ti)+(2h)22y(ti)+O(h3)=y(ti)2hy(ti)+2h2y(ti)+O(h3)— (式 4)y'(t_{i-2}) = y'(t_i) - (2h) y''(t_i) + \frac{(2h)^2}{2} y'''(t_i) + O(h^3) = y'(t_i) - 2h y''(t_i) + 2h^2 y'''(t_i) + O(h^3) \quad \text{--- (式 4)}
3. 代入待定系数式,合并同类项

现在,我们将 (式 3)(式 4) 代回我们的待定系数公式 (式 1) 的右端项: 右端项=y(ti)+h[ay(ti)+by(ti1)+cy(ti2)]\text{右端项} = y(t_i) + h \left[ a y'(t_i) + b y'(t_{i-1}) + c y'(t_{i-2}) \right] 将展开式代入: 右端项=y(ti)+h[ay(ti)+b(y(ti)hy(ti)+h22y(ti))+c(y(ti)2hy(ti)+2h2y(ti))]+O(h4)\text{右端项} = y(t_i) + h \left[ a y'(t_i) + b \left( y'(t_i) - h y''(t_i) + \frac{h^2}{2} y'''(t_i) \right) + c \left( y'(t_i) - 2h y''(t_i) + 2h^2 y'''(t_i) \right) \right] + O(h^4)

我们按 y(ti),y(ti),y(ti)y'(t_i), y''(t_i), y'''(t_i) 的阶数进行提取与合并: 右端项=y(ti)+h(a+b+c)y(ti)+h2(b2c)y(ti)+h3(12b+2c)y(ti)+O(h4)— (式 5)\text{右端项} = y(t_i) + h (a + b + c) y'(t_i) + h^2 (-b - 2c) y''(t_i) + h^3 \left( \frac{1}{2}b + 2c \right) y'''(t_i) + O(h^4) \quad \text{--- (式 5)}

4. 对比系数,建立线性方程组

为了让数值公式 (式 5) 与真实的泰勒展开 (式 2) 完美契合,我们强制令它们的前三项系数完全相等1

  1. hy(ti)h y'(t_i) 的系数a+b+c=1— (方程 1)a + b + c = 1 \quad \text{--- (方程 1)}
  2. h2y(ti)h^2 y''(t_i) 的系数b2c=12    b+2c=12— (方程 2)-b - 2c = \frac{1}{2} \implies b + 2c = -\frac{1}{2} \quad \text{--- (方程 2)}
  3. h3y(ti)h^3 y'''(t_i) 的系数12b+2c=16— (方程 3)\frac{1}{2}b + 2c = \frac{1}{6} \quad \text{--- (方程 3)}
5. 求解方程组,见证系数的诞生

我们用 (方程 2) 减去 (方程 3)(b+2c)(12b+2c)=1216(b + 2c) - \left(\frac{1}{2}b + 2c\right) = -\frac{1}{2} - \frac{1}{6} 12b=23    b=43=1612\frac{1}{2}b = -\frac{2}{3} \implies b = -\frac{4}{3} = -\frac{16}{12}

b=43b = -\frac{4}{3} 代回 (方程 2)43+2c=12    2c=4312=56    c=512-\frac{4}{3} + 2c = -\frac{1}{2} \implies 2c = \frac{4}{3} - \frac{1}{2} = \frac{5}{6} \implies c = \frac{5}{12}

b=1612b = -\frac{16}{12}c=512c = \frac{5}{12} 代入 (方程 1)a1612+512=1    a1112=1    a=2312a - \frac{16}{12} + \frac{5}{12} = 1 \implies a - \frac{11}{12} = 1 \implies a = \frac{23}{12}

6. 最终合成

把求得的 a=2312,b=1612,c=512a = \frac{23}{12}, b = -\frac{16}{12}, c = \frac{5}{12} 代回 (式 1),提取公因子 h12\frac{h}{12}1yi+1=yi+h12[23fi16fi1+5fi2]y_{i+1} = y_i + \frac{h}{12}\left[23 f_i - 16 f_{i-1} + 5 f_{i-2}\right]

三步显式 Adams-Bashforth 公式,完美推导完成!

(同理,若将泰勒展开推进到 O(h4)O(h^4) 阶并引入四个历史点 fi,fi1,fi2,fi3f_i, f_{i-1}, f_{i-2}, f_{i-3},用完全一样的方法即可推导得出四步显式公式的系数: 5524,5924,3724,924\frac{55}{24}, -\frac{59}{24}, \frac{37}{24}, -\frac{9}{24}

四步显式公式

yi+1=yi+h24[55fi59fi1+37fi29fi3]y_{i+1} = y_i + \frac{h}{24}\left[55f_i - 59f_{i-1} + 37f_{i-2} - 9f_{i-3}\right]

4.3 Adams-Moulton (隐式校正)

隐式:在公式中,包含了 f(ti+1,yi+1)f(t_{i+1},y_{i+1}) 这意味着:为了算出下一时刻的状态 yi+1y_{i+1} 我们必须在等式右边提前知道下一时刻的状态 yi+1y_{i+1} !!! 这个在非线性方程中是无法直接进行求解的!

三步隐式公式

yi+1=yi+h24[9f(ti+1,yi+1)+19f(ti,yi)5f(ti1,yi1)+f(ti2,yi2)]y_{i+1} = y_i + \frac{h}{24}\left[9f(t_{i+1}, y_{i+1}) + 19f(t_i, y_i) - 5f(t_{i-1}, y_{i-1}) + f(t_{i-2}, y_{i-2})\right]

代数推导

为了推导它的系数,我们假设:

y(ti+1)y(ti)+h[αf(ti+1,y(ti+1))+βfi+γfi1+δfi2]— (式 6) y(t_{i+1}) \approx y(t_i) + h \left[ \alpha f(t_{i+1}, y(t_{i+1})) + \beta f_i + \gamma f_{i-1} + \delta f_{i-2} \right] \quad \text{--- (式 6)}

我们同样把它们写成导数形式,并将所有项在当前点 tit_i 处展开到 h4h^4 阶(因为多引入了一个点 ti+1t_{i+1},精度会再提升一阶):

  1. 左端点 y(ti+1)y(t_{i+1})tit_i 处的展开(向前走 hh): y(ti+1)=y(ti)+hy(ti)+h22y(ti)+h36y(ti)+h424y(4)(ti)+O(h5)— (式 7)y(t_{i+1}) = y(t_i) + h y'(t_i) + \frac{h^2}{2} y''(t_i) + \frac{h^3}{6} y'''(t_i) + \frac{h^4}{24} y^{(4)}(t_i) + O(h^5) \quad \text{--- (式 7)}
  2. 未来一阶导数 y(ti+1)y'(t_{i+1})tit_i 处的展开(向前走 hh): y(ti+1)=y(ti)+hy(ti)+h22y(ti)+h36y(4)(ti)+O(h4)— (式 8)y'(t_{i+1}) = y'(t_i) + h y''(t_i) + \frac{h^2}{2} y'''(t_i) + \frac{h^3}{6} y^{(4)}(t_i) + O(h^4) \quad \text{--- (式 8)}
  3. 当前一阶导数 y(ti)y'(t_i)y(ti)=y(ti)y'(t_i) = y'(t_i)
  4. 历史一阶导数 y(ti1)y'(t_{i-1})tit_i 处的展开(向后退 h-h): y(ti1)=y(ti)hy(ti)+h22y(ti)h36y(4)(ti)+O(h4)— (式 9)y'(t_{i-1}) = y'(t_i) - h y''(t_i) + \frac{h^2}{2} y'''(t_i) - \frac{h^3}{6} y^{(4)}(t_i) + O(h^4) \quad \text{--- (式 9)}
  5. 历史一阶导数 y(ti2)y'(t_{i-2})tit_i 处的展开(向后退 2h-2h): y(ti2)=y(ti)2hy(ti)+2h2y(ti)4h33y(4)(ti)+O(h4)— (式 10)y'(t_{i-2}) = y'(t_i) - 2h y''(t_i) + 2h^2 y'''(t_i) - \frac{4h^3}{3} y^{(4)}(t_i) + O(h^4) \quad \text{--- (式 10)}
代入待定系数式,合并同类项

(式 8)(式 9)(式 10) 代入 (式 6) 的右侧括号中: 右端项=y(ti)+h[α(y(ti)+hy(ti)+h22y(ti)+h36y(4)(ti))+βy(ti)+γ(y(ti)hy(ti)+h22y(ti)h36y(4)(ti))+δ(y(ti)2hy(ti)+2h2y(ti)4h33y(4)(ti))]\begin{aligned} \text{右端项} = y(t_i) + h \Big[ &\alpha \left( y'(t_i) + h y''(t_i) + \frac{h^2}{2} y'''(t_i) + \frac{h^3}{6} y^{(4)}(t_i) \right) \\ + &\beta y'(t_i) \\ + &\gamma \left( y'(t_i) - h y''(t_i) + \frac{h^2}{2} y'''(t_i) - \frac{h^3}{6} y^{(4)}(t_i) \right) \\ + &\delta \left( y'(t_i) - 2h y''(t_i) + 2h^2 y'''(t_i) - \frac{4h^3}{3} y^{(4)}(t_i) \right) \Big] \end{aligned}

按各阶导数项归类合并: 右端项=y(ti)+h(α+β+γ+δ)y(ti)+h2(αγ2δ)y(ti)+h3(12α+12γ+2δ)y(ti)+h4(16α16γ43δ)y(4)(ti)+O(h5)— (式 11)\begin{aligned} \text{右端项} = y(t_i) &+ h (\alpha + \beta + \gamma + \delta) y'(t_i) \\ &+ h^2 (\alpha - \gamma - 2\delta) y''(t_i) \\ &+ h^3 \left( \frac{1}{2}\alpha + \frac{1}{2}\gamma + 2\delta \right) y'''(t_i) \\ &+ h^4 \left( \frac{1}{6}\alpha - \frac{1}{6}\gamma - \frac{4}{3}\delta \right) y^{(4)}(t_i) + O(h^5) \quad \text{--- (式 11)} \end{aligned}

对比精确展开式 (式 7),建立方程组

对比 (式 11)(式 7) 的对应系数:

  1. hy(ti)h y'(t_i) 对应项α+β+γ+δ=1— (方程 I)\alpha + \beta + \gamma + \delta = 1 \quad \text{--- (方程 I)}
  2. h2y(ti)h^2 y''(t_i) 对应项αγ2δ=12— (方程 II)\alpha - \gamma - 2\delta = \frac{1}{2} \quad \text{--- (方程 II)}
  3. h3y(ti)h^3 y'''(t_i) 对应项12α+12γ+2δ=16    α+γ+4δ=13— (方程 III)\frac{1}{2}\alpha + \frac{1}{2}\gamma + 2\delta = \frac{1}{6} \implies \alpha + \gamma + 4\delta = \frac{1}{3} \quad \text{--- (方程 III)}
  4. h4y(4)(ti)h^4 y^{(4)}(t_i) 对应项16α16γ43δ=124    αγ8δ=14— (方程 IV)\frac{1}{6}\alpha - \frac{1}{6}\gamma - \frac{4}{3}\delta = \frac{1}{24} \implies \alpha - \gamma - 8\delta = \frac{1}{4} \quad \text{--- (方程 IV)}
求解隐式方程组

(方程 II) 减去 (方程 IV)(αγ2δ)(αγ8δ)=1214(\alpha - \gamma - 2\delta) - (\alpha - \gamma - 8\delta) = \frac{1}{2} - \frac{1}{4} 6δ=14    δ=1246\delta = \frac{1}{4} \implies \delta = \frac{1}{24}

δ=124\delta = \frac{1}{24} 代回 (方程 II)αγ224=12    αγ=1424— (方程 A)\alpha - \gamma - \frac{2}{24} = \frac{1}{2} \implies \alpha - \gamma = \frac{14}{24} \quad \text{--- (方程 A)}

δ=124\delta = \frac{1}{24} 代入 (方程 III)α+γ+424=13    α+γ=424— (方程 B)\alpha + \gamma + \frac{4}{24} = \frac{1}{3} \implies \alpha + \gamma = \frac{4}{24} \quad \text{--- (方程 B)}

联立 (方程 A)(方程 B) 相加: 2α=1824    α=9242\alpha = \frac{18}{24} \implies \alpha = \frac{9}{24}

联立 (方程 A)(方程 B) 相减: 2γ=1024    γ=5242\gamma = -\frac{10}{24} \implies \gamma = -\frac{5}{24}

将已求得的 α,γ,δ\alpha, \gamma, \delta 代入 (方程 I)β\beta924+β524+124=1    β+524=1    β=1924\frac{9}{24} + \beta - \frac{5}{24} + \frac{1}{24} = 1 \implies \beta + \frac{5}{24} = 1 \implies \beta = \frac{19}{24}

我们得到了极其完美的系数: α=924,β=1924,γ=524,δ=124\alpha = \frac{9}{24}, \quad \beta = \frac{19}{24}, \quad \gamma = -\frac{5}{24}, \quad \delta = \frac{1}{24}

代回 (式 6) 中:

yi+1=yi+h24[9f(ti+1,yi+1)+19f(ti,yi)5f(ti1,yi1)+f(ti2,yi2)]y_{i+1} = y_i + \frac{h}{24}\left[9f(t_{i+1}, y_{i+1}) + 19f(t_i, y_i) - 5f(t_{i-1}, y_{i-1}) + f(t_{i-2}, y_{i-2})\right]

三步隐式 Adams-Moulton 公式,完美推导完成!

4.4 PECE 模式(预测-求值-校正-求值)

流程:
1. Predict: 用 Adams-Bashforth (显式) 预测 y_{i+1}^(0)
2. Evaluate: 计算 f(t_{i+1}, y_{i+1}^(0))
3. Correct: 用 Adams-Moulton (隐式) 校正得到 y_{i+1}
4. Evaluate: 重新计算 f(t_{i+1}, y_{i+1})
→ 反复迭代 predictor-corrector 直至收敛

💡 用于 Time-Dependent DFT(含时密度泛函理论)等需要长期稳定积分的高精度计算。

极低的计算开销:RK4 走一步需要计算 4 次极其复杂的 f(t,y)f(t,y)。而在 PECE 多步法中,历史斜率都是直接从内存中读取的,走一步通常只需要进行 121 \sim 2f(t,y)f(t,y) 求值(Evaluate 步骤),计算效率比单步法高出 2 到 4 倍

极强的数值稳定性:隐式方法(Moulton 族)天然具有比显式方法更宽广的绝对稳定域。PECE 通过显式预测和隐式校正的交替,牢牢锁住了非线性长期演化中的能量守恒性,有效防止了长时间积分中的误差发散。

总结

数值分析微分方程中主要的就是两种方法 :

1、高阶单步法 RK 纵向延伸 不断地k去迭代 只要可以一直算下去 不断精确 消去高阶项

缺点如下

著名的“Butcher障壁”(Butcher's Barrier):数学家 Butcher 证明了,4 阶 RK 只需要 4步迭代($k1 \dots k4$);但如果要达到 5 阶精度,最少需要 6 步迭代;要达到 6 阶精度,需要 7 步或 8 步。阶数越高,性价比(精度提升 / 计算量增加)急剧下降。

公式推导极其恐怖:高阶 RK 的系数推导(即代数消去的过程)极其困难,后续往往需要借助计算机代数系统(如 Maple 或 Mathematica)来推导系数。

经典

RK4:性价比之王(4 步达成 4 阶)。

Dormand-Prince (DP54 / solve_ivp 中的 RK45):通过 7 步迭代(算到 k7k_7),同时拼凑出一个 4 阶和一个 5 阶的公式,用来自动控制步长。

2、P-C多步法 横向时空协作 的 “历史借力”

隐式公式(如 Adams-Moulton):它的精度极高、稳定性极强(能抗住非线性发散),但它需要解非线性方程(未来点 yi+1y_{i+1} 在等式两边都有),非常难算(往往需要牛顿迭代,求导数雅可比矩阵)

显式公式(如 Adams-Bashforth):它不含未来点,非常好算,但精度和稳定性稍逊。

关键

显式和隐式一结合,显式负责快速给个粗糙的预估,隐式负责精细校正

最绝的是计算速度:因为在 PECE 模式中,历史的 fi1,fi2f_{i-1}, f_{i-2} 早已在之前的步骤中算过并存在内存里了,这步计算它们不需要任何耗时的函数求值($O(1)$ 读取)。

在长期演化(如你提到的 TDDFT 含时密度泛函、天体轨道计算、分子动力学)中,算一次 f(t,y)f(t, y) 常常要解一次庞大的薛定谔方程或泊松方程。此时,PECE 相比于 RK4,能直接砍掉一半以上的计算时间,同时保持极高的精度!


5. 微分方程组与 Lorenz 混沌

5.1 向量形式

多个变量: y=(y1,y2,,ym)\mathbf{y} = (y_1, y_2, \ldots, y_m)

方程:

dydt=f(t,y)\frac{d\mathbf{y}}{dt} = \mathbf{f}(t, \mathbf{y})

Extended RK4(m 个变量的 RK4):

for j = 1 to m:   # 每个变量
    k1_j = f_j(t, y_1, y_2, ..., y_m)
    
for j = 1 to m:
    k2_j = f_j(t + h/2, y_1 + h/2·k1_1, ..., y_m + h/2·k1_m)

# 同理计算 k3, k4,然后:
y_j(new) = y_j + h/6 (k1_j + 2k2_j + 2k3_j + k4_j)

在实际写代码时,最容易犯的一个毁灭性错误,就是“一边计算新值,一边覆盖旧值”

❌ 错误示范:


# 假设我们在算 k2_x, k2_y...

for j in range(m):

    # 危险!当 j=1 (算y) 时,y_mid 需要 x_mid 的预测值。

    # 如果你在这里直接用公式,可能不小心把当前正在被修改的数组当成了输入

    k2[j] = fj [<sup>1</sup>](t + h/2, y[0] + h/2 * k1[0], y[1] + h/2 * k1[1], ...)

正确示范:利用临时的“同步状态向量”

在计算 k2,k3,k4k_2, k_3, k_4 之前,先用上一个阶段完整的斜率向量,生成一个当前阶段专用的、临时的“探路状态”向量 y_temp,然后所有变量统一在这个 y_temp 下进行函数求值:

Python
# 1. 算完所有变量的 k1

for j in range(m):

    k1[j] = fj [<sup>2</sup>](t, y)

# 2. 同步生成中点状态 1

y_temp = y + (h / 2) * k1  # 这是向量加法,保证所有变量同步向前推进半步

# 3. 在这个同步的中点状态上,算完所有变量的 k2

for j in range(m):

    k2[j] = fj [<sup>3</sup>](t + h / 2, y_temp)

# 4. 同步生成中点状态 2

y_temp = y + (h / 2) * k2

# 5. 算完所有变量的 k3

for j in range(m):

    k3[j] = fj [<sup>3</sup>](t + h / 2, y_temp)

# 6. 同步生成终点状态

y_temp = y + h * k3

# 7. 算完所有变量的 k4

for j in range(m):

    k4[j] = fj [<sup>4</sup>](t + h, y_temp)


# 8. 最终大合流

y = y + (h / 6) * (k1 + 2 * k2 + 2 * k3 + k4)

💡 注意 k2k_2 依赖所有变量的 k1k_1——必须算完所有 k1k_1 再算 k2k_2

处理多元微分方程组的黄金法则是:“同生共死,步调一致”。 通过引入一个像 y_temp 这样的中间过渡容器,我们在时空上强行将所有互相纠缠的变量锁定在了同一个时刻(起点、中点、终点)。泰勒展开的代数消去魔术也因此得以在多元空间中完美复现,护送整个混沌系统以高精度、高稳定性安全前行。

5.2 Lorenz 方程 — 混沌的经典

dxdt=σ(yx)dydt=x(rz)ydzdt=xybz\begin{aligned} \frac{dx}{dt} &= \sigma(y - x) \\ \frac{dy}{dt} &= x(r - z) - y \\ \frac{dz}{dt} &= xy - bz \end{aligned}

参数: σ=10, b=8/3\sigma = 10,\ b = 8/3,当 r=28r = 28 时出现混沌。

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import time

# =============================================
# 1. 定义洛伦兹系统(混沌系统)
# =============================================
def lorenz(t, state, sigma=10, r=28, b=8/3):
    """
    洛伦兹方程 (大气对流简化模型)
    dx/dt = sigma*(y - x)
    dy/dt = x*(r - z) - y
    dz/dt = x*y - b*z
    """
    x, y, z = state
    dx = sigma * (y - x)
    dy = x * (r - z) - y
    dz = x * y - b * z
    return np.array([dx, dy, dz])

# =============================================
# 2. 核心:向量版 RK4 步进函数(通用,支持任意维度的系统)
# =============================================
def rk4_step_vector(f, t, y, h):
    """
    四阶龙格-库塔法 (向量形式)
    参数:
        f: 微分方程函数,返回 np.array
        t: 当前时间 (标量)
        y: 当前状态向量 (np.array)
        h: 步长
    返回:
        下一个时间步的状态向量 (np.array)
    """
    # 四个斜率计算(全为向量运算)
    k1 = f(t, y)
    k2 = f(t + h/2, y + (h/2) * k1)
    k3 = f(t + h/2, y + (h/2) * k2)
    k4 = f(t + h, y + h * k3)
    
    # 加权平均更新状态
    y_next = y + (h/6) * (k1 + 2*k2 + 2*k3 + k4)
    return y_next

# =============================================
# 3. 主程序:求解并保存轨迹
# =============================================
if __name__ == "__main__":
    # 参数设置
    state = np.array([1.0, 1.0, 1.0])  # 初始条件 (x0, y0, z0)
    h = 0.01                           # 步长 (越小精度越高,但计算量越大)
    N = 5000                           # 迭代步数 (总积分时间 T = h*N = 50秒)
    
    # 记录轨迹(为了节省内存,可以预先分配数组,但用列表 append 更直观)
    trajectory = [state.copy()]
    t_current = 0.0
    
    print(f"开始求解洛伦兹系统,步长 h={h},总步数 N={N}...")
    start_time = time.time()
    
    # 主循环
    for i in range(N):
        state = rk4_step_vector(lorenz, t_current, state, h)
        t_current += h
        trajectory.append(state.copy())  # 注意要 copy,防止后续修改影响历史数据
        
        # 可选:每 500 步打印一次进度
        if (i + 1) % 500 == 0:
            print(f"  已完成 {i+1}/{N} 步,当前时间 t = {t_current:.2f}")
    
    end_time = time.time()
    print(f"计算完成!耗时 {end_time - start_time:.4f} 秒。")
    
    # 将轨迹列表转换为 numpy 数组,方便切片绘图
    traj = np.array(trajectory)
    print(f"轨迹数组形状: {traj.shape}")  # 应为 (N+1, 3)

    # =============================================
    # 4. 可视化:绘制三维相图和二维投影
    # =============================================
    fig = plt.figure(figsize=(15, 5))
    
    # 子图 1: 三维相空间 (经典蝴蝶效应)
    ax1 = fig.add_subplot(131, projection='3d')
    ax1.plot(traj[:, 0], traj[:, 1], traj[:, 2], linewidth=0.8, color='blue')
    ax1.set_xlabel('X')
    ax1.set_ylabel('Y')
    ax1.set_zlabel('Z')
    ax1.set_title('洛伦兹吸引子 (3D)')
    
    # 子图 2: X-Z 投影 (最常见的蝴蝶图)
    ax2 = fig.add_subplot(132)
    ax2.plot(traj[:, 0], traj[:, 2], linewidth=0.6, color='red')
    ax2.set_xlabel('X')
    ax2.set_ylabel('Z')
    ax2.set_title('X-Z 投影')
    ax2.grid(True, linestyle='--', alpha=0.5)
    
    # 子图 3: X-Y 投影
    ax3 = fig.add_subplot(133)
    ax3.plot(traj[:, 0], traj[:, 1], linewidth=0.6, color='green')
    ax3.set_xlabel('X')
    ax3.set_ylabel('Y')
    ax3.set_title('X-Y 投影')
    ax3.grid(True, linestyle='--', alpha=0.5)
    
    plt.tight_layout()
    plt.show()
    
    # =============================================
    # 5. 额外:打印最终状态和简单的统计学检查
    # =============================================
    final_state = traj[-1]
    print(f"\n最终状态 (t={t_current:.2f}): X={final_state[0]:.6f}, Y={final_state[1]:.6f}, Z={final_state[2]:.6f}")
    
    # 检查是否有数值溢出 (洛伦兹系统在参数 28 时是混沌有界的,一般不会溢出)
    if np.any(np.isnan(traj)):
        print("⚠️ 警告:检测到 NaN,请尝试减小步长 h 或检查初始条件!")
    else:
        print("✅ 数值稳定,未出现溢出。")

💡 混沌标志:初始条件的微小差异(如 x0=1.000x_0 = 1.000 vs 1.0011.001)在 t15t \approx 15 后演化出完全不同的轨迹——蝴蝶效应!


6. 高阶微分方程的降阶处理

6.1 核心技巧:高阶 → 一阶方程组

二阶 ODE: y+p(t)y+q(t)y=r(t)y'' + p(t)y' + q(t)y = r(t)

定义新变量降阶

u1=yu2=y{u1=u2u2=r(t)p(t)u2q(t)u1\begin{aligned} u_1 &= y \\ u_2 &= y' \end{aligned} \quad\Rightarrow\quad \begin{cases} u_1' = u_2 \\ u_2' = r(t) - p(t)u_2 - q(t)u_1 \end{cases}

这就是 mm 个一阶方程 → 用 Extended RK4 直接求解。

6.2 📐 完整例子:阻尼谐振子

方程: y+2γy+ω02y=0y'' + 2\gamma y' + \omega_0^2 y = 0,设 γ=0.3, ω0=2\gamma=0.3,\ \omega_0=2,$y(0)=1,\ y'(0)=0$

降阶为:

{u1=u2u2=0.6u24u1\begin{cases} u_1' = u_2 \\ u_2' = -0.6u_2 - 4u_1 \end{cases}
def damped_oscillator(t, u):
    u1, u2 = u
    gamma, omega0 = 0.3, 2.0
    du1 = u2
    du2 = -2*gamma*u2 - omega0**2 * u1
    return np.array([du1, du2])

u0 = np.array([1.0, 0.0])  # [y(0), y'(0)]
h = 0.05
t_vals = np.arange(0, 10.0, h)
u_traj = [u0]
for i in range(len(t_vals)-1):
    u_traj.append(rk4_step_vector(damped_oscillator, t_vals[i], u_traj[-1], h))

# 结果:振幅随时间指数衰减,频率略小于 ω₀

💡 通用策略:任意 nn 阶 ODE 都可以转化为 nn 个一阶方程。这个技巧在计算物理中无处不在。


7. 刚性微分方程(Stiff ODE)

7.1 什么是刚性?

系统中同时存在"快变量"和"慢变量"时,显式方法必须用极小的步长来追踪最快分量,否则发散。

快变量:变化速度极快 在瞬间 衰减到0

慢变量: 真正关心的 主导了系统长期演变的变量

刚性的本质:微分方程组的 Jacobi 矩阵特征值 λi\lambda_i 中,$\max|\lambdai| / \min|\lambdai|$ 很大。

7.2 稳定性对比

致命的痛点:为什么显式方法(如欧拉、RK4)会在这里死掉?

如果你想计算这个系统在 t=5t = 5 秒时的状态。此时弹簧 A 早就静止了,照理说我们应该可以跨大步子(比如步长 h=0.1h = 0.1 秒)来快速计算弹簧 B 的悠闲运动。

然而,如果你使用显式欧拉法(或者 RK4): 只要你的步长 hh 稍稍大于 0.0001 秒(比如你用了 h=0.01h = 0.01),那个早就已经静止的“快变量”就会在数值计算中像疯了一样成倍放大、瞬间发散到无穷大

显式方法被逼着必须使用 h=0.00001h = 0.00001 秒的超级小步长,去算那毫无意义、早就静止了的快变量,从而在极小的步长上把自己硬生生“耗死”

绝对稳定性与特征值:数值世界里的“紧箍咒”

为了看清为什么显式方法会发散,而隐式方法不会,我们必须做一次严密的代数推导。

1. 显式欧拉的自我毁灭推导

假设我们面对最简单的一个一阶线性微分方程(代表我们系统里的“快变量”衰减过程): dydt=λy,(其中 λ<0,是一个极大的负数,比如 λ=1000)\frac{dy}{dt} = \lambda y, \quad (\text{其中 } \lambda < 0 \text{,是一个极大的负数,比如 } \lambda = -1000) 它的精确解析解是 y(t)=Ceλt=Ce1000ty(t) = C e^{\lambda t} = C e^{-1000 t}。随着时间推移,它会以极快的速度衰减到 00

现在,我们用显式欧拉法来计算它: yi+1=yi+hf(ti,yi)=yi+h(λyi)y_{i+1} = y_i + h f(t_i, y_i) = y_i + h (\lambda y_i) 提取公因子 yiy_iyi+1=(1+hλ)yi— (式 1)y_{i+1} = (1 + h\lambda) y_i \quad \text{--- (式 1)}

致命的死亡条件:

要想让计算出来的 yy 像真实物理世界一样不断衰减(不发散),我们必须保证每前进一步,新值都比旧值小。也就是: 1+hλ<1|1 + h\lambda| < 1 由于 λ=1000\lambda = -1000,我们解这个绝对值不等式: 1<11000h<1    0<1000h<2    h<0.002-1 < 1 - 1000h < 1 \implies 0 < 1000h < 2 \implies h < 0.002

瞧见了吗?不管你有多想跨大步子,你的步长 hh 都被死死地限制在了 0.0020.002 秒以内! 一旦你的 hh 哪怕大了一丁点(比如 h=0.003h = 0.003),系数就会变成 1+hλ=13=2|1 + h\lambda| = |1 - 3| = 2。 下一步的值就会变成上一步的 2 倍,再下一步是 4 倍8 倍……瞬间发散崩溃!

这就是表里的: Explicit: 1+hλ<1\text{Explicit: } |1 + h\lambda| < 1

隐式梯形法的“降维打击”

现在,我们把相同的方程,用隐式梯形法来算。 隐式梯形法的公式为: yi+1=yi+h2[f(ti,yi)+f(ti+1,yi+1)]y_{i+1} = y_i + \frac{h}{2} [f(t_i, y_i) + f(t_{i+1}, y_{i+1})]

代入 f(t,y)=λyf(t,y) = \lambda yyi+1=yi+h2[λyi+λyi+1]y_{i+1} = y_i + \frac{h}{2} [\lambda y_i + \lambda y_{i+1}]

我们将含有未来项 yi+1y_{i+1} 的项移到等式的左边: yi+1hλ2yi+1=yi+hλ2yiy_{i+1} - \frac{h\lambda}{2} y_{i+1} = y_i + \frac{h\lambda}{2} y_i 提取并整理: (1hλ2)yi+1=(1+hλ2)yi\left(1 - \frac{h\lambda}{2}\right) y_{i+1} = \left(1 + \frac{h\lambda}{2}\right) y_i

yi+1=(1+hλ21hλ2)yi— (式 2)y_{i+1} = \left( \frac{1 + \frac{h\lambda}{2}}{1 - \frac{h\lambda}{2}} \right) y_i \quad \text{--- (式 2)}

🎉 奇迹发生了:

我们要让数值解不发散,同样需要放大系数的绝对值小于 1: 1+hλ21hλ2<1\left| \frac{1 + \frac{h\lambda}{2}}{1 - \frac{h\lambda}{2}} \right| < 1

由于物理衰减中 λ<0\lambda < 0(即负实部),所以:

  • 分母 1hλ21 - \frac{h\lambda}{2} 一定是一个大于 1 的正数。
  • 分子 1+hλ21 + \frac{h\lambda}{2} 的绝对值,在 λ<0\lambda < 0 时,永远小于分母

这意味着:无论你的步长 hh 取得有多大(哪怕 h=10000h = 10000 甚至无穷大),这个放大系数的绝对值都永远小于 1! 隐式梯形法是无条件稳定的。你可以放心大胆地用巨无霸步长跨过去,那个快变量只会温顺地、迅速地衰减到 0,绝对不会发散。

方法 类型 稳定性 对 Stiff 方程
Euler (显式) Explicit $1+h\lambda < 1$ ❌ 步长受最快分量限制
隐式梯形法 Implicit 无条件稳定(对负实部特征值)
Gear 方法 Implicit 刚性好 ✅ 推荐

7.3 隐式梯形法 (Implicit Trapezoidal)

yi+1=yi+h2[f(ti,yi)+f(ti+1,yi+1)]y_{i+1} = y_i + \frac{h}{2}\left[f(t_i, y_i) + f(t_{i+1}, y_{i+1})\right]

隐式方法虽然好,但是它有一个致命难点:

未来项 yi+1y_{i+1} 藏在复杂的非线性函数 f(ti+1,yi+1)f(t_{i+1}, y_{i+1}) 里面,我们该怎么把它解出来?

以隐式梯形法为例,我们定义一个残差函数 F(yi+1)F(y_{i+1}),我们的目标是找到一个 yi+1y_{i+1} 使得这个函数等于 0: F(yi+1)=yi+1yih2[f(ti,yi)+f(ti+1,yi+1)]=0F(y_{i+1}) = y_{i+1} - y_i - \frac{h}{2} \left[ f(t_i, y_i) + f(t_{i+1}, y_{i+1}) \right] = 0

因为 ff 是非线性的,我们必须在每一步里,都用牛顿迭代法(Newton-Raphson)去把它活生生“猜”出来。

牛顿迭代手算推导:

牛顿迭代法是求解非线性方程 F(x)=0F(x) = 0 最犀利的武器。它的几何直觉极其美妙:

  1. 第一步(盲猜):我们先闭着眼睛对 yi+1y_{i+1} 猜一个初始值,记为 y(0)y^{(0)}
    • 注:怎么猜?最常用的办法是用最简单的显式欧拉法跨一步: y(0)=yi+hf(ti,yi)y^{(0)} = y_i + h f(t_i, y_i),这个粗糙的值作为我们的起点。
  2. 第二步(作切线):我们画出函数 F(x)F(x) 的曲线,找到曲线在 x=y(0)x = y^{(0)} 处的点 (y(0),F(y(0)))(y^{(0)}, F(y^{(0)}))。我们在这个点上作一条切线
  3. 第三步(切线求交点):这条切线的斜率就是导数 F(y(0))F'(y^{(0)})。切线与 xx 轴(即 F(x)=0F(x) = 0 处)相交的点,就会比我们盲猜的 y(0)y^{(0)} 更接近真正的根。我们将这个交点记为下一次的猜测值 y(1)y^{(1)}

我们用一次函数(切线方程)来写出这个过程: 在点 x=y(k)x = y^{(k)} 处的切线方程为: yF(y(k))=F(y(k))(xy(k))y - F(y^{(k)}) = F'(y^{(k)}) (x - y^{(k)}) 我们要找它与 xx 轴的交点,即令 y=0y = 0,求解此时的 xx(即下一次逼近值 y(k+1)y^{(k+1)}

0F(y(k))=F(y(k))(y(k+1)y(k))(0 - F(y^{(k)}) = F'(y^{(k)}) (y^{(k+1)} - y^{(k)})

移项整理: y(k+1)y(k)=F(y(k))F(y(k))y^{(k+1)} - y^{(k)} = -\frac{F(y^{(k)})}{F'(y^{(k)})}

y(k+1)=y(k)F(y(k))F(y(k))— (牛顿迭代核心公式)y^{(k+1)} = y^{(k)} - \frac{F(y^{(k)})}{F'(y^{(k)})} \quad \text{--- (牛顿迭代核心公式)}

我们要对 F(yi+1)F(y_{i+1}) 关于 yi+1y_{i+1} 求导: F(yi+1)=yi+1(yi+1yih2[f(ti,yi)+f(ti+1,yi+1)])=1h2fyF'(y_{i+1}) = \frac{\partial}{\partial y_{i+1}} \left( y_{i+1} - y_i - \frac{h}{2} [f(t_i, y_i) + f(t_{i+1}, y_{i+1})] \right) = 1 - \frac{h}{2} \frac{\partial f}{\partial y} 这里的 fy\frac{\partial f}{\partial y} 就是一维时的导数,在多元微分方程组里,它就是赫赫有名的雅可比矩阵(Jacobian Matrix) JJ

因此,牛顿迭代的每一次修正公式为: y(k+1)=y(k)y(k)yih2[f(ti,yi)+f(ti+1,y(k))]1h2Jy^{(k+1)} = y^{(k)} - \frac{y^{(k)} - y_i - \frac{h}{2} [f(t_i, y_i) + f(t_{i+1}, y^{(k)})]}{1 - \frac{h}{2} J}

yi+1y_{i+1} 出现在方程右侧,需用 Newton 迭代求解:

# 伪代码:隐式梯形法一步
def trapezoidal_step(f, t, y, h):
    # 先用 Euler 预测一个初猜
    y_guess = y + h * f(t, y)
    
    # Newton 迭代求解
    for _ in range(max_iter):
        F = y_guess - y - h/2 * (f(t, y) + f(t+h, y_guess))
        if abs(F) < tol: break
        # J = 1 - h/2 * df/dy (对单变量)
        J = 1 - h/2 * jacobian(f, t+h, y_guess)
        y_guess = y_guess - F/J
    
    return y_guess

7.4 Gear 方法 (2阶 / 3阶)

Backward Differentiation Formula

普通多步法(Adams 族):通过对斜率 ff 进行插值,去近似积分。

Gear 方法(BDF 族):通过对状态 yy(即当前点和历史点)进行高阶多项式插值,强行对这个多项式求导,以此来逼近未来的斜率。

2 阶 Gear

yi+1=43yi13yi1+2h3f(ti+1,yi+1)y_{i+1} = \frac{4}{3}y_i - \frac{1}{3}y_{i-1} + \frac{2h}{3}f(t_{i+1}, y_{i+1})

它的代数原理极其简单: 假设我们在 ti+1,ti,ti1t_{i+1}, t_i, t_{i-1} 这三个点上,穿过状态值 yi+1,yi,yi1y_{i+1}, y_i, y_{i-1} 作一条二次抛物线 P(t)P(t)。 通过拉格朗日插值法,我们可以写出这条代表位移的抛物线 P(t)P(t) 的表达式。 然后,我们强制要求抛物线在未来时刻 ti+1t_{i+1} 处的导数 P(ti+1)P'(t_{i+1}),必须完美等于物理方程给出的斜率 f(ti+1,yi+1)f(t_{i+1}, y_{i+1})! 即: P(ti+1)=f(ti+1,yi+1)P'(t_{i+1}) = f(t_{i+1}, y_{i+1}) 对插值多项式求导并整理后,这一步就会硬生生、分毫不差地凑出: yi+1=43yi13yi1+2h3f(ti+1,yi+1)y_{i+1} = \frac{4}{3}y_i - \frac{1}{3}y_{i-1} + \frac{2h}{3} f(t_{i+1}, y_{i+1})

同理,若用 4 个点作三次抛物线,求导后就能推导出 3 阶 Gear

yi+1=1811yi911yi1+211yi2+6h11f(ti+1,yi+1)y_{i+1} = \frac{18}{11}y_i - \frac{9}{11}y_{i-1} + \frac{2}{11}y_{i-2} + \frac{6h}{11}f(t_{i+1}, y_{i+1})

3 阶 Gear

yi+1=1811yi911yi1+211yi2+6h11f(ti+1,yi+1)y_{i+1} = \frac{18}{11}y_i - \frac{9}{11}y_{i-1} + \frac{2}{11}y_{i-2} + \frac{6h}{11}f(t_{i+1}, y_{i+1})

都是隐式方法,每步需 Newton 迭代求解 yi+1y_{i+1}

💡 稳定性准则(微分方程组):

Explicit: 1+hλi<1vsImplicit: 无条件稳定(Re(λi)<0 时)\text{Explicit: } |1 + h\lambda_i| < 1 \quad \text{vs} \quad \text{Implicit: 无条件稳定($Re(\lambda_i)<0$ 时)}

为什么 Gear 方法(BDF)最适合 Stiff 方程?(深入绝对稳定性)

为了彻底看清为什么这套方法能成为刚性(Stiff)微分方程的“降维打击”王牌,我们需要从绝对稳定域的数学本源去剖析它。

1. 测试方程与线性化

为了分析任何一个数值方法的稳定性,数学家都会使用标准线性测试方程:

dydt=λy(其中 λC, 复数,且其实部 Re(λ)<0) \frac{dy}{dt} = \lambda y \quad (\text{其中 } \lambda \in \mathbb{C}, \text{ 复数,且其实部 } \text{Re}(\lambda) < 0)

这个方程代表了物理系统中的衰减分量(快变量)。我们定义无量纲参数 z=hλz = h\lambda。 在真实物理世界里,因为实部为负,所以随着 tt \to \infty,解析解 y(t)0y(t) \to 0。 我们要求:数值方法计算出来的序列 yny_n 在步数 nn \to \infty 时,也必须衰减到 00

2. BDF2 的特征方程与绝对稳定条件

我们将测试方程 f(t,y)=λyf(t, y) = \lambda y 代入刚刚推导出的 BDF2 公式中:

yi+1=43yi13yi1+23zyi+1(其中 z=hλ) y_{i+1} = \frac{4}{3} y_i - \frac{1}{3} y_{i-1} + \frac{2}{3} z y_{i+1} \quad (\text{其中 } z = h\lambda)

我们将所有项移到左侧并整理:

(123z)yi+143yi+13yi1=0 \left( 1 - \frac{2}{3} z \right) y_{i+1} - \frac{4}{3} y_i + \frac{1}{3} y_{i-1} = 0

为了去分母,两边乘以 33

(32z)yi+14yi+yi1=0 (3 - 2z) y_{i+1} - 4 y_i + y_{i-1} = 0

这是一个关于序列 yy二阶常系数线性差分方程。其通解的形式为 yn=Crny_n = C r^n,其中 rr 是其特征方程的根。 我们将 yn=rny_n = r^n 代入上式,得出其特征方程

(32z)r24r+1=0 (3 - 2z) r^2 - 4 r + 1 = 0

根据线性差分方程的稳定性理论,要让数值解 yn0y_n \to 0 稳定不发散,特征方程的两个根 r1,r2r_1, r_2 的模长都必须严格小于 1(即它们必须落在复平面的单位圆内):

r1<1r2<1 |r_1| < 1 \quad \text{且} \quad |r_2| < 1

我们来解出特征根 rr 看看它与 z=hλz = h\lambda 的关系:

r=4±164(32z)2(32z)=4±4+8z2(32z)=2±1+2z32z r = \frac{4 \pm \sqrt{16 - 4(3 - 2z)}}{2(3 - 2z)} = \frac{4 \pm \sqrt{4 + 8z}}{2(3 - 2z)} = \frac{2 \pm \sqrt{1 + 2z}}{3 - 2z}
🌟 为什么它极其稳定?

假设我们的方程存在极度刚性的快分量,这意味着 λ\lambda 是一个极大的负实数(例如 λ=10000\lambda = -10000)。如果我们用大步长 h=1h = 1 去跨,那么 z=hλ=10000z = h\lambda = -10000 就会变成一个极其恐怖的负数。 我们来看一下当 zz \to -\infty 时,特征根 rr 会发生什么:

limzr=limz2±1+2z32z \lim_{z \to -\infty} r = \lim_{z \to -\infty} \frac{2 \pm \sqrt{1 + 2z}}{3 - 2z}

由于分母上有 zz 的一次项,而分子上只有根号下 zz(即半次方项)。根据极限法则,分母的增长速度远快于分子:

limzr=0 \lim_{z \to -\infty} r = 0

这意味着什么?

当面对极强刚性( zz \to -\infty)时,BDF2 的特征根 rr 直接趋近于 0! 特征根趋近于 0,意味着每走一步,误差不仅不会放大,反而会被以近乎 100% 的效率瞬间抹除、强行掐灭! 这就是为什么说它是“黑洞一样的结构,能够吞噬快分量误差”的数学解释。


3. 绝对稳定域的对比(显式 vs 隐式)

为了让你更具象地感受,我们画出复平面上的“绝对稳定域”(也就是能让特征根模长小于 1 的所有 zz 的集合):

  • 显式欧拉法:稳定域是复平面上以 (1,0)(-1, 0) 为圆心、半径为 11小圆圈z=hλz = h\lambda 必须在这个小圆圈内。当 λ=1000\lambda = -1000 时, hh 必须小于 0.0020.002 才能把 zz 关进这个圆圈。
  • 隐式梯形法:稳定域是整个复平面的左半平面(A-Stable)。只要 Re(λ)<0\text{Re}(\lambda) < 0,无论 hh 有多大, zz 都永远在稳定域里。但是当 zz \to -\infty 时,其放大系数趋于 1-1(边界上),误差虽然不发散,但会产生持久的数值振荡。
  • Gear 方法(BDF2):不仅是 A-stable 的(整个左半平面几乎全包),而且它拥有极强的 L-稳定性(L-Stable)。也就是说,当 zz \to -\infty 时,它的放大系数直接收敛到 0。这相当于对快分量的数值误差实施了“降维打击”——只要你刚性发作得越厉害,它掐死误差的速度就越快。

核心结论:Implicit 的稳定性远优于 Explicit。对 Stiff 问题,宁可用隐式方法多算几步 Newton 迭代,也别用显式方法在极小步长上耗死自己。

为什么 Gear 方法最适合 Stiff 方程?

因为它的左边是纯粹的状态项 yy,右边只有一项未来的斜率项 f(ti+1,yi+1)f(t_{i+1}, y_{i+1})。 在代数合并和牛顿迭代时,这种结构在复平面上的绝对稳定区域极其庞大,能够像黑洞一样,把所有具有极大负实部特征值(也就是死得最快的那些快分量)的误差全部吞噬、彻底压制


8. 边值问题BVP与打靶法(Shooting)

8.1 问题描述

边值问题:已知 y(a)=α, y(b)=βy(a) = \alpha,\ y(b) = \beta,求解 y(x)y(x)

与初值问题的根本不同——两端都有条件。

核心打靶法就是:

把未知的初始斜率

t=y(a) t = y'(a)

当成一个可调参数,不断试,直到积分到 bb 时满足

y(b)=β y(b)=\beta

打靶法核心思路:把边值问题转化为初值问题!

8.2 线性打靶法

优势之处:线性方程满足叠加原理

对线性方程:

y+p(x)y+q(x)y=r(x),y(a)=α, y(b)=β y'' + p(x)y' + q(x)y = r(x), \quad y(a)=\alpha,\ y(b)=\beta

步骤

  1. 解两个辅助初值问题:
问题1: y1+py1+qy1=r,y1(a)=α, y1(a)=0问题2: y2+py2+qy2=0,y2(a)=0, y2(a)=1\begin{aligned} \text{问题1: } & y_1'' + py_1' + qy_1 = r, \quad y_1(a)=\alpha,\ y_1'(a)=0 \\ \text{问题2: } & y_2'' + py_2' + qy_2 = 0, \quad y_2(a)=0,\ y_2'(a)=1 \end{aligned}
  1. 用 RK4 分别求 y1(b), y2(b)y_1(b),\ y_2(b)

  2. 混合两个解: y(x)=y1(x)+ty2(x)y(x) = y_1(x) + t \cdot y_2(x)

其中系数 tt 由边界条件确定:

t=βy1(b)y2(b)t = \frac{\beta - y_1(b)}{y_2(b)}

两个解都满足方程(因为是线性叠加),调整混合比例 tt 来同时满足两端边界条件。

线性打靶法本质

你可以理解为:

y1 y_1

是“先打一枪,斜率取 0”的轨迹。

y2 y_2

是“单位斜率造成的响应”。

然后真正需要的斜率修正量就是:

t=终点缺口单位斜率带来的终点变化 t=\frac{\text{终点缺口}}{\text{单位斜率带来的终点变化}}

即:

t=βy1(b)y2(b) t = \frac{\beta-y_1(b)}{y_2(b)}

注意:什么时候会失败?

如果

y2(b)=0 y_2(b)=0

那么公式分母为零。

这说明初始斜率的变化对终点 y(b)y(b) 没有影响,或者对应的齐次边值问题存在非零解。

这通常意味着:

  • 问题无解;
  • 或者解不唯一;
  • 或者参数正好落在某个本征值上。

例如 Sturm-Liouville 本征值问题中,齐次解可以同时满足两端边界,这时 Green 函数分母 Wronskian 也会出问题。

8.3 非线性打靶法 + 割线法求 tt

对于非线性问题:

y=f(x,y,y) y''=f(x,y,y')

边界条件:

y(a)=α,y(b)=β y(a)=\alpha,\qquad y(b)=\beta

我们仍然设:

t=y(a) t=y'(a)

每给一个 tt,从 aa 积分到 bb,得到:

y(b;t) y(b;t)

定义残差函数:

F(t)=y(b;t)β F(t)=y(b;t)-\beta

目标:

F(t)=0 F(t)=0

割线法推导

假设已经有两个试探斜率:

tk1,tk t_{k-1},\qquad t_k

对应残差:

F(tk1),F(tk) F(t_{k-1}),\qquad F(t_k)

我们用一条直线近似 F(t)F(t)

割线斜率是:

F(tk)F(tk1)tktk1 \frac{F(t_k)-F(t_{k-1})}{t_k-t_{k-1}}

直线方程为:

F(t)F(tk)+F(tk)F(tk1)tktk1(ttk) F(t)\approx F(t_k) + \frac{F(t_k)-F(t_{k-1})}{t_k-t_{k-1}}(t-t_k)

我们希望下一次 tk+1t_{k+1} 使得这个线性近似为 0:

0=F(tk)+F(tk)F(tk1)tktk1(tk+1tk) 0= F(t_k) + \frac{F(t_k)-F(t_{k-1})}{t_k-t_{k-1}}(t_{k+1}-t_k)

移项:

F(tk)F(tk1)tktk1(tk+1tk)=F(tk) \frac{F(t_k)-F(t_{k-1})}{t_k-t_{k-1}}(t_{k+1}-t_k) = -F(t_k)

所以

tk+1tk=F(tk)tktk1F(tk)F(tk1) t_{k+1}-t_k = -F(t_k) \frac{t_k-t_{k-1}}{F(t_k)-F(t_{k-1})}

得到:

tk+1=tkF(tk)tktk1F(tk)F(tk1) t_{k+1} = t_k - F(t_k) \frac{t_k-t_{k-1}}{F(t_k)-F(t_{k-1})}

由于

F(t)=y(b;t)β F(t)=y(b;t)-\beta

所以

tk+1=tk(y(b;tk)β)tktk1y(b;tk)y(b;tk1) t_{k+1} = t_k - \bigl(y(b;t_k)-\beta\bigr) \frac{t_k-t_{k-1}} {y(b;t_k)-y(b;t_{k-1})}

这就是你写的公式。


非线性打靶法算法

  1. 选两个初始猜测:
t0,t1 t_0,\qquad t_1
  1. 用 RK4 积分:
y(b;t0),y(b;t1) y(b;t_0),\qquad y(b;t_1)
  1. 计算残差:
F(t0)=y(b;t0)β F(t_0)=y(b;t_0)-\beta
  1. 用割线法更新:
t2=t1F(t1)t1t0F(t1)F(t0) t_2= t_1 - F(t_1) \frac{t_1-t_0}{F(t_1)-F(t_0)}
  1. 重复直到:
F(tk)=y(b;tk)β<ε |F(t_k)|=|y(b;t_k)-\beta|<\varepsilon

💡 为什么叫"打靶":你站在 a 点,调整出射角 t=y(a)t = y'(a),"射击"目标是 b 点的边界值。射偏了就调整角度再来一枪,直到命中靶心。

8.4 割线法与牛顿法的选择

如果能算出:

F(t)=y(b;t)t F'(t)=\frac{\partial y(b;t)}{\partial t}

那么可以用牛顿法:

tk+1=tkF(tk)F(tk) t_{k+1} = t_k-\frac{F(t_k)}{F'(t_k)}
方法 每步计算 收敛速度 适用
割线法 (Secant) 1 次积分 超线性 (~1.618 阶) 微分难求时
牛顿法 1 次积分 + 微分 二次收敛 微分好求时

对打靶法,$dy(b,t)/dt$ 往往不好求,割线法更实用。


9. Numerov 方法

9.1 专门为二阶 ODE 设计

Numerov 方法针对以下形式的方程(无 yy' 项): $$y'' + k(x)y = F(x)$$

普通二阶方程: $$ y''+p(x)y'+q(x)y=r(x) $$ 包含 yy',Numerov 不能直接套。

但有时可以通过变量替换消去一阶导。

令:

y(x)=u(x)e12p(x)dx y(x)=u(x)e^{-\frac12\int p(x)\,dx}

S(x)=12p(x)dx S(x)=\frac12\int p(x)\,dx

所以:

y=eSu y=e^{-S}u

求导:

y=eS(uSu) y'=e^{-S}(u'-S'u)

再求导:

y=eS[u2Su+(S2S)u] y'' = e^{-S} \left[ u''-2S'u'+(S'^2-S'')u \right]

代入原方程:

y+py+qy=r y''+p y'+q y=r

得到:

eS[u2Su+(S2S)u]+peS(uSu)+qeSu=r e^{-S} \left[ u''-2S'u'+(S'^2-S'')u \right] + p e^{-S}(u'-S'u) + q e^{-S}u=r

两边乘以 eSe^S

u2Su+(S2S)u+pupSu+qu=eSr u''-2S'u'+(S'^2-S'')u + p u'-pS'u+q u = e^S r

因为

S=p2 S'=\frac p2

所以一阶导项系数:

2S+p=p+p=0 -2S'+p=-p+p=0

一阶导消失。

剩下 uu 的系数:

S2SpS+q S'^2-S''-pS'+q

代入:

S2=p24 S'^2=\frac{p^2}{4}

所以:

S2SpS+q=p24p2p22+q S'^2-S''-pS'+q = \frac{p^2}{4}-\frac{p'}{2}-\frac{p^2}{2}+q

因此变成:

u+(qp2p24)u=eSr u'' + \left( q-\frac{p'}{2}-\frac{p^2}{4} \right)u = e^S r

这就变成了 Numerov 形式:

u+K(x)u=F~(x) u''+K(x)u=\tilde F(x)

其中:

K(x)=qp2p24 K(x)=q-\frac{p'}{2}-\frac{p^2}{4}

9.2 递推公式

我们从 Taylor 展开开始。

在网格:

xi=x0+ih x_i=x_0+ih

记:

yi=y(xi),ki=k(xi),Fi=F(xi) y_i=y(x_i),\qquad k_i=k(x_i),\qquad F_i=F(x_i)

方程:

y+ky=F y''+ky=F

也就是:

y=Fky y''=F-ky

第一步:中心差分展开

Taylor 展开:

yi+1=yi+hyi+h22yi+h36yi+h424yi(4)+h5120yi(5)+h6720yi(6)+ y_{i+1} = y_i+h y_i' +\frac{h^2}{2}y_i'' +\frac{h^3}{6}y_i''' +\frac{h^4}{24}y_i^{(4)} +\frac{h^5}{120}y_i^{(5)} +\frac{h^6}{720}y_i^{(6)} +\cdots

相加:

yi+1+yi1=2yi+h2yi+h412yi(4)+h6360yi(6)+ y_{i+1}+y_{i-1} = 2y_i +h^2 y_i'' +\frac{h^4}{12}y_i^{(4)} +\frac{h^6}{360}y_i^{(6)} +\cdots

所以:

yi+12yi+yi1=h2yi+h412yi(4)+O(h6) y_{i+1}-2y_i+y_{i-1} = h^2y_i'' +\frac{h^4}{12}y_i^{(4)} +O(h^6)

第二步:用差分近似 y(4)y^{(4)}

因为:

y(4)=(y) y^{(4)}=(y'')''

所以可以用二阶中心差分近似:

yi(4)yi+12yi+yi1h2 y_i^{(4)} \approx \frac{y_{i+1}''-2y_i''+y_{i-1}''}{h^2}

代入:

yi+12yi+yi1=h2yi+h412yi+12yi+yi1h2+O(h6) y_{i+1}-2y_i+y_{i-1} = h^2 y_i'' + \frac{h^4}{12} \frac{y_{i+1}''-2y_i''+y_{i-1}''}{h^2} +O(h^6)

整理:

yi+12yi+yi1=h2[yi+112(yi+12yi+yi1)]+O(h6) y_{i+1}-2y_i+y_{i-1} = h^2 \left[ y_i'' + \frac{1}{12} \left( y_{i+1}''-2y_i''+y_{i-1}'' \right) \right] +O(h^6)

把括号内合并:

yi+112(yi+12yi+yi1) y_i'' + \frac{1}{12} (y_{i+1}''-2y_i''+y_{i-1}'')

所以:

yi+12yi+yi1=h212(yi+1+10yi+yi1)+O(h6) y_{i+1}-2y_i+y_{i-1} = \frac{h^2}{12} \left( y_{i+1}''+10y_i''+y_{i-1}'' \right) +O(h^6)

第三步:代入微分方程

由:

y=Fky y''=F-ky

所以:

yi+1=Fi+1ki+1yi+1 y_{i+1}''=F_{i+1}-k_{i+1}y_{i+1}

代入:

yi+12yi+yi1=h212[Fi+1+10Fi+Fi1(ki+1yi+1+10kiyi+ki1yi1)] y_{i+1}-2y_i+y_{i-1} = \frac{h^2}{12} \left[ F_{i+1}+10F_i+F_{i-1} - \left( k_{i+1}y_{i+1} +10k_i y_i +k_{i-1}y_{i-1} \right) \right]

把所有含 yi+1y_{i+1} 的项放左边:

yi+1+h212ki+1yi+1=2yiyi1+h212(Fi+1+10Fi+Fi1)h212(10kiyi+ki1yi1) y_{i+1} + \frac{h^2}{12}k_{i+1}y_{i+1} = 2y_i-y_{i-1} + \frac{h^2}{12} (F_{i+1}+10F_i+F_{i-1}) - \frac{h^2}{12} (10k_i y_i+k_{i-1}y_{i-1})

左边:

(1+h212ki+1)yi+1 \left( 1+\frac{h^2}{12}k_{i+1} \right)y_{i+1}

右边整理 yiy_i 项:

2yi10h212kiyi=2(15h212ki)yi 2y_i-\frac{10h^2}{12}k_i y_i = 2\left(1-\frac{5h^2}{12}k_i\right)y_i

整理 yi1y_{i-1} 项:

yi1h212ki1yi1=(1+h212ki1)yi1 -y_{i-1}-\frac{h^2}{12}k_{i-1}y_{i-1} = -\left( 1+\frac{h^2}{12}k_{i-1} \right)y_{i-1}

因此:

(1+h212ki+1)yi+1=2(15h212ki)yi(1+h212ki1)yi1+h212(Fi+1+10Fi+Fi1) \left( 1+\frac{h^2}{12}k_{i+1} \right)y_{i+1} = 2\left(1-\frac{5h^2}{12}k_i\right)y_i - \left(1+\frac{h^2}{12}k_{i-1}\right)y_{i-1} + \frac{h^2}{12} (F_{i+1}+10F_i+F_{i-1})

最终得到 Numerov 递推公式:

yi+1=2(15h212ki)yi(1+h212ki1)yi1+h212(Fi+1+10Fi+Fi1)1+h212ki+1 y_{i+1} = \frac{ 2\left(1-\frac{5h^2}{12}k_i\right)y_i - \left(1+\frac{h^2}{12}k_{i-1}\right)y_{i-1} + \frac{h^2}{12} (F_{i+1}+10F_i+F_{i-1}) } { 1+\frac{h^2}{12}k_{i+1} }

齐次情形 F=0F=0 时:

yi+1=2(15h212ki)yi(1+h212ki1)yi11+h212ki+1 y_{i+1} = \frac{ 2\left(1-\frac{5h^2}{12}k_i\right)y_i - \left(1+\frac{h^2}{12}k_{i-1}\right)y_{i-1} } { 1+\frac{h^2}{12}k_{i+1} }

对二阶方程的 Taylor 展开到 6 阶,巧妙构造消去误差项:

yi+1=2(15h212ki)yi(1+h212ki1)yi1+h212(Fi+1+10Fi+Fi1)1+h212ki+1y_{i+1} = \frac{2\left(1 - \frac{5h^2}{12}k_i\right)y_i - \left(1 + \frac{h^2}{12}k_{i-1}\right)y_{i-1} + \frac{h^2}{12}(F_{i+1} + 10F_i + F_{i-1})}{1 + \frac{h^2}{12}k_{i+1}}

💡 局部误差正比于 h6h^6比 RK4 还高一阶

9.3 特例:F=0 的齐次形式

F(x)=0F(x) = 0(齐次方程 y+k(x)y=0y'' + k(x)y = 0):

yi+1=2(15h212ki)yi(1+h212ki1)yi11+h212ki+1y_{i+1} = \frac{2\left(1 - \frac{5h^2}{12}k_i\right)y_i - \left(1 + \frac{h^2}{12}k_{i-1}\right)y_{i-1}}{1 + \frac{h^2}{12}k_{i+1}}

9.4 ⚠️ 注意事项

  • 需要两个起点值 y(0)y(0)y(h)y(h) 才能启动——不像 RK4 只要一个值 是三点递推
  • 通常先知道 y(0)y(0)y(0)y'(0),需用其他方法(如 Taylor 展开/RK4走一步)先求出 y(h)y(h)
  • 比 RK4 精度高且计算量小(每步只需一次 k(x)k(x) 估值)

10. Schrödinger 方程数值求解

10.1 球对称势的径向方程

22md2u(r)dr2+[V(r)+2l(l+1)2mr2]u(r)=Eu(r)-\frac{\hbar^2}{2m}\frac{d^2u(r)}{dr^2} + \left[V(r) + \frac{\hbar^2 l(l+1)}{2mr^2}\right]u(r) = E u(r)

定义有效势:

Veff(r)=V(r)+2l(l+1)2mr2 V_{\text{eff}}(r) = V(r)+ \frac{\hbar^2l(l+1)}{2mr^2}

径向方程就是:

22mu+Veffu=Eu -\frac{\hbar^2}{2m}u'' + V_{\text{eff}}u = Eu

整理成 Numerov 形式:

u+k(r;E)u=0 u''+ k(r;E)u=0

其中:

k(r;E)=2m2[EVeff(r)] k(r;E) = \frac{2m}{\hbar^2} \left[ E-V_{\text{eff}}(r) \right]

也就是:

k(r;E)=2m2[EV(r)]l(l+1)r2 k(r;E) = \frac{2m}{\hbar^2} \left[ E-V(r) \right] - \frac{l(l+1)}{r^2}

所以 Schrödinger 径向方程天然适合 Numerov。

其中 u(r)=rR(r)u(r) = rR(r),边界条件:$u(0) = 0,\ u(\infty) \to 0$

正好利用 上边学到的Numerov方法!!!

10.2 打靶法求解束缚态

束缚态能量要求离散!!!

单纯从 r=0r=0 往外积分有问题:

  • 如果 EE 不准,远处通常指数发散;
  • 即使 EE 很准,数值误差也可能激发发散解。

所以常用双向积分。


向外积分 Outward

从小 r=ϵr=\epsilon 开始,使用原点行为:

uout(r)rl+1 u_{\text{out}}(r)\sim r^{l+1}

可以取:

u(ϵ)=ϵl+1 u(\epsilon)=\epsilon^{l+1}

然后用 Taylor 或 RK4/Numerov 得到第二个点,开始向外积分。


向内积分 Inward

在足够大的 RmaxR_{\max} 处,束缚态远处衰减。

如果远处势能趋于 0,且束缚态 E<0E<0,则:

u+2mE2u0 u''+\frac{2mE}{\hbar^2}u\approx 0

因为 E<0E<0,令:

κ=2mE2 \kappa=\sqrt{\frac{-2mE}{\hbar^2}}

则:

uκ2u=0 u''-\kappa^2 u=0

解为:

u(r)=Aeκr+Beκr u(r)=Ae^{-\kappa r}+Be^{\kappa r}

束缚态要求不发散,所以:

u(r)eκr u(r)\sim e^{-\kappa r}

因此在 RmaxR_{\max} 取:

uin(Rmax)=eκRmax u_{\text{in}}(R_{\max})=e^{-\kappa R_{\max}}

然后从 RmaxR_{\max} 向内积分到匹配点 rmr_m


匹配条件

因为线性方程的解可以整体乘任意常数,所以不能直接要求:

uout(rm)=uin(rm) u_{\text{out}}(r_m)=u_{\text{in}}(r_m)

因为振幅可以缩放。

真正关键是形状要一致,也就是对数导数一致:

uout(rm)uout(rm)=uin(rm)uin(rm) \frac{u_{\text{out}}'(r_m)}{u_{\text{out}}(r_m)} = \frac{u_{\text{in}}'(r_m)}{u_{\text{in}}(r_m)}

定义匹配函数:

F(E)=uout(rm)uout(rm)uin(rm)uin(rm) F(E)= \frac{u_{\text{out}}'(r_m)}{u_{\text{out}}(r_m)} - \frac{u_{\text{in}}'(r_m)}{u_{\text{in}}(r_m)}

本征能量满足:

F(E)=0 F(E)=0

等价地,可以写成 Wronskian:

W(E)=uinuoutuoutuin W(E) = u_{\text{in}}u_{\text{out}}' - u_{\text{out}}u_{\text{in}}'

如果两者对数导数相等,则:

uinuout=uoutuin u_{\text{in}}u_{\text{out}}' = u_{\text{out}}u_{\text{in}}'

所以:

W(E)=0 W(E)=0

因此求本征能量就是求:

W(E)=0 W(E)=0

或者:

F(E)=0 F(E)=0

可以用:

  • 二分法;
  • 割线法;
  • 牛顿法;
  • 节点数扫描。
寻找束缚态本征解流程:
1. 从 r=0 向外积分 (outward integration)
2. 从 r=R∞ 向内积分 (inward integration)  
3. 在大距离 ρₘ 处匹配 (matching point)
4. 要求两个解的 Wronskian 满足:u_in·u_out' - u_out·u_in' 连续
5. 调节能量 E,重复上述步骤
→ 找到使匹配条件成立的 E = 本征能量

💡 物理直觉:束缚态能量是离散的——就像吉他弦只有特定频率才能共振。向外积分和向内积分只有在正确的能量 EnE_n 下才能光滑连接。

在一维或径向 Sturm-Liouville 问题中,束缚态有节点定理:

  • 基态没有节点;
  • 第一激发态有一个节点;
  • 第二激发态有两个节点;
  • 依此类推。

所以扫描能量时,可以通过节点数判断你找到的是哪一个本征态。

10.3 散射态与共振态

  • 散射边界条件:$u(r) \sim \sin(kr + \delta)$,提取相移 δ\delta
  • 共振态:能量为复数 EiΓ/2E - i\Gamma/2,相移突然增加 π/2\pi/2
  • 求解方法:复标度法 (Complex-scaling)、稳定化法 (Stabilization)、S-矩阵极点法

11. Green 函数与 Wronskian

11.1 核心问题

Green 函数是线性微分方程的“响应函数”。

考虑:

L[y]=f(x) L[y]=f(x)

如果能找到 G(x,ξ)G(x,\xi) 满足:

Lx[G(x,ξ)]=δ(xξ) L_x[G(x,\xi)]=\delta(x-\xi)

并满足同样的边界条件,那么解就是:

y(x)=abG(x,ξ)f(ξ)dξ y(x)=\int_a^b G(x,\xi)f(\xi)\,d\xi

设:

L[y]=y+k(x)y L[y]=y''+k(x)y

边界条件:

y(a)=0,y(b)=0 y(a)=0,\qquad y(b)=0

我们要构造:

G(x,ξ)+k(x)G(x,ξ)=δ(xξ) G''(x,\xi)+k(x)G(x,\xi)=\delta(x-\xi)

xξx\neq \xi 时:

δ(xξ)=0 \delta(x-\xi)=0

所以 Green 函数在左右两边都满足齐次方程:

G+kG=0 G''+kG=0

11.2 构造左右基本解

u<(x)u_<(x) 是满足左边界条件的齐次解:

u<(a)=0 u_<(a)=0

u>(x)u_>(x) 是满足右边界条件的齐次解:

u>(b)=0 u_>(b)=0

于是 Green 函数可以写成:

G(x,ξ)={A(ξ)u<(x),x<ξB(ξ)u>(x),x>ξ G(x,\xi) = \begin{cases} A(\xi)u_<(x), & x<\xi\\ B(\xi)u_>(x), & x>\xi \end{cases}

因为:

  • x<ξx<\xi 时要满足左端边界;
  • x>ξx>\xi 时要满足右端边界。

11.3 连续条件

Green 函数本身必须连续。

如果 GGx=ξx=\xi 处跳跃,那么 GG' 会有 delta,$G''$ 会有 delta 的导数 δ\delta',而方程右边只有 δ\delta,没有 δ\delta'

所以:

G(ξ,ξ)=G(ξ+,ξ) G(\xi^-,\xi)=G(\xi^+,\xi)

即:

Au<(ξ)=Bu>(ξ) A u_<(\xi)=B u_>(\xi)

11.4 导数跳跃条件

对方程在 ξϵ\xi-\epsilonξ+ϵ\xi+\epsilon 积分:

ξϵξ+ϵ[G+kG]dx=ξϵξ+ϵδ(xξ)dx \int_{\xi-\epsilon}^{\xi+\epsilon} \left[ G''+kG \right]dx = \int_{\xi-\epsilon}^{\xi+\epsilon} \delta(x-\xi)\,dx

右边:

1 1

左边第一项:

Gdx=G(ξ+)G(ξ) \int G''dx = G'(\xi^+)-G'(\xi^-)

第二项:

kGdx0 \int kG\,dx \to 0

因为区间长度趋于 0,且 GG 有限。

所以:

G(ξ+)G(ξ)=1 G'(\xi^+)-G'(\xi^-)=1

代入左右表达式:

G(ξ)=Au<(ξ) G'(\xi^-)=A u_<'(\xi)

因此:

Bu>(ξ)Au<(ξ)=1 B u_>'(\xi)-A u_<'(\xi)=1

11.5 解出 A,BA,B

我们有:

Au<(ξ)=Bu>(ξ) A u_<(\xi)=B u_>(\xi)

所以:

A=Bu>(ξ)u<(ξ) A=\frac{B u_>(\xi)}{u_<(\xi)}

代入跳跃条件:

Bu>(ξ)Bu>(ξ)u<(ξ)u<(ξ)=1 B u_>'(\xi) - \frac{B u_>(\xi)}{u_<(\xi)}u_<'(\xi) = 1

提取 BB

B[u>(ξ)u>(ξ)u<(ξ)u<(ξ)]=1 B \left[ u_>'(\xi) - \frac{u_>(\xi)u_<'(\xi)}{u_<(\xi)} \right] = 1

通分:

Bu<(ξ)u>(ξ)u>(ξ)u<(ξ)u<(ξ)=1 B \frac{ u_<(\xi)u_>'(\xi) - u_>(\xi)u_<'(\xi) } {u_<(\xi)} = 1

定义 Wronskian:

W(ξ)=u<(ξ)u>(ξ)u>(ξ)u<(ξ) W(\xi) = u_<(\xi)u_>'(\xi) - u_>(\xi)u_<'(\xi)

于是:

BW(ξ)u<(ξ)=1 B\frac{W(\xi)}{u_<(\xi)}=1

所以:

B=u<(ξ)W(ξ) B=\frac{u_<(\xi)}{W(\xi)}

再由连续条件:

A=u>(ξ)W(ξ) A=\frac{u_>(\xi)}{W(\xi)}

因此:

G(x,ξ)={u<(x)u>(ξ)W(ξ),x<ξu<(ξ)u>(x)W(ξ),x>ξ G(x,\xi) = \begin{cases} \dfrac{u_<(x)u_>(\xi)}{W(\xi)}, & x<\xi\\[8pt] \dfrac{u_<(\xi)u_>(x)}{W(\xi)}, & x>\xi \end{cases}

如果方程没有一阶导数项,Wronskian 是常数,所以也可以写成:

W W

而不写 W(ξ)W(\xi)



11.7 Green 函数和本征值的关系

如果:

W=0 W=0

说明 u{<} 和 u{>} 线性相关。

也就是说存在非零解同时满足左右边界条件。

这正是本征值问题的条件。

所以:

Green 函数的分母 WW 在本征值处为零。

这也解释了物理中常说:

Green 函数在能量本征值处有极点。

构造流程(配合 Numerov):

1. 从 a→b 向外积分齐次方程,得到 u<(x)|满足 a 端边界条件
2. 从 b→a 向内积分齐次方程,得到 u>(x)|满足 b 端边界条件
3. 计算 Wronskian W = u<·u>' - u>·u<'
4. 构造 G(x,ξ),积分求最终解

💡 物理直觉:Green 函数 = 线性响应函数。$G(x,\xi)$ 是"$\xi$ 处的单位脉冲在 xx 处引起多大的响应",与外场 ff 无关。这是整个线性响应理论的数学基础。


12. 有限差分法(Finite Difference)

12.1 基本思想

将导数用差分代替,把微分方程变成代数方程组。

一阶和二阶导数的中心差分近似(精度 O(h2)O(h^2)):

u(x)=u(x+h)u(xh)2h+O(h2)u'(x) = \frac{u(x+h)-u(x-h)}{2h} +O(h^2)

uiui+12ui+ui1h2u_i'' \approx \frac{u_{i+1}-2u_i+u_{i-1}}{h^2}

12.2 📐 数值例子:一维泊松方程

u(x)=f(x),u(0)=a, u(L)=b-u''(x) = f(x), \quad u(0)=a,\ u(L)=b

离散化【$N$ 个内点(未知),$h = L/(N+1)$ 】:

通常写成:

ui1+2uiui+1h2=fi \frac{-u_{i-1}+2u_i-u_{i+1}}{h^2}=f_i

其中:

fi=f(xi) f_i=f(x_i)

内部点方程

对于 i=1i=1

u0+2u1u2h2=f1 \frac{-u_0+2u_1-u_2}{h^2}=f_1

因为:

u0=a u_0=a

所以:

2u1u2h2=f1+ah2 \frac{2u_1-u_2}{h^2} = f_1+\frac{a}{h^2}

对于中间点 i=2,,N1i=2,\dots,N-1

ui1+2uiui+1h2=fi \frac{-u_{i-1}+2u_i-u_{i+1}}{h^2}=f_i

对于 i=Ni=N

uN1+2uNuN+1h2=fN \frac{-u_{N-1}+2u_N-u_{N+1}}{h^2}=f_N

因为:

uN+1=b u_{N+1}=b

所以:

uN1+2uNh2=fN+bh2 \frac{-u_{N-1}+2u_N}{h^2} = f_N+\frac{b}{h^2}

对于内部点转化为线性方程组 Au=bA\mathbf{u} = \mathbf{b}

1h2(210012100120100012)(u1u2u3uN)=(f1+a/h2f2f3fN+b/h2) \frac{1}{h^2} \begin{pmatrix} 2 & -1 & 0 & \cdots & 0 \\ -1 & 2 & -1 & \cdots & 0 \\ 0 & -1 & 2 & \cdots & 0 \\ \vdots & \vdots & \vdots & \ddots & -1 \\ 0 & 0 & 0 & -1 & 2 \end{pmatrix} \begin{pmatrix} u_1 \\ u_2 \\ u_3 \\ \vdots \\ u_N \end{pmatrix} = \begin{pmatrix} f_1 + a/h^2 \\ f_2 \\ f_3 \\ \vdots \\ f_N + b/h^2 \end{pmatrix}

说人话:一个二阶 ODE 的边值问题变成了一个三对角线性方程组!用 Thomas 算法 O(N)O(N) 秒解,干净利落。

import numpy as np

def solve_poisson_1d(a, b, f, L, N):
    """解 -u'' = f, u(0)=a, u(L)=b"""
    h = L / (N + 1)
    x = np.linspace(0, L, N+2)
    
    # 构造三对角矩阵 + RHS
    diag = 2 * np.ones(N) / h**2
    off_diag = -np.ones(N-1) / h**2
    rhs = f(x[1:-1])
    rhs[0] += a / h**2
    rhs[-1] += b / h**2
    
    # Thomas 算法 (三对角追赶法)
    # 向前消元
    c_prime = np.zeros(N-1)
    d_prime = np.zeros(N)
    c_prime[0] = off_diag[0] / diag[0]
    d_prime[0] = rhs[0] / diag[0]
    for i in range(1, N):
        if i < N-1:
            denom = diag[i] - off_diag[i-1] * c_prime[i-1]
            c_prime[i] = off_diag[i] / denom
        else:
            denom = diag[i] - off_diag[i-1] * c_prime[i-1]
        d_prime[i] = (rhs[i] - off_diag[i-1] * d_prime[i-1]) / denom
    
    # 回代
    u_interior = np.zeros(N)
    u_interior[-1] = d_prime[-1]
    for i in range(N-2, -1, -1):
        u_interior[i] = d_prime[i] - c_prime[i] * u_interior[i+1]
    
    u = np.zeros(N+2)
    u[0], u[-1] = a, b
    u[1:-1] = u_interior
    return x, u

# 示例:f(x)=sin(x), a=0, b=0, L=π
# u_exact(x) = sin(x) → 验证数值解

12.3 有限差分法 vs 打靶法

特性 打靶法 (Shooting) 有限差分法
问题类型 转化为 IVP + 迭代 直接离散为线性系统
精度 继承 RK/Numerov 精度 O(h2)O(h^2) 或更高阶差分
非线性方程 需牛顿/割线迭代 需解非线性代数方程
收敛依赖 对初始猜测敏感 依赖网格足够细
适合 一维问题 多维问题扩展性好

💡 口诀

一维光滑问题,打靶法很灵活; 线性边值问题,有限差分很稳; 多维边值/PDE,有限差分、有限元更主流。


13. 应用实例:TOV 方程与中子星

13.1 TOV 方程 (Tolman-Oppenheimer-Volkoff)

广义相对论中描述中子星结构的耦合 ODE 组:

dPdr=Gr2[ρ(r)+P(r)/c2][m(r)+4πr3P(r)/c2]12Gm(r)/(rc2)dmdr=4πr2ρ(r)\begin{aligned} \frac{dP}{dr} &= -\frac{G}{r^2}\frac{[\rho(r) + P(r)/c^2][m(r) + 4\pi r^3 P(r)/c^2]}{1 - 2Gm(r)/(rc^2)} \\ \frac{dm}{dr} &= 4\pi r^2 \rho(r) \end{aligned}

13.2 状态方程 (EOS)

核物理提供密度-压强关系。简化多方形式: $$P = K \rho^\gamma$$

典型参数:$\gamma = 2.75$,$K = 1.982 \times 10^{-6}$ [cgs]

13.3 求解策略

初始条件 (r=0):
  ρ(0) 给定(中心密度)
  P(0) = P(ρ(0))  从 EOS 得到
  m(0) = 0

用 RK4 从 r=0 向外积分
→ 每次步进:r → r + dr
  更新 P(r), m(r)(耦合方程组)
→ 直到 P(R) = 0(压力降到零)
→ 此时 R = 中子星半径,M = m(R) = 中子星质量

改变中心密度 ρ(0),重复 → 得到质量-半径关系
→ 最大质量 ≈ 2-3 倍太阳质量(取决于 EOS)

💡 物理直觉:用 RK4 从恒星中心往外积,密度(因此压力)一路下降。到表面压力为 0 → 这就是星体边界。不同的中心密度 → 不同的总质量 → 找到最大质量(超过此值星体会坍缩为黑洞)。

13.4 前沿研究

  • Chong-Ji Jiang et al., Chin. Phys. Lett. 2021, 38(5): 052101
  • 中子星物质状态方程仍是核物理前沿
  • 引力波观测 (GW170817) 给 EOS 带来新的约束

14. 总结对比表

14.1 初值问题方法总览

方法 类型 局部误差 步数 每步求值 稳定性 典型用途
Euler 显式 O(h2)O(h^2) 1 1 教学演示
Taylor 2阶 显式 O(h3)O(h^3) 1 需手动求导 中等 高精度小系统
Heun (RK2) 显式 O(h3)O(h^3) 1 2 中等 入门级实际计算
RK4 显式 O(h5)O(h^5) 1 4 ⭐ 工业标准
RKF45 显式-自适应 O(h6)O(h^6) 1 6 自适应步长
AB4 (多步) 显式 O(h5)O(h^5) 4 1 中等 长时间演化
AM3 (多步) 隐式 O(h5)O(h^5) 4 1+迭代 配合 AB 做 PECE
隐式梯形 隐式 O(h3)O(h^3) 1 迭代 极好 Stiff 方程
Gear 隐式-多步 O(h3)O(h^3)~ 多步 迭代 极好 Stiff 方程标准解
Numerov 专用显式 O(h6)O(h^6) 2 1 yy' 的二阶 ODE

14.2 边值问题方法总览

方法 核心思路 精度 计算量 适用
线性打靶法 两解叠加 继承积分器精度 两次积分 线性 BVP
非线性打靶+割线 参数搜索 继承积分器精度 多次积分 非线性 BVP
Green 函数法 脉冲响应分解 取决于积分方法 构造+积分 线性非齐次 BVP
有限差分法 离散→线性方程组 O(h2)O(h^2) 或更高 解三对角/稀疏矩阵 任意 BVP

14.3 关键联系与口诀

📚 核心记忆卡片

🔑 概念 💭 一句话总结
Euler 法 切线代替曲线,最粗糙但最直观
RK4 四点取样加权平均,性价比之王
多步法 利用历史信息减少函数求值次数
Stiff 方程 快慢分量混杂,显式方法必须小步长
隐式方法 牺牲每步计算量换取大步长稳定性
打靶法 把边值问题转化成带参数搜索的初值问题
Numerov 专攻无 y' 的二阶方程,精度超 RK4
Green 函数 系统的"脉冲响应",线性理论基石
有限差分 导数变差分,ODE 变矩阵方程
TOV 方程 RK4 积分 + EOS = 中子星质量-半径关系

Akuiro 整理补充 · 2026-07-01

使用社交账号登录

  • Loading...
  • Loading...
  • Loading...
  • Loading...
  • Loading...