09.2 微分方程#
本節目標#
- 理解常微分方程(ODE)的基本概念:階數、通解與特解
- 學會用
dsolve()解三種典型方程:分離變數型、一階線性、二階常係數 - 掌握特徵方程與二階齊次解的關係(銜接 6.3 的多項式求根)
- 用
ics參數給定初值條件,求出唯一的特解 - 動手實驗:改變參數求解並畫出解曲線族
微分方程的概念#
微分方程是「含有未知函數導數的方程」。例如:
- 階數:方程中出現的最高導數階數
- 通解:滿足方程的解的一般形式,含有任意常數( \(n\) 階方程有 \(n\) 個)
- 特解:用初值條件(如 \(y(0) = 1,\ y'(0) = 0\) )把常數定下來後的解
在 SymPy 中,未知函數必須先用 Function 宣告成「函數符號」:
from sympy import symbols, Function
t = symbols('t')
y = Function('y')(t) # y 是 t 的未知函數
print(y.diff(t)) # Derivative(y(t), t)
print(y.diff(t, 2)) # Derivative(y(t), t, t)
dsolve() 用法:分離變數型#
指數成長模型 \(y' = ky\) 是最經典的分離變數型方程: \(\dfrac{dy}{y} = k\,dt\) ,積分得 \(y = Ce^{kt}\) 。
from sympy import symbols, Function, dsolve, exp, Eq
t, k = symbols('t k')
y = Function('y')
sol = dsolve(y(t).diff(t) - k*y(t), y(t))
print(sol) # Eq(y(t), C1*exp(k*t))
dsolve(方程, y(t)) 的第一個參數也可以直接給 Eq(...) 形式。帶初值條件時用 ics 參數,以字典 {y(0): 1} 表示:
sol = dsolve(y(t).diff(t) - k*y(t), y(t), ics={y(0): 5})
print(sol) # Eq(y(t), 5*exp(k*t))
一階線性方程#
一階線性方程的標準型:
解法是找積分因子 \(\mu(t) = e^{\int p\,dt}\) ,但 SymPy 的 dsolve 會自動分類並求解:
from sympy import Function, dsolve, symbols
t = symbols('t')
y = Function('y')
# y' + y = t
sol = dsolve(y(t).diff(t) + y(t) - t, y(t))
print(sol)
# Eq(y(t), C1*exp(-t) + t - 1)
# 帶初值條件 y(0) = 2
sol2 = dsolve(y(t).diff(t) + y(t) - t, y(t), ics={y(0): 2})
print(sol2)
# Eq(y(t), 2*exp(-t) + t - 1)
二階常係數與特徵方程(銜接 6.3)#
對齊次方程 \(ay'' + by' + cy = 0\) ,假設解為 \(y = e^{rt}\) ,代入後得到特徵方程:
這正是第 6.3 節學過的一元二次多項式方程!三種情況:
| 判別式 \(b^2 - 4ac\) | 解的形式 |
|---|---|
| \(> 0\) (相異實根) | \(y = C_1 e^{r_1 t} + C_2 e^{r_2 t}\) |
| \(= 0\) (重根) | \(y = (C_1 + C_2 t)e^{rt}\) |
| \(< 0\) (共軛複根 \(\alpha \pm \beta i\) ) | \(y = e^{\alpha t}(C_1 \cos \beta t + C_2 \sin \beta t)\) |
**範例: \(y'' + y = 0\) **。特徵方程 \(r^2 + 1 = 0\) 有根 \(r = \pm i\) ,所以解是正弦與餘弦的組合:
from sympy import Function, dsolve, symbols, Eq
t = symbols('t')
y = Function('y')
sol = dsolve(y(t).diff(t, 2) + y(t), y(t))
print(sol)
# Eq(y(t), C1*sin(t) + C2*cos(t))
# 用 6.3 的 solve 解特徵方程,驗證根確實是 ±i
r = symbols('r')
from sympy import solve
print(solve(r**2 + 1, r)) # [-I, I]
帶初值條件 \(y(0) = 1,\ y'(0) = 0\) (初始位移 1、初速 0 的單擺/彈簧振盪):
sol = dsolve(y(t).diff(t, 2) + y(t), y(t),
ics={y(0): 1, y(t).diff(t).subs(t, 0): 0})
print(sol) # Eq(y(t), cos(t))
再看一個阻尼振盪: \(y'' + 2y' + 5y = 0\) ,判別式 \(4 - 20 < 0\) ,解中有 \(e^{-t}\) 衰減因子:
sol = dsolve(y(t).diff(t, 2) + 2*y(t).diff(t) + 5*y(t), y(t),
ics={y(0): 1, y(t).diff(t).subs(t, 0): 0})
print(sol)
# Eq(y(t), (cos(2*t) + sin(2*t)/2)*exp(-t))
動手實驗:參數變動與解曲線族#
實驗一:改變成長率 \(k\) ,畫出 \(y' = ky\) 、 \(y(0) = 1\) 的解曲線族,觀察 \(k\) 的正負如何決定成長或衰退:
import numpy as np
import matplotlib.pyplot as plt
from sympy import symbols, Function, dsolve, lambdify
t, k = symbols('t k')
y = Function('y')
ts = np.linspace(0, 3, 200)
for kv in [-1, -0.5, 0.5, 1, 2]:
sol = dsolve(y(t).diff(t) - k*y(t), y(t), ics={y(0): 1})
f = lambdify(t, sol.rhs.subs(k, kv))
plt.plot(ts, f(ts), label=f'k = {kv}')
plt.axhline(0, color='gray', lw=0.5)
plt.legend()
plt.title("$y' = ky,\\ y(0)=1$,不同 k 的解")
plt.xlabel('t'); plt.ylabel('y')
plt.show()
實驗二:阻尼振盪 \(y'' + 2y' + cy = 0\) ,掃過不同的 \(c\) ,從欠阻尼到過阻尼:
ts = np.linspace(0, 10, 500)
for cv in [1, 2, 5, 10]:
sol = dsolve(y(t).diff(t, 2) + 2*y(t).diff(t) + cv*y(t), y(t),
ics={y(0): 1, y(t).diff(t).subs(t, 0): 0})
f = lambdify(t, sol.rhs)
plt.plot(ts, f(ts), label=f'c = {cv}')
plt.legend()
plt.title('阻尼振盪:c 越大衰減越快')
plt.xlabel('t'); plt.ylabel('y')
plt.show()
觀察重點: \(c = 1\) 時明顯振盪(欠阻尼,複根); \(c = 10\) 時單調衰減(過阻尼,相異實根)。臨界值 \(c = 1\) 對應重根 \(r = -1\) ,正好是判別式為零的情形——特徵方程的理論與圖形完全吻合。
小結與練習#
本節重點
- 未知函數用
Function('y')(t)宣告,導數用.diff(t) dsolve(方程, y(t))自動分類並求解;ics={y(0): ..., y'(0): ...}給初值條件- 分離變數型、一階線性、二階常係數是三大基本類型
- 二階常係數的解由特徵方程 \(ar^2 + br + c = 0\) 的根決定(複習 6.3)
lambdify把符號解轉成數值函數,方便畫圖
練習
- 解 \(y' = y\cos t\) (分離變數型),並驗證解確實滿足方程。
- 解 \(y' - 2ty = t\) (一階線性),帶初值條件 \(y(0) = 0\) 。
- 解 \(y'' - 4y' + 4y = 0\) , \(y(0) = 1\) , \(y'(0) = 0\) ,並說明為什麼解中有 \(t e^{2t}\) 項。
- 實驗:對 \(y'' + y = 0\) 分別設 \(y(0) = 1, y'(0) = 0\) 與 \(y(0) = 0, y'(0) = 1\) ,畫出兩條解曲線,確認它們是 \(\cos t\) 與 \(\sin t\) 。