本文介绍了常微分方程的初值问题、边值问题与本征值问题的数值解法,正确理解这些方法,对MATLAB或其它编程语言计算常微分方程有着极大帮助,同时而言也有利于后续偏微分方程的学习。
首先再来认识一下微分方程和常微分方程。
微分方程是未知函数及其导数或微分的关系,例如: d y d x = 2 x \frac{\mathrm{d}y}{\mathrm{d}x}=2x dxdy=2x 等。函数方程是关于未知数 x x x的,而微分方程则是关于 x x x的导数或微分的,这就是微分方程 (Differential Equation)。
常微分方程则是一个未知函数与其导数或微分的关系,“常”(Ordinary)便表示“一个”未知函数这种平常的形式 (平常是相较于多个未知函数的偏微分而言)。因此,这样的只存在一个未知函数的导数/微分的关系式称作常微分方程(Ordinary Differential Equation -> ODE)。
一般形式 n n n阶常微分方程为 F ( x , y , y ′ , … , y ( n ) ) = 0 F(x,y,y',\dots,y^{(n)})=0 F(x,y,y′,…,y(n))=0,一阶常微分方程的形式为 y ′ ( x ) = d y d x = k ( x , y ) y'(x)=\frac{\mathrm{d}y}{\mathrm{d}x}=k(x,y) y′(x)=dxdy=k(x,y)。
常微分方程的两大类问题为初值问题和边值问题。初值问题: y y y在 t = 0 t=0 t=0时的值是给定的,求解 t > 0 t>0 t>0 时方程的解;边值问题:方程在某些点的值被给定,求解其他点的值。
为了方便讨论,我们以一阶常微分方程为例,并加入定解条件 y ( x 0 ) = y 0 y(x_0)=y_0 y(x0)=y0,因此得到方程组 { y ′ ( x ) = d y d x = k ( x , y ) y ( x 0 ) = y 0 \left\{\begin{array}{l} y^{\prime}(x)=\frac{d y}{d x}=k(x, y) \\ y\left(x_{0}\right)=y_{0} \end{array}\right. {y′(x)=dxdy=k(x,y)y(x0)=y0 ,那么有了这样的方程组以后,如何求解 y ( x ) y(x) y(x)呢?
微分方程有两种常见的物理图像,一种为对时间的微分,例如位移的导数为速度 x ′ = d x d t x'=\frac{\mathrm{d}x}{\mathrm{d}t} x′=dtdx等;而另一种即为曲线的斜率 y ′ = d y d x y'=\frac{\mathrm{d}y}{\mathrm{d}x} y′=dxdy,在此处使用了第二种物理图像进行推导。
k ( x , y ) k(x,y) k(x,y)表示平面上各点处的斜率。
上述方程组给出了平面上点的坐标以及点对应的斜率值,可以使用欧拉法对 y ( x ) y(x) y(x) 进行迭代的近似求解。求解分析如下:
已知 x = x 0 x=x_{0} x=x0 时 y = y 0 y=y_{0} y=y0 ,且斜率为 y ′ ( x 0 ) = k ( x 0 , y 0 ) y^{\prime}\left(x_{0}\right)=k\left(x_{0}, y_{0}\right) y′(x0)=k(x0,y0) ,那么就可以用过该点且斜率为 y ′ ( x 0 ) y^{\prime}\left(x_{0}\right) y′(x0) 的直线近似求解 x 0 x_{0} x0 附近一点 x 1 x_{1} x1 的函数值。
构建直线: y ( x ) = y 0 + k ( x 0 , y 0 ) ( x − x 0 ) y(x)=y_{0}+k\left(x_{0}, y_{0}\right)\left(x-x_{0}\right) y(x)=y0+k(x0,y0)(x−x0),那么,在 x = x 1 x=x_{1} x=x1 时,求得
y ( x 1 ) = y 0 + k ( x 0 , y 0 ) ( x 1 − x 0 ) y\left(x_{1}\right)=y_{0}+k\left(x_{0}, y_{0}\right)\left(x_{1}-x_{0}\right) y(x1)=y0+k(x0,y0)(x1−x0)
即在 x = x 1 x=x_{1} x=x1 时, y = y ( x 1 ) y=y\left(x_{1}\right) y=y(x1),且斜率为 y ′ ( x 1 ) = k ( x 1 , y 1 ) y^{\prime}\left(x_{1}\right)=k\left(x_{1}, y_{1}\right) y′(x1)=k(x1,y1) 。重复以上步骤,可以求得 y ( x 2 ) , y ( x 3 ) , ⋯ , y ( x n ) y\left(x_{2}\right), y\left(x_{3}\right), \cdots, y\left(x_{n}\right) y(x2),y(x3),⋯,y(xn)
如果等间隔取 x x x 值,即 x 1 − x 0 = x 2 − x 1 = x 3 − x 2 = ⋯ = x n − x n − 1 = h x_{1}-x_{0}=x_{2}-x_{1}=x_{3}-x_{2}=\cdots=x_{n}-x_{n-1}=h x1−x0=x2−x1=x3−x2=⋯=xn−xn−1=h ,也即 x n = x 0 + n ⋅ h x_{n}=x_{0}+n \cdot h xn=x0+n⋅h 可以得到
y ( x 1 ) = y 0 + k ( x 0 , y 0 ) ⋅ h y ( x 2 ) = y 1 + k ( x 1 , y 1 ) ⋅ h ⋮ y ( x n ) = y n − 1 + k ( x n − 1 , y n − 1 ) ⋅ h \begin{gathered} y\left(x_{1}\right)=y_{0}+k\left(x_{0}, y_{0}\right) \cdot h \\ y\left(x_{2}\right)=y_{1}+k\left(x_{1}, y_{1}\right) \cdot h \\ \vdots \\ y\left(x_{n}\right)=y_{n-1}+k\left(x_{n-1}, y_{n-1}\right) \cdot h \end{gathered} y(x1)=y0+k(x0,y0)⋅hy(x2)=y1+k(x1,y1)⋅h⋮y(xn)=yn−1+k(xn−1,yn−1)⋅h
总结为:
{ y ( x n ) = y n − 1 + k ( x n − 1 , y n − 1 ) ⋅ h x n = x 0 + n ⋅ h \left\{\begin{array}{l} y\left(x_{n}\right)=y_{n-1}+k\left(x_{n-1}, y_{n-1}\right) \cdot h \\ x_{n}=x_{0}+n \cdot h \end{array}\right. {y(xn)=yn−1+k(xn−1,yn−1)⋅hxn=x0+n⋅h
该公式便是欧拉公式。
推导结束之后我们再来找找欧拉法的bug
。可以注意到,欧拉法最大的问题在于斜率
的选取,公式 y ( x n ) = y n − 1 + f ( x n − 1 , y n − 1 ) ⋅ h = y n − 1 + y ′ ( x n − 1 ) ⋅ h y\left(x_{n}\right)=y_{n-1}+f\left(x_{n-1}, y_{n-1}\right) \cdot h=y_{n-1}+y'(x_{n-1}) \cdot h y(xn)=yn−1+f(xn−1,yn−1)⋅h=yn−1+y′(xn−1)⋅h 中,我们用 x n − 1 x_{n-1} xn−1处的斜率 y ′ ( x n − 1 ) y'(x_{n-1}) y′(xn−1)乘间距 h h h表示 y ( x n ) y(x_n) y(xn) 与 y ( x n − 1 ) y(x_{n-1}) y(xn−1) 的差值,这样显然存在不小的误差。
如果读者是从按专栏顺序读下来的,那应该可以体会到,数值计算就是妥协的艺术
,欧拉法便是在此处对斜率
做了比较大的妥协。而我们可以使用更好的“妥协方法”将斜率表示出来,这样的妥协艺术就是 后退欧拉法
,梯形法
,改进欧拉法
。
欧拉法
: y n + 1 = y n + h k ( x n , y n ) y_{n+1}=y_{n}+h k\left(x_{n}, y_{n}\right) yn+1=yn+hk(xn,yn);
后退欧拉法
: y n + 1 = y n + h k ( x n + 1 , y n + 1 ) y_{n+1}=y_{n}+h k\left(x_{n+1}, y_{n+1}\right) yn+1=yn+hk(xn+1,yn+1);
梯形法
: y n + 1 = y n + h 2 ( k ( x n , y n ) + k ( x n + 1 , y n + 1 ) ) y_{n+1}=y_{n}+\frac{h}{2}\left(k\left(x_{n}, y_{n}\right)+k\left(x_{n+1}, y_{n+1}\right)\right) yn+1=yn+2h(k(xn,yn)+k(xn+1,yn+1));
改进欧拉法
: y n + 1 = y n + h 2 ( k ( x n , y n ) + k ( x n + 1 , y n + h k ( x n , y n ) ) ) y_{n+1}=y_{n}+\frac{h}{2}\left(k\left(x_{n}, y_{n}\right)+k\left(x_{n+1}, y_{n}+h k\left(x_{n}, y_{n}\right)\right)\right) yn+1=yn+2h(k(xn,yn)+k(xn+1,yn+hk(xn,yn)))
龙格库塔法核心思路与欧拉法相似,甚至欧拉法就是龙格库塔法的一种
由中值定理,得 y ( x n + 1 ) − y ( x n ) h = y ˙ ( x n + θ k ) ( 0 < θ < 1 ) \frac{y(x_{n+1})-y(x_n)}{h}=\dot{y}(x_n+\theta k)\ (0<\theta<1) hy(xn+1)−y(xn)=y˙(xn+θk) (0<θ<1),将它改写为 y ( x n + 1 ) = y ( x n ) + h k ave y\left(x_{n+1}\right)=y\left(x_{n}\right)+h k_{\text {ave }} y(xn+1)=y(xn)+hkave ,平均斜率为
k a v e = f ( x n + θ h , y ( x n + θ h ) ) k_{\mathrm{ave}}=f\left(x_{n}+\theta h, y\left(x_{n}+\theta h\right)\right) kave=f(xn+θh,y(xn+θh))
如果能确定平均斜率,就能从 y ( x n ) y\left(x_{n}\right) y(xn) 求出后面的 y ( t i + 1 ) y\left(t_{i+1}\right) y(ti+1)。
拉格朗日中值定理:若 y = f ( x ) y=f(x) y=f(x) 满足:(1) 在区间 [ a , b ] [a, b] [a,b] 上连续;(2) 在区间 ( a , b ) (a, b) (a,b) 内可导,则至少存在一点 ξ ∈ ( a , b ) \xi \in(a, b) ξ∈(a,b),使 f ′ ( ξ ) = f ( b ) − f ( a ) b − a f^{\prime}(\xi)=\frac{f(b)-f(a)}{b-a} f′(ξ)=b−af(b)−f(a)
用 K 1 , K 2 K_1,K_2 K1,K2分别表示 x n , x n + 1 x_{n},x_{n+1} xn,xn+1的斜率,由于 x n + 1 x_{n+1} xn+1 的斜率 K 2 K_{2} K2 还是末知,所以先用欧拉法求得 y ( x n + 1 ) y\left(x_{n+1}\right) y(xn+1) 的预报值 y ˉ n + 1 = y n + h K 1 = y n + h k ( x n , y n ) \bar{y}_{n+1}=y_{n}+h K_{1}=y_{n}+h k\left(x_{n}, y_{n}\right) yˉn+1=yn+hK1=yn+hk(xn,yn),再用预报值计算 x n + 1 x_{n+1} xn+1 处的斜率值 K 2 = k ( x n + 1 , y ˉ n + 1 ) = k ( x n + 1 , y n + h k ( x n , y n ) ) K_{2}=k\left(x_{n+1}, \bar{y}_{n+1}\right)=k\left(x_{n+1}, y_{n}+h k\left(x_{n}, y_{n}\right)\right) K2=k(xn+1,yˉn+1)=k(xn+1,yn+hk(xn,yn))。
因此 y n + 1 = y n + h 2 ( K 1 + K 2 ) = y n + h 2 [ k ( x n , y n ) + k ( x n + 1 , y n + h k ( x n , y n ) ) ] y_{n+1} =y_{n}+\frac{h}{2}\left(K_{1}+K_{2}\right) =y_{n}+\frac{h}{2}\left[k\left(x_{n}, y_{n}\right)+k\left(x_{n+1}, y_{n}+h k\left(x_{n}, y_{n}\right)\right)\right] yn+1=yn+2h(K1+K2)=yn+2h[k(xn,yn)+k(xn+1,yn+hk(xn,yn))]
这就是改进的欧拉公式
,通常写成
{ y n + 1 = y n + h 2 ( K 1 + K 2 ) K 1 = k ( x n , y n ) K 2 = k ( x n + h , y n + h K 1 ) \left\{\begin{array}{l} y_{n+1}=y_{n}+\frac{h}{2}\left(K_{1}+K_{2}\right) \\ K_{1}=k\left(x_{n}, y_{n}\right) \\ K_{2}=k\left(x_{n}+h, y_{n}+h K_{1}\right) \end{array}\right. ⎩⎨⎧yn+1=yn+2h(K1+K2)K1=k(xn,yn)K2=k(xn+h,yn+hK1)
为了提高精度,我们可以多取几点的斜率值作加权平均当作平均斜率 k ave k_{\text {ave }} kave ,这就是龙格-库塔法
的基本思想。
一般的显式龙格-库塔法可以写成
{ y n + 1 = y n + h ∑ m = 1 N λ m K m K 1 = k ( x n , y n ) K m = k ( x n + α m h , y n + h ∑ j = 1 m − 1 β m j K j ) , m = 2 , 3 , ⋯ , N \begin{cases} y_{n+1}=y_{n}+h \sum_{m=1}^{N} \lambda_{m} K_{m}\\ K_{1}=k\left(x_{n}, y_{n}\right) \\ K_{m}=k\left(x_{n}+\alpha_m h, y_{n}+h \sum_{j=1}^{m-1} \beta_{m j} K_{j}\right), \quad m=2,3, \cdots, N \end{cases} ⎩⎪⎪⎨⎪⎪⎧yn+1=yn+h∑m=1NλmKmK1=k(xn,yn)Km=k(xn+αmh,yn+h∑j=1m−1βmjKj),m=2,3,⋯,N
其中的 λ m , α m , β m j \lambda_{m}, \alpha_{m}, \beta_{m j} λm,αm,βmj 都是常数。确定这些常数的原则是,使局部截断误差关于 h h h 的阶数尽可能的高。
龙格库塔法相较于欧拉公式的优势在于,其通过中值定理,可以得到更加准确的平均值公式。
如果在改进的欧拉公式中将边界点 x n + 1 x_{n+1} xn+1 替换为区间中内的某个点 x n + p = x n + p h ( 0 < p ⩽ 1 ) x_{n+p}=x_{n}+p h \ (0 xn+p=xn+ph (0<p⩽1)
接下来这步是关键,我们取平均斜率 k ave ≈ λ 1 K 1 + λ 2 K 2 k_{\text {ave }} \approx \lambda_{1} K_{1}+\lambda_{2} K_{2} kave ≈λ1K1+λ2K2,其中 λ 1 , λ 2 \lambda_{1}, \lambda_{2} λ1,λ2 是待定的系数。
这样得到的公式为
{ K 1 = k ( x n , y n ) K 2 = k ( x n + p h , y n + p h K 1 ) y n + 1 = y n + h ( λ 1 K 1 + λ 2 K 2 ) \left\{\begin{array}{l} K_{1}=k\left(x_{n}, y_{n}\right) \\ K_{2}=k\left(x_{n}+p h, y_{n}+p h K_{1}\right) \\ y_{n+1}=y_{n}+h\left(\lambda_{1} K_{1}+\lambda_{2} K_{2}\right) \end{array}\right. ⎩⎨⎧K1=k(xn,yn)K2=k(xn+ph,yn+phK1)yn+1=yn+h(λ1K1+λ2K2)
我们将相关参数带入求解 λ 1 , λ 2 , p \lambda_{1}, \lambda_{2}, p λ1,λ2,p
K 1 = f ( x n , y n ) = y ˙ ( x n ) K 2 = f ( x n + p h , y n + p h K 1 ) = f ( x n , y n ) + p h f ˙ ( x n , y n ) + O ( h 2 ) = y ˙ ( x n ) + p h y ¨ ( x n ) + O ( h 2 ) y ~ n + 1 = y ( t n ) + h ( λ 1 + λ 2 ) y ˙ ( x n ) + λ 2 p h 2 y ¨ ( x n ) + O ( h 3 ) \begin{aligned} K_{1} &=f\left(x_{n}, y_{n}\right)=\dot{y}\left(x_{n}\right) \\ K_{2} &=f\left(x_{n}+p h, y_{n}+p h K_{1}\right) \\ &=f\left(x_{n}, y_{n}\right)+p h \dot{f}\left(x_{n}, y_{n}\right)+O\left(h^{2}\right) \\ &=\dot{y}\left(x_{n}\right)+p h \ddot{y}\left(x_{n}\right)+O\left(h^{2}\right) \\ \tilde{y}_{n+1} &=y\left(t_{n}\right)+h\left(\lambda_{1}+\lambda_{2}\right) \dot{y}\left(x_{n}\right)+\lambda_{2} p h^{2} \ddot{y}\left(x_{n}\right)+O\left(h^{3}\right) \end{aligned} K1K2y~n+1=f(xn,yn)=y˙(xn)=f(xn+ph,yn+phK1)=f(xn,yn)+phf˙(xn,yn)+O(h2)=y˙(xn)+phy¨(xn)+O(h2)=y(tn)+h(λ1+λ2)y˙(xn)+λ2ph2y¨(xn)+O(h3)
将它与 y ( x n + 1 ) y\left(x_{n+1}\right) y(xn+1) 在 x n x_{n} xn 处的泰勒展开式对比 y ( x n + 1 ) = y ( x n ) + h y ˙ ( x n ) + h 2 2 y ¨ ( x n ) + O ( h 3 ) y\left(x_{n+1}\right)=y\left(x_{n}\right)+h \dot{y}\left(x_{n}\right)+\frac{h^{2}}{2} \ddot{y}\left(x_{n}\right)+O\left(h^{3}\right) y(xn+1)=y(xn)+hy˙(xn)+2h2y¨(xn)+O(h3)。对比可见,若要局部截断误差达到 O ( h 3 ) O\left(h^{3}\right) O(h3),则要求有
λ 1 + λ 2 = 1 , λ 2 p = 1 2 \lambda_{1}+\lambda_{2}=1, \quad \lambda_{2} p=\frac{1}{2} λ1+λ2=1,λ2p=21
两个方程三个参数,因此 λ 1 , λ 2 , p \lambda_1,\lambda_2,p λ1,λ2,p可以有无穷组解,这些解带入 { K 1 = k ( x n , y n ) K 2 = k ( x n + p h , y n + p h K 1 ) y n + 1 = y n + h ( λ 1 K 1 + λ 2 K 2 ) \left\{\begin{array}{l} K_{1}=k\left(x_{n}, y_{n}\right) \\ K_{2}=k\left(x_{n}+p h, y_{n}+p h K_{1}\right) \\ y_{n+1}=y_{n}+h\left(\lambda_{1} K_{1}+\lambda_{2} K_{2}\right) \end{array}\right. ⎩⎨⎧K1=k(xn,yn)K2=k(xn+ph,yn+phK1)yn+1=yn+h(λ1K1+λ2K2) 后得到的全部公式,统称为二阶龙格-库塔公式
。
当我们选取 λ 1 = λ 2 = 1 / 2 , p = 1 \lambda_{1}=\lambda_{2}=1 / 2, \quad p=1 λ1=λ2=1/2,p=1 时,就得到前面的欧拉公式。如果取中点 x n + 1 / 2 x_{n+1 / 2} xn+1/2 的斜率为 K 2 K_{2} K2,即取 p = 1 / 2 , λ 1 = 0 , λ 2 = 1 p=1 / 2, \ \lambda_{1}=0, \ \lambda_{2}=1 p=1/2, λ1=0, λ2=1,就得到变形的欧拉公式 (中点公式) 为 { y n + 1 = y n + h K 2 K 1 = f ( x n , y n ) K 2 = f ( x n + h 2 , y n + h 2 K 1 ) \left\{\begin{array}{l} y_{n+1}=y_{n}+h K_{2} \\ K_{1}=f\left(x_{n}, y_{n}\right) \\ K_{2}=f\left(x_{n}+\frac{h}{2}, y_{n}+\frac{h}{2} K_{1}\right) \end{array}\right. ⎩⎨⎧yn+1=yn+hK2K1=f(xn,yn)K2=f(xn+2h,yn+2hK1)
三阶的龙格-库塔公式是三个点 x n , x n + p , x n + q x_n, x_{n+p}, x_{n+q} xn,xn+p,xn+q 的斜率值 K 1 , K 2 , K 3 K_{1}, K_{2}, K_{3} K1,K2,K3 的加权平均。所得的公式形式为 y n + 1 = y n + h ( λ 1 K 1 + λ 2 K 2 + λ 3 K 3 ) y_{n+1}=y_{n}+h\left(\lambda_{1} K_{1}+\lambda_{2} K_{2}+\lambda_{3} K_{3}\right) yn+1=yn+h(λ1K1+λ2K2+λ3K3)。
假定 K 1 , K 2 K_{1}, K_{2} K1,K2 仍取上节的形式,第三个点 x n + q x_{n+q} xn+q 的取法是 x n + q = x n + q h , 0 < p ⩽ q ⩽ 1 x_{n+q}=x_{n}+q h, \ 0 xn+q=xn+qh, 0<p⩽q⩽1
y ˉ n + q = y n + q h ( r K 1 + s K 2 ) K s = f ( x n + q , y ˉ n + q ) = f ( x n + q , y n + q h ( r K 1 + s K 2 ) ) \begin{aligned} \bar{y}_{n+q} &=y_{n}+q h\left(r K_{1}+s K_{2}\right) \\ K_{s} &=f\left(x_{n+q}, \bar{y}_{n+q}\right) \\ &=f\left(x_{n+q}, y_{n}+q h\left(r K_{1}+s K_{2}\right)\right) \end{aligned} yˉn+qKs=yn+qh(rK1+sK2)=f(xn+q,yˉn+q)=f(xn+q,yn+qh(rK1+sK2))
所得的公式形式为
{ y n + 1 = y n + h ( λ 1 K 1 + λ 2 K 2 + λ 3 K 3 ) K 1 = f ( x n , y n ) K 2 = f ( x n + p h , y n + p h K 1 ) K 3 = f ( x n + q h , y n + q h ( r K 1 + s K 2 ) ) \left\{\begin{array}{l} y_{n+1}=y_{n}+h\left(\lambda_{1} K_{1}+\lambda_{2} K_{2}+\lambda_{3} K_{3}\right) \\ K_{1}=f\left(x_{n}, y_{n}\right) \\ K_{2}=f\left(x_{n}+p h, y_{n}+p h K_{1}\right) \\ K_{3}=f\left(x_{n}+q h, y_{n}+q h\left(r K_{1}+s K_{2}\right)\right) \end{array}\right. ⎩⎪⎪⎨⎪⎪⎧yn+1=yn+h(λ1K1+λ2K2+λ3K3)K1=f(xn,yn)K2=f(xn+ph,yn+phK1)K3=f(xn+qh,yn+qh(rK1+sK2))
适当地选择其中的参数,使得局部截断误差为 O ( h 4 ) O\left(h^{4}\right) O(h4) 。因此,利用泰勒展开并采用二阶龙格库塔法参数推导,可以得到七个参数所满足的五个条件:
{ r + s = 1 λ 1 + λ 2 + λ 3 = 1 λ 2 p + λ 3 q = 1 2 λ 2 p 2 + λ 3 q 2 = 1 3 λ 3 p q s = 1 6 \left\{\begin{array}{l} r+s=1 \\ \lambda_{1}+\lambda_{2}+\lambda_{3}=1 \\ \lambda_{2} p+\lambda_{3} q=\frac{1}{2} \\ \lambda_{2} p^{2}+\lambda_{3} q^{2}=\frac{1}{3} \\ \lambda_{3} p q s=\frac{1}{6} \end{array}\right. ⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧r+s=1λ1+λ2+λ3=1λ2p+λ3q=21λ2p2+λ3q2=31λ3pqs=61
它有无穷组解,都称为三阶龙格–库塔公式
。下面就是其中的一种:
{ y n + 1 = y n + h 6 ( K 1 + 4 K 2 + K 3 ) K 1 = f ( x n , y n ) K 2 = f ( x n + h 2 , y n + h 2 K 1 ) K 3 = f ( x n + h , y n + h ( − K n + 2 K 2 ) ) \left\{\begin{array}{l} y_{n+1}=y_{n}+\frac{h}{6}\left(K_{1}+4 K_{2}+K_{3}\right) \\ K_{1}=f\left(x_{n}, y_{n}\right) \\ K_{2}=f\left(x_{n}+\frac{h}{2}, y_{n}+\frac{h}{2} K_{1}\right) \\ K_{3}=f\left(x_{n}+h, y_{n}+h\left(-K_{n}+2 K_{2}\right)\right) \end{array}\right. ⎩⎪⎪⎨⎪⎪⎧yn+1=yn+6h(K1+4K2+K3)K1=f(xn,yn)K2=f(xn+2h,yn+2hK1)K3=f(xn+h,yn+h(−Kn+2K2))
四阶的龙格-库塔法也称经典的龙格-库塔法
。计算公式是:
{ y n + 1 = y i + 1 6 ( k 1 + 2 k 2 + 2 k 3 + k 4 ) k 1 = h f ( x n , y n ) k 2 = h f ( x n + h 2 , y n + k 1 2 ) k 3 = h f ( x n + h 2 , y n + k 2 2 ) k 4 = h f ( x n + h , y i + k 3 ) \left\{\begin{array}{l} y_{n+1}=y_{i}+\frac{1}{6}\left(k_{1}+2 k_{2}+2 k_{3}+k_{4}\right) \\ k_{1}=h f\left(x_{n}, y_{n}\right) \\ k_{2}=h f\left(x_{n}+\frac{h}{2}, y_{n}+\frac{k_{1}}{2}\right) \\ k_{3}=h f\left(x_{n}+\frac{h}{2}, y_{n}+\frac{k_{2}}{2}\right) \\ k_{4}=h f\left(x_{n}+h, y_{i}+k_{3}\right) \end{array}\right. ⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧yn+1=yi+61(k1+2k2+2k3+k4)k1=hf(xn,yn)k2=hf(xn+2h,yn+2k1)k3=hf(xn+2h,yn+2k2)k4=hf(xn+h,yi+k3)
经典的龙格-库塔法的总体截断误差是 O ( h 4 ) O\left(h^{4}\right) O(h4) 。
正如我们在 数值计算与MATLAB微积分 提到过的自适应辛普森算法可以自动调整步长一样,变步长的龙格-库塔法也有相似的功能。
变步长的原因:之前介绍的龙格-库塔法都是定步长的,但从每一步看,似乎步长越小,截断误差就越小。然而实际上,在步长过小时,不但会导致计算量增大,还可能因为舍入误差的积累导致总误差反而增大。因此我们可以给龙格-库塔法增加变步长功能以尽量减小误差。
以经典龙格-库塔法为例,步长为 h h h时求得的近似值为 y n + 1 ( h ) y_{n+1}^{(h)} yn+1(h),步长折半时又得到近似值 y n + 1 ( h 2 ) y_{n+1}^{(\frac{h}{2})} yn+1(2h),我们可以通过检查步长折半前后,计算结果的偏差 Δ = ∣ y n + 1 ( h 2 ) − y n + 1 ( h ) ∣ \Delta=\mid y_{n+1}^{(\frac{h}{2})}-y_{n+1}^{(h)}\mid Δ=∣yn+1(2h)−yn+1(h)∣ 来判断所取步长是否合适。具体可分以下两种情况:
(1) 对于给定的精度 ε \varepsilon ε,如果 Δ > ε \Delta>\varepsilon Δ>ε,就反复将步长折半计算直至 Δ < ε \Delta<\varepsilon Δ<ε 为止,这时取步长折半后的 “新值” y n + 1 ( h 2 ) y_{n+1}^{\left(\frac{h}{2}\right)} yn+1(2h) 作为结果。
(2) 如果 Δ < ε \Delta<\varepsilon Δ<ε,就反复将步长加倍直至 Δ > ε \Delta>\varepsilon Δ>ε 为止,这时取步长加倍前的 “旧值” 作为结果。
这种通过步长折半或加倍的计算的方法就叫变步长方法。
高阶常微分方程可以变为一阶常微分方程组,然后再求解。
以二阶常微分方程 d 2 x ( t ) d t 2 = − x ( t ) \frac{\mathrm{d}^{2} x(t)}{\mathrm{d} t^{2}}=-x(t) dt2d2x(t)=−x(t) 为例。令 y = ( x ( t ) d x ( t ) d t ) = ( y 1 ( t ) y 2 ( t ) ) y=\left(\begin{array}{l}x(t) \\ \frac{\mathrm{d} x(t)}{\mathrm{d} t}\end{array}\right)=\left(\begin{array}{l}y_{1}(t) \\ y_{2}(t)\end{array}\right) y=(x(t)dtdx(t))=(y1(t)y2(t)) ,因此 y ˙ = ( y 2 ( t ) − y 1 ( t ) ) \dot{y}=\left(\begin{array}{c}y_{2}(t) \\ -y_{1}(t)\end{array}\right) y˙=(y2(t)−y1(t)),所以 d d t ( y 1 ( t ) y 2 ( t ) ) = ( y 2 ( t ) − y 1 ( t ) ) \frac{d}{dt} \left(\begin{array}{l}y_{1}(t) \\ y_{2}(t)\end{array}\right)=\left(\begin{array}{c}y_{2}(t) \\ -y_{1}(t)\end{array}\right) dtd(y1(t)y2(t))=(y2(t)−y1(t))。
再以 y ′ ′ ′ + y 2 − t = 0 y'''+y^2-t=0 y′′′+y2−t=0 为例, d d t ( y 1 y 2 y 3 ) = ( y 2 y 3 − y 1 2 + t ) \frac{d}{dt} \left(\begin{array}{l}y_{1} \\ y_{2}\\ y_3 \end{array}\right) = \left(\begin{array}{l}y_{2} \\ y_{3}\\ -y_1^2+t \end{array}\right) dtd⎝⎛y1y2y3⎠⎞=⎝⎛y2y3−y12+t⎠⎞。
通过这两个例子可以看出,我们以 y 1 y_1 y1 表示原函数, y n y_n yn表示原函数的 ( n − 1 ) (n-1) (n−1)阶导数,然后对 ( y 1 y 2 … y n − 1 ) \left(\begin{array}{l}y_{1} \\ y_{2}\\ \dots\\ y_{n-1} \end{array}\right) ⎝⎜⎜⎛y1y2…yn−1⎠⎟⎟⎞ 求导得到 ( y 2 y 3 … y n ) \left(\begin{array}{l}y_{2} \\ y_{3}\\ \dots\\ y_{n} \end{array}\right) ⎝⎜⎜⎛y2y3…yn⎠⎟⎟⎞,求解几元问题就需要几个方程,除了导数关系外,我们可以把带求解方程组带入,因此这样就凑齐了方程组可以准备求解。
具体求解步骤便是对方程组使用龙格库塔法等数值解法求解常微分方程组。
考虑方程组
{ y ′ = f ( x , y , z ) , y ( x 0 ) = y 0 z ′ = g ( x , y , z ) , z ( x 0 ) = z 0 \begin{cases}y^{\prime}=f(x, y, z), & y\left(x_{0}\right)=y_{0} \\ z^{\prime}=g(x, y, z), & z\left(x_{0}\right)=z_{0}\end{cases} {y′=f(x,y,z),z′=g(x,y,z),y(x0)=y0z(x0)=z0
其经典四阶龙格-库塔格式如下:
对于 n = 0 , 1 , 2 , … n=0,1,2, \ldots n=0,1,2,…, 计算
{ y n + 1 = y n + h 6 ( K 1 + 2 K 2 + 2 K 3 + K 4 ) z n + 1 = z n + h 6 ( L 1 + 2 L 2 + 2 L 3 + L 4 ) \left\{\begin{array}{l} y_{n+1}=y_{n}+\frac{h}{6}\left(K_{1}+2 K_{2}+2 K_{3}+K_{4}\right) \\ z_{n+1}=z_{n}+\frac{h}{6}\left(L_{1}+2 L_{2}+2 L_{3}+L_{4}\right) \end{array}\right. {yn+1=yn+6h(K1+2K2+2K3+K4)zn+1=zn+6h(L1+2L2+2L3+L4)
其中
{ K 1 = f ( x n , y n , z n ) , L 1 = g ( x n , y n , z n ) K 2 = f ( x n + h 2 , y n + h K 1 2 , z n + h L 1 2 ) , L 2 = g ( x n + h 2 , y n + h K 1 2 , z n + h L 1 2 ) K 3 = f ( x n + h 2 , y n + h K 2 2 , z n + h L 2 2 ) , L 3 = g ( x n + h 2 , y n + h K 2 2 , z n + h L 2 2 ) K 4 = f ( x n + h , y n + h K 3 , z n + h L 3 ) , L 4 = g ( x n + h , y n + h K 3 , z n + h L 3 ) \left\{\begin{array}{l} K_{1}=f\left(x_{n}, y_{n}, z_{n}\right), \quad L_{1}=g\left(x_{n}, y_{n}, z_{n}\right) \\ K_{2}=f\left(x_{n}+\frac{h}{2}, y_{n}+\frac{h K_{1}}{2}, z_{n}+\frac{h L_{1}}{2}\right), L_{2}=g\left(x_{n}+\frac{h}{2}, y_{n}+\frac{h K_{1}}{2}, z_{n}+\frac{h L_{1}}{2}\right) \\ K_{3}=f\left(x_{n}+\frac{h}{2}, y_{n}+\frac{h K_{2}}{2}, z_{n}+\frac{h L_{2}}{2}\right), L_{3}=g\left(x_{n}+\frac{h}{2}, y_{n}+\frac{h K_{2}}{2}, z_{n}+\frac{h L_{2}}{2}\right) \\ K_{4}=f\left(x_{n}+h, y_{n}+h K_{3}, z_{n}+h L_{3}\right), L_{4}=g\left(x_{n}+h, y_{n}+h K_{3}, z_{n}+h L_{3}\right) \end{array}\right. ⎩⎪⎪⎨⎪⎪⎧K1=f(xn,yn,zn),L1=g(xn,yn,zn)K2=f(xn+2h,yn+2hK1,zn+2hL1),L2=g(xn+2h,yn+2hK1,zn+2hL1)K3=f(xn+2h,yn+2hK2,zn+2hL2),L3=g(xn+2h,yn+2hK2,zn+2hL2)K4=f(xn+h,yn+hK3,zn+hL3),L4=g(xn+h,yn+hK3,zn+hL3)
好了,那么以上就是常微分方程的数值解法,MATLAB中ode45
、ode23s
等便是基于这些数值解法得到的。
由于期末复习压力巨大,更详细的MATLAB解常微分方程将在一个月之后写好。那么本系列就暂时告一段落了,感谢您的观看。
参考文献
[1] 天真的和感伤的想象家 龙格库塔算法原理详解