python微分求解
这里用简单函数
假设我们现在知道原函数
$f(x)=x^2$
那么二阶微分方程为:
$$f’’(x)+f’(x)+(-2-2\times x) = 0$$
初始条件
$$f(0)=0 \quad f’(0)=0$$
先看代码
1  | import matplotlib.pyplot as plt  | 
解析式求解
使用 sympy 库 dsolve 函数
微分方程在 eq_test 函数里,其中 3 个注释掉了,分别是
$$f’’(x)+sin(x)=0 \quad f’’(x)+x^2=0 \quad f’’(x)+f(x)=0$$
1  | import sympy as sy  | 
使用函数 sympy,eq_test 函数即为微分方程,sy.pprint可以美化输出,print(sy.printing.latex(s))可以输出为 latex 代码
解析解:
$$\displaystyle f{\left(x \right)} = C_{1} + C_{2} e^{- x} + x^{2}$$
数值求解
scipy 里内置函数 odeint, solve_ivp 两个都可以,区别如下
| 函数 | 作用 | 速度 | 区别 | 
|---|---|---|---|
| odeint | 微分方程数值求解 | 快 | 参数简洁,推荐 | 
| solve_ivp | 如果使用 method='LSODA' 与 odeint 一样 | 相对慢一些 | 通用,含多个计算方式 | 
1  | import matplotlib.pyplot as plt  | 
odeint 函数
odeint 函数一般只需要传递 3 个参数
微分方程矩阵函数、自变量、初始值
1  | odeint(fvdp, y0, t, tfirst=True)  | 
微分方程矩阵函数
对于高阶,需要构造微分方程函数 fvdp,即最开始提到的方程为
$$
f’’(x)+f’(x)+(-2-2x) = 0 \quad f(0)=0 \quad f’(0)=0
$$
要把这个二阶方程全部转化为矩阵
$$[y’, y’’]$$
即 fvdp 函数的返回值,这个函数的参数为 t 自变量,y 因变量的导数矩阵 $[y, y’]$
odeint函数的参数顺序(y, t),如果要与solve_ivp一致参数顺序变成(t, y),odeint函数多传递一个参数tfirst=True
所以,返回值 $y’=y[1]$,y'' 用微分方程 ($f’’(x)+f’(x)+(-2-2x) = 0$) 表示
$y’’=-y[1]+2+2t$
最终 fvdp 函数返回值
$$[y’, y’’]=[y[1], -y[1]+2+2t]$$
自变量
用 numpy 数组表示即可 t = np.linspace(0, 5, 1000)
初始值
注意与自变量对应,二阶微分方程初始值为
$$[f(t_0), f’(t_0)]$$
这里的$t_0$必须是自变量的第一个值,不然会有很大的误差
返回值
odeint 函数返回值只有 ys=$[[y], [y’]]$ ,但是注意转置一下,行列不太方便,如果不转置
$y=ys[:, 0] \qquad y’=ys[:, 1]$
solve_ivp 函数
1  | y_ = solve_ivp(fvdp, t_span=tspan, method="LSODA", y0=y0, t_eval=t)  | 
微分方程矩阵函数
solve_ivp 不一样的仅仅只有参数顺序,这个函数参数应该是 (t, y) 与 matlab 是一致的,
- 自变量
 
这个也有区别,自变量数组在 t_eval=t,但是还需要一个 t_span=(min, max),其中 max min 为自变量数组的最大值最小值,如果只有t_span,取得值太少,不行
- 初始值
 
与 odeint 一致
- 返回值
 
ys = y_.y
$y=ys[0] \qquad y’=ys[1]$
总结
还是用 odeint吧,参数少一些,方便
其他
solve_ivp 积分:
详细看官网文档,包含各种方法的具体参考文献
‘RK45’(默认):显式 Runge-Kutta 5(4)阶。假设四阶方法的精度控制误差,但使用五阶精确公式(完成局部外推)采取步骤。四次插值多项式用于密集输出[2]。可应用于复杂领域。
‘RK23’:显式 Runge-Kutta (2)3 阶。假设二阶方法的精度,控制误差,但使用三阶精确公式(完成局部外推)采取步骤。三次 Hermite 多项式用于密集输出。可应用于复杂领域。
‘DOP853’:8 阶显式 Runge-Kutta。最初用 Fortran 编写的“DOP853”算法的 Python 实现。精确到 7 阶的 7 阶插值多项式用于密集输出。可应用于复杂领域。
‘Radau’:5 阶 Radau IIA 的隐式 Runge-Kutta。误差由三阶精确嵌入公式控制。满足搭配条件的三次多项式用于密集输出。
‘BDF’:基于导数逼近的后向微分公式的隐式多步变阶(1 到 5)方法。使用准恒定步长方案,并使用 NDF 修改提高精度。可应用于复杂领域。
‘LSODA’:具有自动刚度检测和切换功能的 Adams/BDF 方法。这是来自 ODEPACK 的 Fortran 求解器的封装。
显式 Runge-Kutta 方法(’RK23’、’RK45’、’DOP853’)应用于非刚性问题,隐式方法(’Radau’、’BDF’)应用于刚性问题。在 Runge-Kutta 方法中,建议使用“DOP853”进行高精度求解(rtol 和 atol 的值较低)。
如果不确定,请先尝试运行“RK45”。如果它进行了异常多次的迭代、发散或失败,则您的问题可能很僵硬,您应该使用“Radau”或“BDF”。’LSODA’ 也可以是一个很好的通用选择,但它可能不太方便,因为它包装了旧的 Fortran 代码。
本文作者:yuhldr
本文地址: [https://yuhldr.github.io/posts/13877.html](https://yuhldr.github.io/posts/13877.html)
版权声明:转载请注明出处!