【數學知識】常微分方程的數值求解及python實現
引言
在工程和科學技術的實際問題中,常需要求解微分方程。不管是本科生參加數學建模競賽還是研究生進行自己的課題研究,常微分方程都是經常出現的。
然而,只有簡單的和典型的微分方程可以求出解析解,而在實際問題中的微分方程往往無法求出解析解。
常微分方程認識
定義與常見形式
凡含有參數,未知函數和未知函數導數 (或微分) 的方程,稱爲微分方程,有時簡稱爲方程,未知函數是一元函數的微分方程稱作常微分方程 ,未知函數是多元函數的微分方程稱作偏微分方程 。
常微分方程定義:
F ( x , y , y ′ , y ′ ′ , . . . , y ( n ) ) = 0
F(x,y,y',y'',...,y^{(n)})=0
F ( x , y , y ′ , y ′ ′ , . . . , y ( n ) ) = 0
在高等數學中我們見過以下常微分方程:
初值問題(1):
{ y ′ = f ( x , y ) a ≤ x ≤ b y ( a ) = y 0
\left\{
\begin{array}{l}
y'=f(x,y) \quad a\le x \le b \\
y(a) = y_0
\end{array}
\right.
{ y ′ = f ( x , y ) a ≤ x ≤ b y ( a ) = y 0
初值問題(2):
{ y ′ ′ = f ( x , y , y ′ ) a ≤ x ≤ b y ( a ) = y 0 , y ′ ( a ) = α
\left\{
\begin{array}{l}
y''=f(x,y,y') \quad a\le x \le b \\
y(a) = y_0 , y'(a)=\alpha
\end{array}
\right.
{ y ′ ′ = f ( x , y , y ′ ) a ≤ x ≤ b y ( a ) = y 0 , y ′ ( a ) = α
邊值問題
{ y ′ ′ = f ( x , y , y ′ ) a ≤ x ≤ b y ( a ) = y 0 , y ′ ( b ) = y n
\left\{
\begin{array}{l}
y''=f(x,y,y') \quad a\le x \le b \\
y(a) = y_0 , y'(b)=y_n
\end{array}
\right.
{ y ′ ′ = f ( x , y , y ′ ) a ≤ x ≤ b y ( a ) = y 0 , y ′ ( b ) = y n
初值問題(1)的解存在的條件
存在和唯一性定理 :如果連續函數f(x,y)關於y滿足Lipschitz 條件,即:
∃ \exists ∃ 正數L L L ,使得∀ x ∈ [ a , b ] \forall x \in [a,b] ∀ x ∈ [ a , b ] ,均有
∣ f ( x , y 1 ) − f ( x , y 2 ) ∣ ≤ L ∣ y 1 − y 2 ∣ |f(x,y_1)-f(x,y_2)|\le L|y_1-y_2| ∣ f ( x , y 1 ) − f ( x , y 2 ) ∣ ≤ L ∣ y 1 − y 2 ∣
則初值問題(1)的解存在且唯一
初值問題(1)的數值解
對於初值問題(1):
{ y ′ = f ( x , y ) a ≤ x ≤ b y ( a ) = y 0
\left\{
\begin{array}{l}
y'=f(x,y) \quad a\le x \le b \\
y(a) = y_0
\end{array}
\right.
{ y ′ = f ( x , y ) a ≤ x ≤ b y ( a ) = y 0
要求它的數值解,就是求未知函數y ( x ) y(x) y ( x ) 在區間[ a , b ] [a,b] [ a , b ] 上的一系列離散點(節點)
a = x 0 ≤ x 1 ≤ x 2 ≤ ⋯ ≤ x n = b
a = x_0 \le x_1 \le x_2 \le \cdots \le x_n = b
a = x 0 ≤ x 1 ≤ x 2 ≤ ⋯ ≤ x n = b
上函數值y ( x k ) y(x_k) y ( x k ) 的近似值y k ( k = 1 , 2 , ⋯ , n ) y_k(k=1,2,\cdots,n) y k ( k = 1 , 2 , ⋯ , n ) ,這就是初值問題(1)的數值解。
求它的數值解的關鍵在於y ′ ( x ) y'(x) y ′ ( x ) 的數值計算問題或者它的等價的積分方程y ( x ) = y 0 + ∫ a x f ( t , y ( t ) ) d x y(x) = y_0 +\int_{a}^{x}f(t,y(t)) dx y ( x ) = y 0 + ∫ a x f ( t , y ( t ) ) d x 的數值計算問題。
求解微分方程的數值方法分爲:數值微分和數值積分兩種方法。
實際應用中,通常取求解區間[ a , b ] [a,b] [ a , b ] 的等分點作爲離散點,即
x k = a + k h , k = 0 , 1 , ⋯ , n , w h e r e h = n b − a
x_k = a + kh, \quad k = 0,1,\cdots,n, where \quad h = \frac{n}{b-a}
x k = a + k h , k = 0 , 1 , ⋯ , n , w h e r e h = b − a n
推導初值問題的數值方法的途徑:
Talor展開
利用差商離散導數
利用數值積分方法
求初值問題數值解的方法是步進法 ,即從已知的初值y 0 y_0 y 0 出發,通過一定的計算求y 1 y_1 y 1 ,然後由y 1 y_1 y 1 或y 0 y_0 y 0 和y 1 y_1 y 1 求出y 2 y_2 y 2 ,依次計算到y n y_n y n ,這時,可以分爲
單步法:只利用y k y_k y k 來計算y k + 1 y_{k+1} y k + 1
多步法:計算y k + 1 y_{k+1} y k + 1 時,除了利用y k y_k y k ,還需要用到已算出的若干y k − j y_{k-j} y k − j (j = 1 , 2 , ⋯ , l − 1 j=1,2,\cdots,l-1 j = 1 , 2 , ⋯ , l − 1 ),並稱爲l l l 步法
常微分方程數值求解方法
歐拉(尤拉) (Euler) 公式推導
方法一:利用Taylor展開
因爲
x k + 1 − x k = h
x_{k+1}-x_k=h
x k + 1 − x k = h
故
y ( x k + 1 ) = y ( x k + h )
y(x_{k+1})=y(x_k+h)
y ( x k + 1 ) = y ( x k + h )
可將y ( x k + 1 ) = y ( x k + h ) y(x_{k+1})=y(x_k+h) y ( x k + 1 ) = y ( x k + h ) 按照1階泰勒公式 展開,得
y ( x k + 1 ) = y ( x k ) + 1 1 ! y ′ ( x k ) ( x k + 1 − x k )
y(x_{k+1})=y(x_k)+\frac{1}{1!}y'(x_k)(x_{k+1}-x_k)
y ( x k + 1 ) = y ( x k ) + 1 ! 1 y ′ ( x k ) ( x k + 1 − x k )
也就是
y ( x k + 1 ) = y ( x k ) + h y ′ ( x k )
y(x_{k+1})=y(x_k)+hy'(x_k)
y ( x k + 1 ) = y ( x k ) + h y ′ ( x k )
又根據初值條件
{ y ′ = f ( x , y ) a ≤ x ≤ b y ( a ) = y 0
\left\{
\begin{array}{l}
y'=f(x,y) \quad a\le x \le b \\
y(a) = y_0
\end{array}
\right.
{ y ′ = f ( x , y ) a ≤ x ≤ b y ( a ) = y 0
可以得到數值解序列{ y k } \{y_k\} { y k } 的計算遞推公式:
{ y 0 = y ( a ) y k + 1 = y k + h f ( x k , y k ) , k = 0 , 1 , ⋯ , n − 1
\left\{
\begin{array}{l}
y_0 = y(a) \\
y_{k+1}=y_k+hf(x_k,y_k), k = 0,1,\cdots , n-1
\end{array}
\right.
{ y 0 = y ( a ) y k + 1 = y k + h f ( x k , y k ) , k = 0 , 1 , ⋯ , n − 1
方法二:利用差商離散導數
首先,導數的定義爲:
f ′ ( x ) = f ( x ) − f ( x − Δ x ) Δ x
f'(x)=\frac{f(x)-f(x-\Delta x)}{\Delta x}
f ′ ( x ) = Δ x f ( x ) − f ( x − Δ x )
我們對x k x_k x k 處的導數用差商來近似代替,如向前差商:
f ′ ( x k ) ≈ y ( x k + 1 ) − y ( x k ) h
f'(x_k) \approx \frac{y(x_{k+1})-y(x_k)}{h}
f ′ ( x k ) ≈ h y ( x k + 1 ) − y ( x k )
則微分方程初值問題可以化爲:
{ y ( x k + 1 ) − y ( x k ) h ≈ f ( x k , y ( x k ) ) , k = 0 , 1 , ⋯ , n − 1 y ( a ) = y 0
\begin{cases}
\frac{y(x_{k+1})-y(x_k)}{h} \approx f(x_k,y(x_k)) , k = 0,1,\cdots , n-1 \\
y(a) = y_0
\end{cases}
{ h y ( x k + 1 ) − y ( x k ) ≈ f ( x k , y ( x k ) ) , k = 0 , 1 , ⋯ , n − 1 y ( a ) = y 0
將近似號改爲等號,精確解y ( x k ) y(x_k) y ( x k ) 改爲近似序列y k y_k y k ,滿足:
{ y 0 = y ( a ) y k + 1 = y k + h f ( x k , y k ) , k = 0 , 1 , ⋯ , n − 1
\left\{
\begin{array}{l}
y_0 = y(a) \\
y_{k+1}=y_k+hf(x_k,y_k), k = 0,1,\cdots , n-1
\end{array}
\right.
{ y 0 = y ( a ) y k + 1 = y k + h f ( x k , y k ) , k = 0 , 1 , ⋯ , n − 1
第三種方法——利用數值積分方法這裏就不介紹了
總的來說,上面推導的結果,就是歐拉(尤拉) (Euler) 公式 ,這裏重寫一遍:
{ y 0 = y ( a ) y k + 1 = y k + h f ( x k , y k ) , k = 0 , 1 , ⋯ , n − 1
\left\{
\begin{array}{l}
y_0 = y(a) \\
y_{k+1}=y_k+hf(x_k,y_k), k = 0,1,\cdots , n-1
\end{array}
\right.
{ y 0 = y ( a ) y k + 1 = y k + h f ( x k , y k ) , k = 0 , 1 , ⋯ , n − 1
歐拉(尤拉) (Euler) 公式及其變形/改進
上一節詳細推到了歐拉(尤拉) (Euler) 公式,這裏介紹它的幾種不同的形式:
顯式歐拉公式 :原始的歐拉公式
{ y 0 = y ( a ) y k + 1 = y k + h f ( x k , y k ) , k = 0 , 1 , ⋯ , n − 1
\left\{
\begin{array}{l}
y_0 = y(a) \\
y_{k+1}=y_k+hf(x_k,y_k), k = 0,1,\cdots , n-1
\end{array}
\right.
{ y 0 = y ( a ) y k + 1 = y k + h f ( x k , y k ) , k = 0 , 1 , ⋯ , n − 1
隱式歐拉公式 :使用向後差商代替導數得到
{ y 0 = y ( a ) y k + 1 = y k + h f ( x k + 1 , y k + 1 ) , k = 0 , 1 , ⋯ , n − 1
\left\{
\begin{array}{l}
y_0 = y(a) \\
y_{k+1}=y_k+hf(x_{k+1},y_{k+1}), k = 0,1,\cdots , n-1
\end{array}
\right.
{ y 0 = y ( a ) y k + 1 = y k + h f ( x k + 1 , y k + 1 ) , k = 0 , 1 , ⋯ , n − 1
梯形公式 :將顯式歐拉公式和隱式歐拉公式作算術平均
{ y 0 = y ( a ) y k + 1 = y k + h 2 [ f ( x k , y k ) + f ( x k + 1 , y k + 1 ) ] , k = 0 , 1 , ⋯ , n − 1
\left\{
\begin{array}{l}
y_0 = y(a) \\
y_{k+1}=y_k+\frac{h}{2}[f(x_{k},y_{k})+f(x_{k+1},y_{k+1})], k = 0,1,\cdots , n-1
\end{array}
\right.
{ y 0 = y ( a ) y k + 1 = y k + 2 h [ f ( x k , y k ) + f ( x k + 1 , y k + 1 ) ] , k = 0 , 1 , ⋯ , n − 1
預估-校正Euler方法 :
即首先計算出初步的近似值y k + 1 ‾ \overline{y_{k+1}} y k + 1 :
y k + 1 ‾ = y k + h f ( x k , y k )
\overline{y_{k+1}}=y_k+hf(x_k,y_k)
y k + 1 = y k + h f ( x k , y k )
然後用該預估值替代梯形公式右端中的y k + 1 y_{k+1} y k + 1 進行計算,從而得到最後的校正值y k + 1 y_{k+1} y k + 1 :
y k + 1 = y k + h 2 [ f ( x k , y k ) + f ( x k + 1 , y k + 1 ‾ ) ]
y_{k+1}=y_k+\frac{h}{2}[f(x_{k},y_{k})+f(x_{k+1},\overline{y_{k+1}})]
y k + 1 = y k + 2 h [ f ( x k , y k ) + f ( x k + 1 , y k + 1 ) ]
歐拉(尤拉) (Euler) 公式Python實現
導入包,代碼如下:
from pylab import *
import warnings
warnings. filterwarnings( 'ignore' )
import matplotlib. pyplot as plt
% matplotlib inline
定義函數euler_xianshi(f,a=0,b=1,ya=1,h=0.1,print_result=True)
使用顯式歐拉公式進行微分方程數值計算代碼如下:
def euler_xianshi ( f, a= 0 , b= 1 , ya= 1 , h= 0.1 , print_result= True ) :
'''顯式歐拉公式, Explicit Euler formula
f:需要求解的微分方程,y'=f(x,y)
f的格式:
def f(x,y):
...
return dy
a:求解區間起始值
b:求解區間終止值
ya:起始條件,ya=y(a)
h:求解步長(區間[a,b]n等分)
print_result:顯示顯式歐拉公式的每一步計算結果
Returns
----------
res:返回顯式歐拉公式的求解結果
'''
res = [ ]
xi = a
yi = ya
while xi<= b:
y = yi + h* f( xi, yi)
if print_result:
print ( 'xi:{:.2f}, yi:{:.6f}' . format ( xi, yi) )
res. append( y)
xi, yi = xi+ h, y
return res
例1:求解下列微分方程
{ y ′ = x − y + 1 0 ≤ x ≤ 1 y ( 0 ) = 1
\left\{
\begin{array}{l}
y'= x-y+1 \quad 0\le x \le 1 \\
y(0) = 1
\end{array}
\right.
{ y ′ = x − y + 1 0 ≤ x ≤ 1 y ( 0 ) = 1
def f ( x, y) :
'''
求解的微分方程:y'=x-y+1
'''
return x- y+ 1
第2步:應用前面定義的euler_xianshi函數進求解
a= 0
b= 1
y0= 1
h= 0.05
y = euler_xianshi( f, a, b, y0, h, print_result= True )
import math
import numpy as np
def fun_y ( x) :
return x+ np. exp( - x)
x_true = np. arange( a, b, 0.1 * h)
y_true = fun_y( x_true)
x = np. arange( a, b, h)
plt. plot( x_true, y_true, label= "true" , color= "red" )
plt. scatter( x, y, label= "predict" )
plt. legend( )
結果如下:
【作者簡介】陳藝榮 ,男,目前在華南理工大學電子與信息學院廣東省人體數據科學工程技術研究中心 攻讀博士,擔任IEEE Access、IEEE Photonics Journal的審稿人。兩次獲得美國大學生數學建模競賽(MCM)一等獎,獲得2017年全國大學生數學建模競賽(廣東賽區)一等獎、2018年廣東省大學生電子設計競賽一等獎等科技競賽獎項,主持一項2017-2019年國家級大學生創新訓練項目獲得優秀結題,參與兩項廣東大學生科技創新培育專項資金、一項2018-2019年國家級大學生創新訓練項目獲得良好結題,發表SCI論文4篇,授權實用新型專利8項,受理髮明專利13項。
我的主頁
我的Github
我的CSDN博客
我的Linkedin