考虑一阶常微分方程 y ′ = f ( x , y ) y' = f(x, y) y′=f(x,y),初始条件为 y ( x 0 ) = y 0 y(x_0) = y_0 y(x0)=y0,我们希望求解其在区间 [ x 0 , x n ] [x_0, x_n] [x0,xn] 上的数值解。为了简化问题,我们假设步长为 h = x n − x 0 n h = \frac{x_n - x_0}{n} h=nxn−x0,其中 n n n 表示迭代次数,即时间步数。
首先,我们可以使用泰勒级数展开 y ( x i + 1 ) y(x_{i+1}) y(xi+1),得到:
y ( x i + 1 ) = y ( x i ) + h y ′ ( x i ) + h 2 2 y ′ ′ ( x i ) + O ( h 3 ) y(x_{i+1}) = y(x_i) + h y'(x_i) + \frac{h^2}{2}y''(x_i) + O(h^3) y(xi+1)=y(xi)+hy′(xi)+2h2y′′(xi)+O(h3)
其中 O ( h 3 ) O(h^3) O(h3) 表示高阶项,其大小与 h 3 h^3 h3 同阶或更高。由于我们无法直接求得 y ′ ′ ( x i ) y''(x_i) y′′(xi),因此我们需要通过一阶导数 y ′ ( x i ) y'(x_i) y′(xi) 来近似计算二阶导数。
接下来,我们使用龙格-库塔方法的经典四阶公式,得到:
y i + 1 = y i + 1 6 ( k 1 + 2 k 2 + 2 k 3 + k 4 ) y_{i+1} = y_i + \frac{1}{6}(k_1 + 2k_2 + 2k_3 + k_4) yi+1=yi+61(k1+2k2+2k3+k4)
其中,
k 1 = h f ( x i , y i ) k 2 = h f ( x i + h 2 , y i + k 1 2 ) k 3 = h f ( x i + h 2 , y i + k 2 2 ) k 4 = h f ( x i + h , y i + k 3 ) \begin{aligned} k_1 &= hf(x_i, y_i) \\ k_2 &= hf(x_i + \frac{h}{2}, y_i + \frac{k_1}{2}) \\ k_3 &= hf(x_i + \frac{h}{2}, y_i + \frac{k_2}{2}) \\ k_4 &= hf(x_i + h, y_i + k_3) \end{aligned} k1k2k3k4=hf(xi,yi)=hf(xi+2h,yi+2k1)=hf(xi+2h,yi+2k2)=hf(xi+h,yi+k3)
这里的 k 1 , k 2 , k 3 , k 4 k_1, k_2, k_3, k_4 k1,k2,k3,k4 分别表示在 y i y_i yi 处的四个斜率。直观上来说,这些斜率是在 y i y_i yi 处、 y i y_i yi 到 y i + 1 y_{i+1} yi+1 之间的四个点处计算得到的。
将上式代入泰勒级数展开式,我们可以得到:
y i + 1 = y i + 1 6 ( k 1 + 2 k 2 + 2 k 3 + k 4 ) + O ( h 5 ) y_{i+1} = y_i + \frac{1}{6}(k_1 + 2k_2 + 2k_3 + k_4) + O(h^5) yi+1=yi+61(k1+2k2+2k3+k4)+O(h5)
这里的 O ( h 5 ) O(h^5) O(h5) 表示高阶项,其大小与 h 5 h^5 h5 同阶或更高。因此,龙格-库塔方法是一种五阶收敛的数值积分方法,其误差随步长的减小而快速收敛。
def runge_kutta(self, f, x0, y0, h, n):
"""
使用龙格-库塔方法求解一阶常微分方程的数值解
:param f: 函数 f(x, y) 的句柄,表示 y' = f(x, y)
:param x0: 自变量的初始值
:param y0: 因变量的初始值
:param h: 步长
:param n: 迭代次数
:return: 返回一个二元组,包含自变量和因变量的数组
"""
x = np.zeros(n + 1)
y = np.zeros(n + 1)
x[0] = x0
y[0] = y0
for i in range(n):
k1 = f(x[i], y[i])
k2 = f(x[i] + h / 2, y[i] + h / 2 * k1)
k3 = f(x[i] + h / 2, y[i] + h / 2 * k2)
k4 = f(x[i] + h, y[i] + h * k3)
y[i + 1] = y[i] + h / 6 * (k1 + 2 * k2 + 2 * k3 + k4)
x[i + 1] = x[i] + h
return x, y