【微分方程数值解】常微分方程(一)欧拉方法和改进欧拉方法(附python算例,封装类)

欧拉方法与改进欧拉方法


一、算法原理

对给定微分方程
{ y ′ = f ( x , y ) y ( x 0 ) = y 0 (1) \begin{cases} y' = f(x,y)\\ y(x_0) = y_0 \end{cases}\tag{1} {y=f(x,y)y(x0)=y0(1)
在xn到xn+1上积分,得到

y n + 1 = y n + ∫ x n x n + 1 f ( t , y ( t ) ) d t (2) y_{n+1} = y_n + \int_{x_n}^{x_{n+1}}f(t,y(t))dt \tag{2} yn+1=yn+xnxn+1f(t,y(t))dt(2)

如果用左矩形公式做了个(2)式中积分的近似,那可以得到欧拉公式。
y n + 1 = y n + h f ( x n , y n ) (3) y_{n+1} = y_n +hf(x_n,y_n) \tag{3} yn+1=yn+hf(xn,yn)(3)

但用左矩形公式,结果当然是不够好的,现用梯形方法替代等式(2)式中积分,得到

y n + 1 = y n + h 2 ( f ( x n , y n ) + f ( x n + 1 , y n + 1 ) ) (4) y_{n+1} = y_n +\frac{h}{2}(f(x_n,y_n)+f(x_{n+1},y_{n+1}))\tag{4} yn+1=yn+2h(f(xn,yn)+f(xn+1,yn+1))(4)

可以看到等式右边出现了一项 f ( x n + 1 , y n + 1 ) f(x_{n+1},y_{n+1}) f(xn+1,yn+1),里面也有一项需要求的目标值 y n + 1 y_{n+1} yn+1,为使计算简单,将这一项 f f f里的 y n + 1 y_{n+1} yn+1用旧欧拉方法,也就是(3)式得到的值(避免混淆可以记为 y p y_p yp)代入,上等式的结果记为 y c y_c yc。最终可以采取平均的形式
{ y p = y n + h f ( x n , y n ) y c = y n + h f ( x n + 1 , y p ) y n + 1 = ( y p + y c ) / 2 (5) \begin{cases} y_{p} = y_n +hf(x_n,y_n) \\ y_{c} = y_n +hf(x_{n+1},y_p)\\ y_{n+1} = (y_p +y_c)/2 \end{cases}\tag{5} yp=yn+hf(xn,yn)yc=yn+hf(xn+1,yp)yn+1=(yp+yc)/2(5)

综上总结,改进欧拉方法就是旧欧拉方法和梯形近似积分的结合。

二、数值算例

(题目来源于李庆杨《数值分析》计算实习题)
给定初值问题
{ y ′ = 1 x 2 − y x , x ∈ [ 1 , 2 ] y ( 1 ) = 1 \begin{cases} y' = \frac{1}{x^2} - \frac{y}{x} , x\in [1,2]\\ y(1) = 1 \end{cases} {y=x21xy,x[1,2]y(1)=1
用欧拉方法和改进欧拉法(h = 0.05)求 x ∈ [ 1 , 2 ] x \in [1,2] x[1,2]的数值解。

import sympy as sympy


class Euler:    #欧拉算法类
    def __init__(self, h, x0, y0, f ,a,b):        #h为步长,x0和y0为初值,f为微分方程y' = f(x,y),ab为所要计算的区间
        self.h = h
        self.y0 = y0
        self.x0 = x0
        self.n = int((b-a)/h)
        self.f = f

    def euler(self):       
        Y = []   #存储y值
        X = []   #存储x值
        Y.append(self.y0)
        X.append(self.x0)
        for i in range(self.n):
            y_euler = Y[i] + self.h*self.f.subs([(x,self.x0),(y,Y[i])])   #欧拉方法值
            self.x0 = self.x0+self.h   #注意这里都要用self.
            Y.append(y_euler)
            X.append(self.x0)
        return X,Y

class ProEuler:    #改进欧拉类
    def __init__(self, h, x0, y0, f ,a,b):        #h为步长,x0和y0为初值,f为微分方程y' = f(x,y),ab为所要计算的区间
        self.h = h
        self.y0 = y0
        self.x0 = x0
        self.n = int((b-a)/h)
        self.f = f

    def euler(self):       
        Y = []   #存储y值
        X = []   #存储x值
        Y.append(self.y0)
        X.append(self.x0)
        for i in range(self.n):
            y_euler1 = Y[i] + self.h*self.f.subs([(x,self.x0),(y,Y[i])])   #欧拉方法得到第一个y_n+1值
            self.x0 = self.x0+self.h   #注意这里都要用self.
            y_euler2 = Y[i] + self.h*self.f.subs([(x,self.x0),(y,y_euler1)])   #梯形公式得到第二个y_n+1'的值
            y_pro_euler = (y_euler1+y_euler2)/2    #两者相加平均值,就是改进欧拉方法的结果
            Y.append(y_pro_euler)
            X.append(self.x0)
        return X,Y
x,y = sympy.symbols("x y")
f = 1/(x**2)-y/x   #在此修改函数表达式
t1 = Euler(0.05,1,1,f,1,2)  #欧拉方法实例     
x1,y1 = t1.euler()
t2 = ProEuler(0.05,1,1,f,1,2)  #改进欧拉方法实例
x2,y2 = t2.euler()
for i in range(len(x1)):
    print("xi:","%.2f"%x2[i], "  y_euler:", "%.7f"%y1[i],"  y_proeuler:","%.7f"%y2[i])

输出结果

xi: 1.00   y_euler: 1.0000000   y_proeuler: 1.0000000
xi: 1.05   y_euler: 1.0000000   y_proeuler: 0.9988662
xi: 1.10   y_euler: 0.9977324   y_proeuler: 0.9957694
xi: 1.15   y_euler: 0.9937033   y_proeuler: 0.9911415
xi: 1.20   y_euler: 0.9883060   y_proeuler: 0.9853210
xi: 1.25   y_euler: 0.9818488   y_proeuler: 0.9785748
xi: 1.30   y_euler: 0.9745748   y_proeuler: 0.9711148
xi: 1.35   y_euler: 0.9666770   y_proeuler: 0.9631101
xi: 1.40   y_euler: 0.9583090   y_proeuler: 0.9546959
xi: 1.45   y_euler: 0.9495938   y_proeuler: 0.9459812
xi: 1.50   y_euler: 0.9406304   y_proeuler: 0.9370539
xi: 1.55   y_euler: 0.9314983   y_proeuler: 0.9279848
xi: 1.60   y_euler: 0.9222616   y_proeuler: 0.9188316
xi: 1.65   y_euler: 0.9129722   y_proeuler: 0.9096406
xi: 1.70   y_euler: 0.9036719   y_proeuler: 0.9004497
xi: 1.75   y_euler: 0.8943943   y_proeuler: 0.8912892
xi: 1.80   y_euler: 0.8851667   y_proeuler: 0.8821837
xi: 1.85   y_euler: 0.8760109   y_proeuler: 0.8731530
xi: 1.90   y_euler: 0.8669441   y_proeuler: 0.8642129
xi: 1.95   y_euler: 0.8579802   y_proeuler: 0.8553758
xi: 2.00   y_euler: 0.8491299   y_proeuler: 0.8466517

你可能感兴趣的:(微分方程数值解,python,微分方程,数值解)