【Scipy高级计算】(2) 常微分方程、洛伦兹吸引子,附python完整代码

大家好,在上一篇博文中,我介绍了如何使用Scipy库计算定积分和二重积分,感兴趣的可以看一下:https://blog.csdn.net/dgvv4/article/details/124226759

本文将继续使用 scipy.integrate 库求解常微分方程


1. 常微分方程

微分方程是指一个方程中有导数,表示未知函数的导数以及自变量之间关系的方程未知函数是一元函数的微分方程称作常微分方程未知函数是多元函数的微分方程称作偏微分方程。微分方程中出现的未知函数最高阶导数的阶数,成为微分方程的阶。例如:

y'= x   或   ( y - 2xy) dx + x^{2}dy = 0

'''
scipy.integrate中微分方程的求解方法
# -------------------------------------- #
odeint       常微分方程的通用函数
ode          求解常微分和偏微分
complex_ode  在复数域求解微分方程
# -------------------------------------- #
'''

本文之介绍 scipy.integrate.odeint() 求解常微分方程的方法,该函数的参数如下:

'''
参数
# -------------------------------------- #
func    常微分方程函数
y0      微分方程求解出的原函数的初值,导数:2x  原函数: x^(2) + y0 
t       微分方程的自变量数值序列
args    元组。func被积函数的自变量以外,需要的其他变量的参数,
# -------------------------------------- #
返回值:对应自变量序列的原函数的值
'''

案例一:简单常微分方程求解

求解常微分方程  \frac{dy}{dx}=x ,由于计算机不会计算出具体的公式,只会根据传进去的数据,计算出求解后的计算结果数据,因此自变量 x 应该传入一组数值序列 np.linspace(0, 10, 100) 。设置求解后的原函数初值y0=0

import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint

# 定义导数 y'=x, 求出原函数
def diff(y, x):
    res = np.array(x)
    # 返回导数
    return res  

# 给出x的范围, 从0到10产生100个数
x = np.linspace(0, 10, 100) 

# 求原函数, 初值为0, 自变量为x
y = odeint(func=diff, y0=0, t=x)  # y.shape=[100,1]

# 绘制导函数曲线
plt.plot(x, np.array(x), label='derivative')
# 绘制求解后的曲线
plt.plot(x, y[:,0], label='origin')  # y[:,0].shape=(100,)
plt.grid()  # 网格
plt.legend()  # 图例
plt.show()

绘制原导函数的曲线,和求解出的原函数的曲线


案例二:稍复杂的常微分方程求解

计算常微分方程  \frac{dy}{dx} = k\times x^{n}+b ,其中 k=3, n=2, b=4 ,计算结果的初值 y0=100,

import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint

# 定义导数 y'=x, 求出原函数
def diff(y, x, k, n, b):
    res = k * (np.array(x) ** n) + b 
    # 返回导数
    return res  

# 给出x的范围, 从0到10产生100个数
x = np.linspace(0, 10, 100) 

# 求原函数,  初值为100,  自变量为x,  k,n,b=(3.0, 2, 4.0)
y = odeint(func=diff, y0=100.0, t=x, args=(3.0, 2, 4.0))  # y.shape=[100,1]

# 绘制导函数曲线
plt.plot(x, 3.0*(np.array(x)**2)+4.0, label='derivative')
# 绘制计算结果函数曲线
plt.plot(x, y[:,0], label='origin')  # y[:,0].shape=(100,)
plt.grid()  # 网格
plt.legend()  # 图例
plt.show()

绘制原导函数的曲线,和求解出的结果函数的曲线


2. 洛伦兹吸引子

洛伦兹方程是大气流体动力学模型的一个简化的常微分方程组:

\LARGE \left\{\begin{matrix} \frac{dx}{dt}=-\sigma x+\sigma y\\ \frac{dy}{dt}=rx-y-xz\\ \frac{dz}{dt}=-bz+xy \end{matrix}\right.

该模型将大气流体运动的强度 x 水平和垂直方向的温度变化 y 和 z 联系了起来。参数 \large \sigma 称为普兰特系数,r 是规范化的瑞利数,b 和几何形状相关。洛伦兹方程是非线性方程组,无法求出解析解,必须使用数值方法求解上述微分方程组。

首先需要定义出洛伦兹函数 lorenz,位置参数 w 包含三维坐标 (x, y, z),参数 p 代表普兰特系数。构建和上面公式相同的导函数。自变量为 t,计算出三个坐标对于自变量 t 的导函数。

求解后的位置坐标点初始值 (x0, y0, z0)=(0.0, 1.0, 0.0),args对应三个洛伦兹参数 (p, r, b)=(10.0, 28.0, 3.0)

import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint

# 定义洛伦兹函数, 位置矢量w, 三个参数p、r、b
def lorenz(w, t, p, r, b):
    x, y, z = w.tolist() # tolist()是把数组中的值作为列表元素, 生成列表与原数组结构相同
    # 计算导数 dx/dt, dy/dt, dz/dt
    return p*(y-x), x*(r-z)-y, x*y-b*z

# 自变量的取值序列, 0到30,步长0.02
t = np.arange(0, 30, 0.02)

# x, y, z的初值
initial_val = (0.0, 1.0, 0.0)

# 求解常微分方程, args是p、r、b的值, track.shape=(1500, 3)
track = odeint(func=lorenz, y0=initial_val, t=t, args=(10.0, 28.0, 3.0))

# 绘图
fig = plt.figure()
ax=fig.gca(projection='3d')  # 三维绘图
# 取出xyz坐标点值
x, y, z = track[:,0], track[:,1], track[:,2]
ax.plot(x,y,z)
plt.show()

绘制洛伦兹方程求解出的x,y,z坐标

猜你喜欢

转载自blog.csdn.net/dgvv4/article/details/124228904