小白每每聽到微分方程就以爲懼怕,其實數學建模中的微分方程模型不只沒那麼複雜,並且很容易寫出高水平的數模論文。html
本文介紹微分方程模型邊值問題的建模與求解,不涉及算法推導和編程,只探討如何使用 Python 的工具包,零基礎求解微分方程模型邊值問題。node
經過 3個 BVP 案例層層深刻,手把手教你搞定微分方程邊值問題。python
歡迎關注『Python小白的數學建模課 @ Youcans』系列,每週持續更新算法
微分方程是指含有未知函數及其導數的關係式。編程
微分方程是描述系統的狀態隨時間和空間演化的數學工具。物理中許多涉及變力的運動學、動力學問題,如空氣的阻力爲速度函數的落體運動等問題,不少能夠用微分方程求解。微分方程在化學、工程學、經濟學和人口統計等領域也有普遍應用。數組
微分方程分爲初值問題和邊值問題。初值問題是已知微分方程的初始條件,即自變量爲零時的函數值,通常能夠用歐拉法、龍哥庫塔法來求解。邊值問題則是已知微分方程的邊界條件,即自變量在邊界點時的函數值。函數
邊值問題的提出和發展,與流體力學、材料力學、波動力學以及核物理學等密切相關,而且在現代控制理論等學科中有重要應用。例如,力學問題中的懸鏈線問題、彈簧振動問題,熱學問題中的導熱細杆問題、細杆端點冷卻問題,流體力學問題、結構強度問題。工具
上節咱們介紹的常微分方程,主要是微分方程的初值問題。本節介紹二階常微分方程邊值問題的建模與求解。spa
只含邊界條件做爲定解條件的常微分方程求解問題,稱爲常微分方程的邊值問題(boundary value problem)。code
通常形式的二階常微分方程邊值問題:
有三種狀況的邊界條件:
(1)第一類邊界條件(兩點邊值問題):
(2)第二類邊界條件:
(3)第三類邊界條件:
其中:\(a_0 \geq 0,b_0 \geq 0,a_0+b_0>0\)
簡單介紹求解常微分方程邊值問題的數值解法,經常使用方法有:打靶算法、有限差分法和有限元法。打靶算法把邊值問題轉化爲初值問題求解,是根據邊界條件反覆迭代調整初始點的斜率,使初值問題的數值解在邊界上「命中」問題的邊值條件。有限差分法把空間離散爲網格節點,用差商代替微商,將微分方程離散化爲線性或非線性方程組來求解。 有限元法將微分方程離散化,有限元就是指近似連續域的離散單元,對每一單元假定一個近似解,而後推導求解域知足條件,從而獲得問題的解。
按照本系列「編程方案」的概念,不涉及這些算法的具體內容,只探討如何使用 Python 的工具包、庫函數,零基礎求解微分方程模型邊值問題。咱們的選擇仍是 Python 經常使用工具包三劍客:Scipy、Numpy 和 Matplotlib。
Scipy 用 solve_bvp() 函數求解常微分方程的邊值問題,定義微分方程的標準形式爲:
所以要將第一類邊界條件 \(y(a)=ya,y(b)=yb\) 改寫爲:
**scipy.integrate.solve_bvp() **是求解微分方程邊值問題的具體方法,能夠求解一階微分方程(組)的兩點邊值問題(第一類邊界條件)。在 odeint
函數內部使用 FORTRAN 庫 odepack 中的 lsoda,能夠求解一階剛性系統和非剛性系統的初值問題。官網介紹詳見: scipy.integrate.solve_bvp — SciPy v1.7.0 Manual 。
scipy.integrate.solve_bvp(fun, bc, x, y, p=None, S=None, fun_jac=None, bc_jac=None, tol=0.001, max_nodes=1000, verbose=0, bc_tol=None)
solve_bvp 的主要參數:
求解標準形式的微分方程(組)主要使用前 4 個參數:
其它參數用於控制求解算法的參數,通常狀況能夠忽略。
solve_bvp 的主要返回值:
求常微分方程邊值問題的數值解。
引入變量 \(y0 = y,y1 = y\ '\),經過變量替換就把原方程化爲以下的標準形式的微分方程組:
這樣就能夠用 solve_bvp() 求解該常微分方程的邊值問題。
以該題爲例講解scipy.integrate.solve_bvp 求解常微分方程邊值問題的步驟:
導入 scipy、numpy、matplotlib 包;
定義導數函數 dydx(x,y)
注意本問題中 y 表示向量,記爲 \(y=[y_0,y_1]\),導數定義函數 dydx(x,y) 編程以下:
# 導數函數,計算導數 dY/dx def dydx(x, y): dy0 = y[1] dy1 = -abs(y[0]) return np.vstack((dy0, dy1))
定義邊界條件函數 boundCond(ya,yb)
本問題中邊界條件爲常數,具體編程以下。注意對照 3.1中的邊值條件,沒有爲何,函數就是這麼定義的。
# 計算 邊界條件 def boundCond(ya, yb): fa = 0.5 # 邊界條件 y(xa=0) = 0.5 fb = -1.5 # 邊界條件 y(xb=4) = -1.5 return np.array([ya[0]-fa,yb[0]-fb])
設置 x、y 的初值
調用 solve_bvp() 求解常微分方程在區間 [xa,xb] 的數值解
由 solve_bvp() 的返回值 sol,得到網格節點的處的 y值。
# mathmodel11_v1.py # Demo10 of mathematical modeling algorithm # Solving ordinary differential equations (boundary value problem) with scipy. from scipy.integrate import odeint, solve_bvp import numpy as np import matplotlib.pyplot as plt # 1. 求解微分方程組邊值問題,DEMO # y'' + abs(y) = 0, y(0)=0.5, y(4)=-1.5 # 導數函數,計算導數 dY/dx def dydx(x, y): dy0 = y[1] dy1 = -abs(y[0]) return np.vstack((dy0, dy1)) # 計算 邊界條件 def boundCond(ya, yb): fa = 0.5 # 邊界條件 y(xa=0) = 0.5 fb = -1.5 # 邊界條件 y(xb=4) = -1.5 return np.array([ya[0]-fa,yb[0]-fb]) xa, xb = 0, 4 # 邊界點 (xa,xb) # fa, fb = 0.5, -1.5 # 邊界點的 y值 xini = np.linspace(xa, xb, 11) # 肯定 x 的初值 yini = np.zeros((2, xini.size)) # 肯定 y 的初值 res = solve_bvp(dydx, boundCond, xini, yini) # 求解 BVP xSol = np.linspace(xa, xb, 100) # 輸出的網格節點 ySol = res.sol(xSol)[0] # 網格節點處的 y 值 plt.plot(xSol, ySol, label='y') # plt.legend() plt.xlabel("x") plt.ylabel("y") plt.title("scipy.integrate.solve_bvp") plt.show()
水平面上的水滴橫截面形狀,能夠用以下的微分方程描述:
引入變量 \(h0 = h,h1 = h\ '\),經過變量替換就把原方程化爲以下的標準形式的微分方程組:
這樣就能夠用 solve_bvp() 求解該常微分方程的邊值問題。
注:本問題來自 司守奎 等,數學建模算法與應用(第2版),國防工業出版社,2015
# mathmodel11_v1.py # Demo10 of mathematical modeling algorithm # Solving ordinary differential equations (boundary value problem) with scipy. from scipy.integrate import odeint, solve_bvp import numpy as np import matplotlib.pyplot as plt # 3. 求解微分方程邊值問題,水滴的橫截面 # 導數函數,計算 h=[h0,h1] 點的導數 dh/dx def dhdx(x,h): # 計算 dh0/dx, dh1/dx 的值 dh0 = h[1] # 計算 dh0/dx dh1 = (h[0]-1)*(1+h[1]*h[1])**1.5 # 計算 dh1/dx return np.vstack((dh0, dh1)) # 計算 邊界條件 def boundCond(ha,hb): # ha = 0 # 邊界條件:h0(x=-1) = 0 # hb = 0 # 邊界條件:h0(x=1) = 0 return np.array([ha[0],hb[0]]) xa, xb = -1, 1 # 邊界點 (xa=0, xb=1) xini = np.linspace(xa, xb, 11) # 設置 x 的初值 hini = np.zeros((2, xini.size)) # 設置 h 的初值 res = solve_bvp(dhdx, boundCond, xini, hini) # 求解 BVP # scipy.integrate.solve_bvp(fun, bc, x, y,..) # fun(x, y, ..), 導數函數 f(y,x),y在 x 處的導數。 # bc(ya, yb, ..), 邊界條件,y 在兩點邊界的函數。 # x: shape (m),初始網格的序列,起止於兩點邊界值 xa,xb。 # y: shape (n,m),網格節點處函數值的初值,第 i 列對應於 x[i]。 xSol = np.linspace(xa, xb, 100) # 輸出的網格節點 hSol = res.sol(xSol)[0] # 網格節點處的 h 值 plt.plot(xSol, hSol, label='h(x)') plt.xlabel("x") plt.ylabel("h(x)") plt.axis([-1, 1, 0, 1]) plt.title("Cross section of water drop by BVP xupt") plt.show()
Mathieu 在研究橢圓形膜的邊界值問題時,導出了一個二階常微分方程,其形式爲:
用這種形式的數學方程能夠描述天然中的物理現象,包括振動橢圓鼓、四極質譜儀和四極離子阱、週期介質中的波動、強制振盪器參數共振現象、廣義相對論中的平面波解決方案、量子擺哈密頓函數的本徵函數、旋轉電偶極子的斯塔克效應。
式中 \(\lambda、q\) 是兩個實參數,方程的係數是以 \(\pi\) 或 \(2\pi\) 爲週期的,但只有在 \(\lambda、q\) 知足必定關係時 Mathieu 方程纔有週期解。
引入變量 \(y0 = y,y1 = y\ '\),經過變量替換就把原方程化爲以下的標準形式的微分方程組:
這樣就能夠用 solve_bvp() 求解該常微分方程的邊值問題。
以該題爲例講解scipy.integrate.solve_bvp 求解常微分方程邊值問題的步驟。
須要注意的是:(1)本案例涉及一個待定參數 \(\lambda\) 須要經過 solve_bvp(fun, bc, x, y, p=None) 中的可選項 p 傳遞到導數函數和邊界條件函數,(2)本案例涉及 3 個邊界條件,要注意邊界條件函數的定義。
導入 scipy、numpy、matplotlib 包;
定義導數函數 dydx(x,y,p)
本問題中 y 表示向量,記爲 \(y=[y_0,y_1]\),定義函數 dydx(x,y,p) 中的 p 是待定參數。
# 導數函數,計算導數 dY/dx def dydx(x, y, p): # p 是待定參數 lam = p[0] # 待定參數,從 solve-bvp() 傳遞過來 q = 10 # 設置參數 dy0 = y[1] dy1 = -(lam-2*q*np.cos(2*x))*y[0] return np.vstack((dy0, dy1))
定義邊界條件函數 boundCond(ya,yb,p)
注意,雖然邊界條件定義函數並無用到參數 p,但也必須寫在輸入變量中,函數就是這麼要求的。
# 計算 邊界條件 def boundCond(ya, yb, p): lam = p[0] return np.array([ya[0]-1,ya[0],yb[0]])
設置 x、y 的初值
調用 solve_bvp() 求解常微分方程在區間 [xa,xb] 的數值解
由 solve_bvp() 的返回值 sol,得到網格節點的處的 y值。
# mathmodel11_v1.py # Demo10 of mathematical modeling algorithm # Solving ordinary differential equations (boundary value problem) with scipy. from scipy.integrate import odeint, solve_bvp import numpy as np import matplotlib.pyplot as plt # 4. 求解微分方程組邊值問題,Mathieu 方程 # y0' = y1, y1' = -(lam-2*q*cos(2x))y0) # y0(0)=1, y1(0)=0, y1(pi)=0 # 導數函數,計算導數 dY/dx def dydx(x, y, p): # p 是待定參數 lam = p[0] q = 10 dy0 = y[1] dy1 = -(lam-2*q*np.cos(2*x))*y[0] return np.vstack((dy0, dy1)) # 計算 邊界條件 def boundCond(ya, yb, p): lam = p[0] return np.array([ya[0]-1,ya[0],yb[0]]) xa, xb = 0, np.pi # 邊界點 (xa,xb) xini = np.linspace(xa, xb, 11) # 肯定 x 的初值 xSol = np.linspace(xa, xb, 100) # 輸出的網格節點 for k in range(5): A = 0.75*k y0ini = np.cos(8*xini) # 設置 y0 的初值 y1ini = -A*np.sin(8*xini) # 設置 y1 的初值 yini = np.vstack((y0ini, y1ini)) # 肯定 y=[y0,y1] 的初值 res = solve_bvp(dydx, boundCond, xini, yini, p=[10]) # 求解 BVP y0 = res.sol(xSol)[0] # 網格節點處的 y 值 y1 = res.sol(xSol)[1] # 網格節點處的 y 值 plt.plot(xSol, y0, '--') plt.plot(xSol, y1,'-',label='A = {:.2f}'.format(A)) plt.xlabel("xupt") plt.ylabel("y") plt.title("Characteristic function of Mathieu equation") plt.axis([0, np.pi, -5, 5]) plt.legend(loc='best') plt.text(2,-4,"youcans-xupt",color='whitesmoke') plt.show()
初值 A從 0~3.0 變化時,y-x 曲線(圖中虛線)幾乎不變,但 y'-x 的振幅增大;當 A 再稍微增大,系統就進入不穩定區, y-x 曲線振盪發散(圖中未表示)。
關於 Mathieu 方程解的穩定性的討論,已經不是數學建模課的內容,再也不討論。
【本節完】
版權聲明:
歡迎關注『Python小白的數學建模課 @ Youcans』 原創做品
原創做品,轉載必須標註原文連接:。
Copyright 2021 Youcans, XUPT
Crated:2021-06-23
歡迎關注 『Python小白的數學建模課 @ Youcans』,每週更新數模筆記
Python小白的數學建模課-01.新手必讀
Python小白的數學建模課-02.數據導入
Python小白的數學建模課-03.線性規劃
Python小白的數學建模課-04.整數規劃
Python小白的數學建模課-05.0-1規劃
Python小白的數學建模課-A1.國賽賽題類型分析
Python小白的數學建模課-A2.2021年數維杯C題探討
Python小白的數學建模課-A3.12個新冠疫情數模競賽賽題及短評
Python小白的數學建模課-B2.新冠疫情 SI模型
Python小白的數學建模課-B3.新冠疫情 SIS模型
Python小白的數學建模課-B4.新冠疫情 SIR模型
Python小白的數學建模課-B5.新冠疫情 SEIR模型
Python小白的數學建模課-B6.改進 SEIR疫情模型
Python數模筆記-PuLP庫
Python數模筆記-StatsModels統計迴歸
Python數模筆記-Sklearn
Python數模筆記-NetworkX
Python數模筆記-模擬退火算法