| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 人工智能 -> 【Python常微分方程】 -> 正文阅读 |
|
[人工智能]【Python常微分方程】 |
方程中的未知量是方程而不是变量,并且涉及未知函数导数的方程称为微分方程(Differential Equation, ED)。在这类方程中,如果导数的未知函数只有一个因变量,称之为常微分方程(Ordinary Differential Equation, ODE)。如果方程中存在多个变量的导数,则称为偏微分方程(Partial Differential Equation, PDE)。 常微分方程在科学和工程中有广泛引用。例如根据牛顿第二运动定律,物体在力的作用下的位移 s s s和时间 t t t的关系就可以表示为如下常微分方程: m d 2 s d t 2 = f ( s ) m{\frac {d^{2}s}{dt^{2}}}=f(s) mdt2d2s?=f(s) 除非特殊情况,常微分方程的解析闭合解不存在,我们需要使用数值方法进行求解。 1. 导入模块为了求解ODE,我们需要使用SymPy库以及SciPy的integrate模块。
2. 常微分方程常微分方程的最简单形式是 d y ( x ) d x = f ( x , y ( x ) ) \frac{dy(x)}{dx}=f(x, y(x)) dxdy(x)?=f(x,y(x)),其中 y ( x ) y(x) y(x)是未知函数, f ( x , y ( x ) ) f(x, y(x)) f(x,y(x))是已知函数。由于方程中有 y ( x ) y(x) y(x)的导数,因此这是一个微分方程。同时该方程中只出现了一阶导数,因此这是一阶ODE。更一般的情况下,可以将n阶ODE写为隐式形式 F ( x , y , d y d x , ? ? , d n y d x n ) F(x, y, \frac{dy}{dx},\cdots,\frac{d^ny}{dx^n}) F(x,y,dxdy?,?,dxndny?),其中 F F F是已知函数。 二阶ODE的例子为牛顿第二运动定律
F
=
m
a
F=ma
F=ma,也可写成
F
(
x
(
t
)
)
=
m
d
2
x
(
t
)
d
t
2
F(x(t))=m\frac{d^2x(t)}{dt^2}
F(x(t))=mdt2d2x(t)?。为了求解该ODE,我们除了找到它的一般解,还必须给出对象的初始位置和速度。类似的,
n
n
n阶ODE的一般解有
n
n
n个自由参数,需要给出未知函数的初始条件以及
n
?
1
n-1
n?1阶导数。 d d x [ y 1 y 2 ? y n ] = [ y 2 y 3 ? g ( x , y 1 , ? ? , y n ) ] \frac{d}{dx} \begin{bmatrix}y_1 \\y_2 \\\vdots \\y_n\end{bmatrix}= \begin{bmatrix}y_2 \\y_3 \\\vdots \\g(x, y_1, \cdots, y_n) \end{bmatrix} dxd???????y1?y2??yn????????=??????y2?y3??g(x,y1?,?,yn?)??????? 上式可以写为更紧凑的形式 d d x y ( x ) = f ( x , y ( x ) ) \frac{d}{dx}\mathbf{y}(x) = f(x, \mathbf{y}(x)) dxd?y(x)=f(x,y(x))。 牛顿第二定律可以写成标准形式 y = [ y 1 = x , y 2 = d x d t ] \mathbf{y}=[y_1=x, y_2=\frac{dx}{dt}] y=[y1?=x,y2?=dtdx?],或者 d d t [ y 1 y 2 ] = [ y 2 F ( y 1 ) / m ] \frac{d}{dt} \begin{bmatrix}y_1 \\y_2 \end{bmatrix} = \begin{bmatrix}y_2 \\F(y_1)/m\end{bmatrix} dtd?[y1?y2??]=[y2?F(y1?)/m?] 如果函数 f 1 , f 2 , ? ? , f n f_1, f_2, \cdots,f_n f1?,f2?,?,fn?是线性的,那么对应的常微分方程组可以写成简单形式: d d x y ( x ) = A ( x ) y ( x ) + r ( x ) \frac{d}{dx}\mathbf{y}(x) =\mathbf{A}(x)\mathbf{y}(x) + \mathbf{r}(x) dxd?y(x)=A(x)y(x)+r(x) 其中 A ( x ) A(x) A(x)是一个n×n的矩阵, r ( x ) r(x) r(x)是一个仅依赖于x的n维向量,被称为源项。如果 r ( x ) = 0 r(x) = 0 r(x)=0,则线性方程组是齐次的。线性常微分方程是可以求解的(例如使用 A ( x ) A(x) A(x)的特征值分解)。对于一般的 f ( x , y ( x ) ) f(x, y(x)) f(x,y(x)),没有通用的求解方法。 3. 符号方法求解ODESymPy提供了一个通用的ODE求解器 3.1 牛顿冷却定律为了演示SymPy求解ODE的方法,我们考虑一个简单的一阶ODE,牛顿冷却定律 d T ( t ) d t = ? k ( T ( t ) ? T a ) \frac{dT(t)}{dt} = -k(T(t)-T_a) dtdT(t)?=?k(T(t)?Ta?),其中初始温度 T ( 0 ) = T 0 T(0)=T_0 T(0)=T0?。该定律描述了环境温度 T a T_a Ta?中的物体温度随时间的变化。
将ODE写为 d T ( t ) d t + k ( T ( t ) ? T a ) = 0 \frac{dT(t)}{dt} + k(T(t)-T_a) = 0 dtdT(t)?+k(T(t)?Ta?)=0,并为ODE左边创建一个SymPy表达式
3.2 自动应用初始条件上述一阶问题求解未知积分常数的过程比较简单直接,但是在高阶问题中应用初始条件和求解积分常数较为繁琐。我们可以将这些步骤集中到一个函数之中,将这个过程推广到任意阶数的微分方程。
3.3 阻尼振荡器作为一个稍微复杂一点的例子,我们考虑阻尼谐波振荡器的ODE,这是二阶ODE d 2 x ( t ) d t 2 + 2 γ ω 0 d x ( t ) d t + ω 0 2 x ( t ) = 0 \frac{d^2 x(t)}{dt^2} + 2 \gamma \omega_0 \frac{d x(t)}{dt} + \omega_0^2 x(t) = 0 dt2d2x(t)?+2γω0?dtdx(t)?+ω02?x(t)=0 其中 x ( t ) x(t) x(t)是振荡器在时间 t t t的位置, ω 0 \omega_0 ω0?是无阻尼的振荡频率, γ \gamma γ是阻尼比。 当阻尼为0时,上式就是简谐运动的运动方程。
其中0.707为工程最优阻尼比,兼顾稳定性,快速性,准确性
3.4 方向场图方向场图可以用于可视化一阶ODE的可能解。它由x-y平面网格中未知函数斜率的短线组成。 我们只需要遍历坐标网络中感兴趣区域的x和y值,然后计算 f ( x , y ( x ) ) f(x, y(x)) f(x,y(x))在该点的斜率,就可以生成该ODE的方向场图。 在方向场图中,与斜率相切的平滑连续曲线就是ODE的可能解。
使用上面的函数,为 f ( x , y ( x ) ) = ? x / y ( x ) f(x, y(x)) = -x/y(x) f(x,y(x))=?x/y(x)、 f ( x , y ( x ) ) = y ( x ) 2 + x f(x, y(x)) = y(x)^2+x f(x,y(x))=y(x)2+x和 f ( x , y ( x ) ) = ? y ( x ) f(x, y(x)) = -y(x) f(x,y(x))=?y(x)生成方向场图。
3.5 近似解析解下面我们将借助方向场图对无法解析求解的ODE问题进行可视化分析。 考虑ODE d y ( x ) d x = x + y ( x ) 2 \frac{dy(x)}{dx}=x+y(x)^2 dxdy(x)?=x+y(x)2,初始条件y(0) = 0。
根据幂级数解的性质,x较大时误差会急剧扩大。误差在左图中, x = 0 x = 0 x=0 附近,近似解的曲线可以很好地与方向线对齐,但是 ∣ x ∣ ≥ 0 |x| \geq 0 ∣x∣≥0时开始偏离。我们可以通过不断拓展初始条件x的值分段求解ODE,可以获得扩展的有效范围内的解法。右图红色曲线就是通过使用初始条件序列求解ODE得到的连续曲线。
3.6 使用拉普拉斯变换求解ODE对ODE进行拉普拉斯变换,可以将很多问题转化为更容易求解的代数方程。然后可以通过拉普拉斯逆变换将代数方程的解转换回原始域,从而得到原始问题的解。 拉普拉斯变换是一个线性变换,可将一个有实数变量 t ≥ 0 t\geq 0 t≥0的函数变换为一个变量为复数 s s s的函数。函数导数的拉普拉斯变换是函数自身拉普拉斯变换的线性表达式:
L
{
f
′
(
t
)
}
=
s
?
L
{
f
(
t
)
}
?
f
(
0
)
{\mathcal {L}}\left\{f'(t)\right\}=s\cdot {\mathcal {L}}\left\{f(t)\right\}-f(0)
L{f′(t)}=s?L{f(t)}?f(0) d 2 d t 2 y ( t ) + 2 d d t y ( t ) + 10 y ( t ) = 2 s i n 3 t \frac{d^2}{dt^2}y(t) + 2\frac{d}{dt}y(t) + 10y(t) = 2sin3t dt2d2?y(t)+2dtd?y(t)+10y(t)=2sin3t
4. 数值求解ODE任何ODE问题都可以标准形式写为一阶常微分方程组,我们这里将讨论标准形式 d y ( x ) d x = f ( x , y ( x ) ) \frac{dy(x)}{dx}=f(x, y(x)) dxdy(x)?=f(x,y(x))的一阶常微分方程的数值求解方法,并介绍SciPy的相关函数。 4.1 欧拉方法很多ODE数值方法的基本思想都来自欧拉方法,欧拉方法可以从函数 y ( x ) y(x) y(x)在点 x x x处的泰勒级数展开推导而来: y ( x + h ) = y ( x ) + d y d x h + 1 2 d 2 y d x 2 h 2 + ? y(x+h)=y(x)+\frac{dy}{dx}h+\frac{1}{2}\frac{d^2y}{dx^2}h^2+\cdots y(x+h)=y(x)+dxdy?h+21?dx2d2y?h2+? 去掉二阶和更高阶的项,我们得到近似等式 y ( x + h ) ≈ y ( x ) + d y d x h y(x+h)\approx y(x)+\frac{dy}{dx}h y(x+h)≈y(x)+dxdy?h,该式中的步长 h h h已精确到一阶。通过将变量 x x x离散化为 x 0 x_0 x0?、 x 1 x_1 x1?、 x 2 x_2 x2?、 ? \cdots ?、 x k x_k xk?,并设置步长 h k = x k + 1 ? x k h_k = x_{k+1} - x_k hk?=xk+1??xk?,可以将公式转换为迭代公式: y k + 1 ≈ y k + f ( x k , y k ) h k y_{k+1}\approx y_k+f(x_k, y_k)h_k yk+1?≈yk?+f(xk?,yk?)hk? 该公式被称为前向欧拉法。 该方法会带来两方面误差:泰勒级数截断产生的误差,以及计算
y
k
+
1
y_{k+1}
yk+1?时,
y
k
y_{k}
yk?近似值造成的累计误差。 y k + 1 ≈ y k + f ( x k + 1 , y k + 1 ) h k y_{k+1}\approx y_k+f(x_{k+1}, y_{k+1})h_k yk+1?≈yk?+f(xk+1?,yk+1?)hk? 这是一种后向微分公式(BDF),并且是隐式的。因为为了计算 y k + 1 y_{k+1} yk+1?需要求解一个代数方程。在每一个迭代过程中,隐式法相比显式法要做更多的计算,但是隐式法通常拥有更大的稳定区域以及更高的准确性。这意味着隐式法可以使用更大的步长。对于描述具有多个不同时间尺度的动力学ODE问题,例如包含快速振荡和慢速振荡的动力学,隐式法是更好的选择。 4.2 高阶方法改进一阶欧拉方法的一个途径是在泰勒级数展开中保留高阶项。例如二阶方法: y ( x + h ) ≈ y ( x ) + d y d x h + 1 2 d 2 y d x 2 h 2 y(x+h)\approx y(x)+\frac{dy}{dx}h+\frac{1}{2}\frac{d^2y}{dx^2}h^2 y(x+h)≈y(x)+dxdy?h+21?dx2d2y?h2 计算函数
y
(
x
)
y(x)
y(x)高阶导数,可以使用导数的有限差分,或者通过在区间
[
x
k
,
x
k
+
1
]
[x_k, x_{k+1}]
[xk?,xk+1?]的中点对
f
(
x
,
y
(
x
)
)
f(x, y(x))
f(x,y(x))进行采样来近似高阶导数。 y k + 1 = y k + h k 6 ( k 1 + 2 k 2 + 2 k 3 + k 4 ) y_{{k+1}}=y_{k}+{h_k \over 6}(k_{1}+2k_{2}+2k_{3}+k_{4}) yk+1?=yk?+6hk??(k1?+2k2?+2k3?+k4?) 其中 这里的 k 1 ~ k 4 k_1 \sim k_4 k1?~k4?的计算需要使用前面计算 y k + 1 y_{k+1} yk+1?的显式公式。 通过组合不同阶的方法,可以估计近似值的误差。一种常见的组合是龙格-库塔法的四阶和五阶组合,这种方法被称为RK45。 4.3 多步方法另外一个改进精度的途径是使用 y k y_k yk?的多个前值来计算 y k + 1 y_{k+1} yk+1?,这被称为线性多步法。它的迭代公式为: y k + s = ∑ n = 0 s ? 1 a n y k + n + h ∑ n = 0 s b n f ( x k + n , y k + n ) y_{k+s} = \sum _{n=0}^{s-1}a_{n}y_{k+n} + h\sum _{n=0}^{s}b_{n}f(x_{k+n},y_{k+n}) yk+s?=n=0∑s?1?an?yk+n?+hn=0∑s?bn?f(xk+n?,yk+n?) 使用以上公式,可以利用前 s s s个 y k y_k yk?和 f ( x k , y k ) f(x_{k},y_{k}) f(xk?,yk?)来计算 y k + s y_{k+s} yk+s?( s s s步法)。如果 b n = 0 b_{n}=0 bn?=0则是显式法;如果 b n ≠ 0 b_{n} \neq 0 bn??=0则是隐式法。 例如, a 0 = b 1 = 1 a_0 = b_1 = 1 a0?=b1?=1的一步BDF法可退化为后向欧拉法;两步BDF法在求解出系数 a 0 a_0 a0?、 a 1 a_1 a1?和 b 2 b_2 b2?后,迭代公式为 y k + 2 = ? 1 3 y k + 4 3 y k + 1 + 2 3 h f ( x k + 2 , y k + 2 ) y_{k+2} = -\frac{1}{3} y_k + \frac{4}{3} y_{k+1} + \frac{2}{3} hf(x_{k+2},y_{k+2}) yk+2?=?31?yk?+34?yk+1?+32?hf(xk+2?,yk+2?)。 为了更高的精度,我们还可以构建更高阶的BDF方法。 对于刚性方程,求解方程的某些数值方法在数值上是不稳定的,除非步长非常小。推荐使用SciPy中提供了BDF求解器处理刚性问题。 例如,Adams–Bashforth法和Adams–Moulton法的两步法分别是: 如果误差值可以估计,求解器就可以在可能的时候使用较大的步长或者使用较低的阶数来提升计算效率。在Adams法中,阶数可以很容易改变。 SciPy同样提供了Adams法的求解器,可以用于非刚性方程。 4.4 预测-矫正法一般来说,显式法比隐式法更容易实现,计算量较小。但是隐式法通常更精确且稳定性更好。 一种兼顾两种方法优点的折中办法时将显式法和隐式法组合使用:首先使用显式法计算 y k + 1 y_{k+1} yk+1?,然后使用 y k + 1 y_{k+1} yk+1?作为隐式法中求解方程的初始猜测值。这个方程不需要精确求解,只需要进行少量的迭代即可。 这种使用显式法预测 y k + 1 y_{k+1} yk+1?,使用隐式法矫正预测值的方法称为预估-矫正法。 5. SciPy对ODE进行数值积分SciPy的integrate模块提供了两种ODE求解器接口:integrate.odeint和integrate.ode。
5.1 标量问题为了展示
需要注意, 接下来,需要定义初始值 y 0 y_0 y0?以及因变量 x x x离散化后的NumPy数组。
下面,我们将数值积分结果与方向场绘制在一起,可以看到数值解与方向场中的线对齐相切。
5.2 ODE方程组5.2.1 二阶ODE问题我们首先回顾受驱阻尼振荡器的二阶ODE问题: d 2 d t 2 y ( t ) + 2 d d t y ( t ) + 10 y ( t ) = 2 s i n 3 t \frac{d^2}{dt^2}y(t) + 2\frac{d}{dt}y(t) + 10y(t) = 2sin3t dt2d2?y(t)+2dtd?y(t)+10y(t)=2sin3t 我们需要引入 y 1 ( t ) = y ( t ) y_1(t) = y(t) y1?(t)=y(t)和 y 2 ( t ) = y ′ ( t ) y_2(t) = y'(t) y2?(t)=y′(t)将方程写成标准形式:
d
d
t
[
y
1
y
2
]
=
[
y
2
2
s
i
n
3
t
?
2
y
2
(
t
)
?
10
y
1
(
t
)
]
\frac{d}{dt} \begin{bmatrix}y_1 \\y_2 \end{bmatrix}= \begin{bmatrix}y_2 \\ 2sin3t - 2y_2(t) - 10y_1(t) \end{bmatrix}
dtd?[y1?y2??]=[y2?2sin3t?2y2?(t)?10y1?(t)?]
为初始条件 y ( 0 ) = 1 y(0)=1 y(0)=1 和 y ′ ( 0 ) = 0 y'(0)=0 y′(0)=0创建数组:
5.2.2 耦合ODE问题在前面的示例中,ODE右侧的函数在实现时没有使用附加参数。如果需要使用可调参数,通常在实现
f
f
f时,将所有系数或参数作为
x
′
(
t
)
=
σ
(
y
?
x
)
x'(t) = \sigma(y - x)
x′(t)=σ(y?x) 这些方程因为它们的混沌解而著名,这些解敏感地依赖于参数 σ \sigma σ、 ρ \rho ρ和 β \beta β的值。 如果希望使用这些参数的不同值来求解这些方程,可以编写一个含有参数变量的函数。
设置 x ( t ) x(t) x(t)、 x ( t ) x(t) x(t)和 z ( t ) z(t) z(t)的初始条件:
调用
下面将绘制三个解的3D图形,可以看到,当参数发生很小的变化时,得到的解可能会有很大区别。
5.3 integrate.ode类在SciPy中,可以将 在使用
这里函数返回的是一个一维数组,元素是ODE函数的导数。需要的参数被打包在元组args中。注意,初始条件只能使用列表或者一维数组。
我们需要创建一个 求解器实例保存在变量 还可以使用方法
使用BqPlot对运动轨迹进行动态可视化。
参考文献来自桑鸿乾老师的课件:科学计算和人工智能 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/26 4:39:09- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |