数学建模:微分方程模型—常微分方程数值解算法及 Python 实现

目录

    • 一、显式欧拉 (Euler) 法
    • 二、显式欧拉法的改进
      • 隐式欧拉法 (后退欧拉法)
      • 梯形法
      • 两步欧拉法 (中点法)
      • 预报 - 校正法 (改进欧拉法)
    • 三、龙格 - 库塔 (Runge-Kutta) 法
      • 基本思路
      • 2 阶龙格 - 库塔法
      • 4 阶经典龙格 - 库塔法 (最常用)
      • 一般的龙格 - 库塔法

考虑一阶常微分方程的初值问题
{ d y d x = f ( x , y ) x ∈ [ a , b ] y ( a ) = y 0 {\begin{cases} {\frac{{dy}}{{dx}} = f(x,y)\quad x \in [a,b]} \\ {y(a) = {y_0}} \end{cases}} {dxdy=f(x,y)x[a,b]y(a)=y0

只要 f ( x , y ) f(x, y) f(x,y) [ a , b ] × R 1 [a, b] \times \mathbb{R}^{1} [a,b]×R1 上连续,且关于 y y y 满足 Lipschitz 条件,即存在与 x , y x, y x,y 无关的常数 L L L, s . t . s.t. s.t. ∣ f ( x , y 1 ) − f ( x , y 2 ) ∣ ≤ L ∣ y 1 − y 2 ∣ \left|f\left(x, y_{1}\right)-f\left(x, y_{2}\right)\right| \leq L\left|y_{1}-y_{2}\right| f(x,y1)f(x,y2)Ly1y2, 对任意定义在 [ a , b ] [a, b] [a,b] 上的 y 1 ( x ) y_{1}(x) y1(x) y 2 ( x ) y_{2}(x) y2(x) 成立,则上述初值问题的连续可微解 y ( x ) y(x) y(x) [ a , b ] [a, b] [a,b] 上存在且唯一。

常微分方程数值解要计算出解函数 y ( x ) y(x) y(x) 在一系列节点 a = x 0 < x 1 < … < x n = b a=x_{0}a=x0<x1<<xn=b 处的近似值 y i ≈ y ( x i )   ( i = 1 , … , n ) y_{i} \approx y\left(x_{i}\right) \ (i=1, \ldots, n) yiy(xi) (i=1,,n),节点间距 h i = x i + 1 − x i ( i = 0 , … , n − 1 ) h_{i}=x_{i+1}-x_{i}(i=0, \ldots, n-1) hi=xi+1xi(i=0,,n1) 称为步长,通常采用等距节点,即取 h i = h h_i = h hi=h (常数)。

一、显式欧拉 (Euler) 法

x y x y xy 平面上, 微分方程的解 y = y ( x ) y=y(x) y=y(x) 称为积分曲线. 积分曲线上一点 ( x , y ) (x, y) (x,y) 的切线斜率等于 函数 f ( x , y ) f(x, y) f(x,y) 的值.

从初始点 P 0 ( x 0 , y 0 ) P_{0}\left(x_{0}, y_{0}\right) P0(x0,y0) 出发, 沿切线方向推进到 x = x 1 x=x_{1} x=x1 上一点 P 1 P_{1} P1, 再从 P 1 P_{1} P1 沿切线方向推进到 x = x 2 x=x_{2} x=x2 上一点 P 2 P_{2} P2, 循此前进作出一条折线 P 0 P 1 P 2 ⋯ P_{0} P_{1} P_{2} \cdots P0P1P2, 作为积分曲线的一个近似. 即向前取差商近似导数
{ y 0 = y ( x 0 ) , y i + 1 = y i + h f ( x i , y i ) ( i = 0 , 1 , ⋯   , n − 1 ) \begin{cases} {y_0} = y({x_0}),\\ {y_{i + 1}} = {y_i} + {h}f({x_i},{y_i}) \quad (i = 0,1, \cdots ,n - 1) \end{cases} {y0=y(x0),yi+1=yi+hf(xi,yi)(i=0,1,,n1)

称为 (显式) 欧拉法

定义 在假设 y i = y ( x i ) y_{i}=y\left(x_{i}\right) yi=y(xi) ,即第 i i i 步计算是精确的前提下, R i = y ( x i + 1 ) − y i + 1 R_{i}=y\left(x_{i+1}\right)-y_{i+1} Ri=y(xi+1)yi+1 称为局部截断误差。

定义 若某算法的局赔截断误差为 O ( h p + 1 ) O\left(h^{p+1}\right) O(hp+1) ,则称该算法有 p p p 阶精度。

显式欧拉格式具有 1 阶精度

Python 实现:

import numpy as np
#显式欧拉法的Python实现
def Euler(f,x0,y0,h,l):
    #f函数, x0,y0初值, h步长, l数量
    xn, yn = x0, y0
    n = 0
    ns, xs, ys = [n], [x0], [y0]
    while n <= l:
        n += 1
        xn += h
        yn = yn + f(xn,yn) * h
        ns.append(n)
        xs.append(xn)
        ys.append(yn)
    return (ns,xs,ys)

二、显式欧拉法的改进

隐式欧拉法 (后退欧拉法)

将常微分方程化为积分方程
y ( x i + 1 ) = y ( x i ) + ∫ x i x i + 1 f ( x , y ( x ) ) d x . {y}\left(x_{i+1}\right)= {y}\left(x_{i}\right)+\int_{x_{i}}^{x_{i+1}} {f}(x, {y}(x)) {d} x . y(xi+1)=y(xi)+xixi+1f(x,y(x))dx.

采用左矩形公式计算积分
y i + 1 = y i + h f ( x i , y i ) , {y}_{i+1}= {y}_{i}+h {f}\left(x_{i}, {y}_{i}\right), yi+1=yi+hf(xi,yi),

即是显式欧拉法的递推公式.

用右矩形公式计算积分, 即是向后取差商近似导数
y i + 1 = y i + h f ( x i + 1 , y i + 1 ) ( i = 0 , … , n − 1 ) y_{i+1}=y_{i}+h f\left(x_{i+1}, y_{i+1}\right) \quad(i=0, \ldots, n-1) yi+1=yi+hf(xi+1,yi+1)(i=0,,n1)

称为隐式欧拉法或后退欧拉法.

隐式欧拉格式具有 1 阶精度

梯形法

即显、隐式两种算法的平均

y i + 1 = y i + h 2 [ f ( x i , y i ) + f ( x i + 1 , y i + 1 ) ] ( i = 0 ,    . . .    , n − 1 ) {y_{i + 1}} = {y_i} + \frac{h}{2}[f({x_i},{y_i}) + f({x_{i + 1}},{y_{i + 1}})]\quad (i = 0,\;...\;,n - 1) yi+1=yi+2h[f(xi,yi)+f(xi+1,yi+1)](i=0,...,n1)

称为梯形法.

梯形格式具有 2 阶精度

两步欧拉法 (中点法)

取中心差商近似导数
y i + 1 = y i − 1 + 2 h   f ( x i , y i ) ( i = 1 ,    . . .    , n − 1 ) {y_{i + 1}} = {y_{i - 1}} + 2h\,f({x_i},{y_i})\quad (i = 1,\;...\;,n - 1) yi+1=yi1+2hf(xi,yi)(i=1,...,n1)

称为两步欧拉法或中点法.

中点格式具有 2 阶精度

预报 - 校正法 (改进欧拉法)

  1. 先用显式欧拉法作预报, 算出 y ˉ i + 1 = y i + h f ( x i , y i ) \bar{y}_{i+1}=y_{i}+h f\left(x_{i}, y_{i}\right) yˉi+1=yi+hf(xi,yi)

  2. 再将 y ˉ i + 1 \bar{y}_{i+1} yˉi+1 代入隐式梯形法的右边作校正,得到
    y i + 1 = y i + h 2 [ f ( x i , y i ) + f ( x i + 1 , y ˉ i + 1 ) ] y_{i+1}=y_{i}+\frac{h}{2}\left[f\left(x_{i}, y_{i}\right)+f\left(x_{i+1}, \bar{y}_{i+1}\right)\right] yi+1=yi+2h[f(xi,yi)+f(xi+1,yˉi+1)]


y i + 1 = y i + h 2 [ f ( x i , y i ) + f ( x i + 1 , y i + h f ( x i , y i ) ) ] ( i = 0 , … , n − 1 ) y_{i+1}=y_{i}+\frac{h}{2}\left[f\left(x_{i}, y_{i}\right)+f\left(x_{i+1}, y_{i}+h f\left(x_{i}, y_{i}\right)\right)\right] \quad(i=0, \ldots, n-1) yi+1=yi+2h[f(xi,yi)+f(xi+1,yi+hf(xi,yi))](i=0,,n1)

预报 - 校正法通常只迭代一两次就转人下一步的计算, 避免了梯形法和中点法每次迭代, 都要重新计算函数 f ( x , y ) {f}(x, {y}) f(x,y), 减少了计算量.

预报 - 校正法具有 2 阶精度

三、龙格 - 库塔 (Runge-Kutta) 法

基本思路

积分方程右端积分的求积公式可以表示为
∫ x i x i + 1 f ( x , y ( x ) ) d x ≈ h ∑ i = 1 r c i f ( x i + λ i h , y ( x i + λ i h ) ) \int_{x_{i}}^{x_{i+1}} {f}(x, {y}(x)) \mathrm{d} x \approx h \sum_{i=1}^{r} c_{i} {f}\left(x_{i}+\lambda_{i} h, {y}\left(x_{i}+\lambda_{i} h\right)\right) xixi+1f(x,y(x))dxhi=1rcif(xi+λih,y(xi+λih))

将上式表示为
y n + 1 = y n + h ϕ ( x n , y n , h ) {y}_{n+1}= {y}_{n}+h {\phi}\left(x_{n}, {y}_{n}, h\right) yn+1=yn+hϕ(xn,yn,h)

其中
ϕ ( x i , y i , h ) = ∑ i = 1 r c i K i K 1 = f ( x i , y i ) K i = f ( x i + λ i h , y i + h ∑ j = 1 i − 1 μ i j K j ) ( i = 2 , ⋯   , r ) \begin{gathered} &\phi\left(x_{i}, {y}_{i}, h\right)=\sum_{i=1}^{r} c_{i} {K}_{i} \\ & {K}_{1}= {f}\left(x_{i}, {y}_{i}\right) \\ & {K}_{i}= {f}\left(x_{i}+\lambda_{i} h, {y}_{i}+h \sum_{j=1}^{i-1} \mu_{i j} {K}_{j}\right) \quad(i=2, \cdots, r) \end{gathered} ϕ(xi,yi,h)=i=1rciKiK1=f(xi,yi)Ki=f(xi+λih,yi+hj=1i1μijKj)(i=2,,r)

称为 r r r 阶显式龙格 - 库塔法. 当 r = 1 r=1 r=1 时, ϕ ( x i , y i , h ) = f ( x i , y i ) \phi\left(x_{i}, y_{i}, h\right)=f\left(x_{i}, y_{i}\right) ϕ(xi,yi,h)=f(xi,yi), 就是欧拉法.

2 阶龙格 - 库塔法

r = 2 r=2 r=2
{ y i + 1 = y i + h [ λ 1 K 1 + λ 2 K 2 ] K 1 = f ( x i , y i ) K 2 = f ( x i + p h , y i + p h K 1 ) \left\{\begin{array}{l} y_{i+1}=y_{i}+h\left[\lambda_{1} K_{1}+\lambda_{2} K_{2}\right] \\ K_{1}=f\left(x_{i}, y_{i}\right) \\ K_{2}=f\left(x_{i}+p h, y_{i}+p h K_{1}\right) \end{array}\right. yi+1=yi+h[λ1K1+λ2K2]K1=f(xi,yi)K2=f(xi+ph,yi+phK1)

其中 λ 1 + λ 2 = 1 ,   λ 2 p = 1 2 {\lambda _1} + {\lambda_2} = 1, \ {\lambda_2}p = \frac{1}{2} λ1+λ2=1, λ2p=21, 算法有 2 阶精度

若取 λ 1 = 0 , λ 2 = 1 {\lambda _1}=0, {\lambda_2} = 1 λ1=0,λ2=1, 则 p = 1 2 p = \frac{1}{2} p=21, 则
{ y i + 1 = y i + h K 2 K 1 = f ( x i , y i ) K 2 = f ( x i + h 2 , y i + h 2 K 1 ) \left\{\begin{array}{l} {y}_{i+1}= {y}_{i}+h {K}_{2} \\ {K}_{1}= {f}\left(x_{i}, {y}_{i}\right) \\ {K}_{2}= {f}\left(x_{i}+\frac{h}{2}, {y}_{i}+\frac{h}{2} {K}_{1}\right) \end{array}\right. yi+1=yi+hK2K1=f(xi,yi)K2=f(xi+2h,yi+2hK1)

即是中点法

4 阶经典龙格 - 库塔法 (最常用)

4 阶龙格 - 库塔法是最常用的龙格 - 库塔法

{ y i + 1 = y i + h 6 ( K 1 + 2 K 2 + 2 K 3 + K 4 ) K 1 = f ( x i , y i ) K 2 = f ( x i + h 2 , y i + h 2 K 1 ) K 3 = f ( x i + h 2 , y i + h 2 K 2 ) K 4 = f ( x i + h , y i + h K 3 ) \left\{\begin{array}{l} y_{i+1}=y_{i}+\frac{h}{6}\left(K_{1}+2 K_{2}+2 K_{3}+K_{4}\right) \\ K_{1}=f\left(x_{i}, y_{i}\right) \\ K_{2}=f\left(x_{i}+\frac{h}{2}, y_{i}+\frac{h}{2} K_{1}\right) \\ K_{3}=f\left(x_{i}+\frac{h}{2}, y_{i}+\frac{h}{2} K_{2}\right) \\ K_{4}=f\left(x_{i}+h, y_{i}+h K_{3}\right) \end{array}\right. yi+1=yi+6h(K1+2K2+2K3+K4)K1=f(xi,yi)K2=f(xi+2h,yi+2hK1)K3=f(xi+2h,yi+2hK2)K4=f(xi+h,yi+hK3)

Python 实现:

import numpy as np
#四阶龙格库塔法的Python实现
def RK4(f,x0,y0,h,maxx):
    #f函数, x0,y0初值, h步长, maxx: x最大值
    xn, yn = x0, y0
    n = 0
    ns, xs, ys = [n], [xn], [yn]
    while xn < maxx:
        n += 1
        xn += h
        k1 = f(xn,yn)
        k2 = f(xn + (h / 2),yn + (h * k1) / 2)
        k3 = f(xn + (h / 2),yn + (h * k2) / 2)
        k4 = f(xn + h,yn + h * k3)
        yn = yn + (h / 6) * (k1 + 2 * k2 + 2 * k3 + k4)
        ns.append(n)
        xs.append(xn)
        ys.append(yn)
    return (ns,xs,ys)

一般的龙格 - 库塔法

{ y i + 1 = y i + h [ λ 1 K 1 + λ 2 K 2 + … + λ m K m ] K 1 = f ( x i , y i ) K 2 = f ( x i + α 2 h , y i + β 21 h K 1 ) K 3 = f ( x i + α 3 h , y i + β 31 h K 1 + β 32 h K 2 ) ⋯ ⋯ K m = f ( x i + α m h , y + β m 1 h K 1 + β m 2 h K 2 + … + β m m − 1 h K m − 1 ) \left\{\begin{aligned} y_{i+1} &=y_{i}+h\left[\lambda_{1} K_{1}+\lambda_{2} K_{2}+\ldots+\lambda_{m} K_{m}\right] \\ K_{1} &=f\left(x_{i}, y_{i}\right) \\ K_{2} &=f\left(x_{i}+\alpha_{2} h, y_{i}+\beta_{21} h K_{1}\right) \\ K_{3} &=f\left(x_{i}+\alpha_{3} h, y_{i}+\beta_{31} h K_{1}+\beta_{32} h K_{2}\right) \\ & \cdots \cdots \\ K_{m} &=f\left(x_{i}+\alpha_{m} h, y+\beta_{m 1} h K_{1}+\beta_{m 2} h K_{2}+\ldots+\beta_{m m-1} h K_{m-1}\right) \end{aligned}\right. yi+1K1K2K3Km=yi+h[λ1K1+λ2K2++λmKm]=f(xi,yi)=f(xi+α2h,yi+β21hK1)=f(xi+α3h,yi+β31hK1+β32hK2)=f(xi+αmh,y+βm1hK1+βm2hK2++βmm1hKm1)

由于龙格-库塔法的导出基于泰勒展开, 故精度主要受解函数的光滑性影响. 对于光滑性不太好的解, 最好采用低阶算法而将步长 h h h 取小.

你可能感兴趣的:(数学建模,python,算法,数据分析)