用python的scipy中的odeint来解常微分方程中的一些细节问题(适用于小白)

2023-05-16

用python的scipy中的odeint来解常微分方程中的一些细节问题(适用于小白)

写在前面

最近有些需要解决常微分方程的问题,网上查了很多教程都不是很明晰,便自己研究了一段时间,写一点小白初次接触这个方法应该如何理解,有哪些需要注意的点。
odeint在官网的参数很多,如下所示:

scipy.integrate.odeint(func, y0, t, args=(), Dfun=None, col_deriv=0, full_output=0, ml=None, 
mu=None, rtol=None, atol=None, tcrit=None, h0=0.0, hmax=0.0, hmin=0.0, ixpr=0, mxstep=0, 
mxhnil=0, mxordn=12, mxords=5, printmessg=0, tfirst=False)

我们这次简单点只使用前三个参数scipy.integrate.odeint(func, y0, t),如果想了解更多,其他教程应该有更详细的教学,这里只说一点最简单的原理和注意事项。

  • 第一个参数是我们自行定义的需要求解的微分方程的函数
  • 第二个参数代表求解的微分方程的初值,没有初值微分方程的解不能唯一确定
  • 第三个参数是求解的微分方程中的自变量,应该是一个连续的序列值

我们必须明确,求解微分方程最终我们得到的是一个关于自变量的函数,而不是一个值。

在此我们说一点基础的数学知识点,对于一个函数,比如
y = 4 x 3 + 100 y=4x^3+100 y=4x3+100
我们对它求导得到:
y ′ = 12 x 2 y'=12x^2 y=12x2
那么对应的,求解第二个微分方程就能得到第一个方程吗?
答案是否定的,因为对第二个导数式子积分,得到的是:
y = 4 x 3 + a ( 常 数 ) y = 4x^3 + a(常数) y=4x3+a()
只有求解出常数a,才能唯一确定一个微分方程的解;否则我们得到的是一系列相差常数的解

官网例子说明

在odeint的官网里面有个具体的例子,我们拿出来讲一讲,
θ ′ ′ ( t ) + b ∗ θ ′ ( t ) + c ∗ s i n ( θ ( t ) ) = 0 \theta''(t) + b*\theta'(t) + c*sin(\theta(t)) = 0 θ(t)+bθ(t)+csin(θ(t))=0
官网的办法是说把这个二阶的微分方程先变换作一阶的方程组:
θ ′ ( t ) = ω ( t ) \theta'(t) = \omega(t) θ(t)=ω(t) ω ′ ( t ) = − b ∗ ω ( t ) − c ∗ s i n ( θ ( t ) ) \omega'(t) = -b*\omega(t) - c*sin(\theta(t)) ω(t)=bω(t)csin(θ(t))
这里边有一个代换过程:

ω ( t ) = θ ′ ( t ) \omega(t) = \theta'(t) ω(t)=θ(t)
因此有: ω ′ ( t ) = θ ′ ′ ( t ) = − b ∗ ω ( t ) − c ∗ s i n ( θ ( t ) ) \omega'(t)= \theta''(t) = -b*\omega(t) - c*sin(\theta(t)) ω(t)=θ(t)=bω(t)csin(θ(t))
最终我们需要的两个方程是: θ ′ ( t ) = ω ( t ) \theta'(t)=\omega(t) θ(t)=ω(t) ω ′ ( t ) = − b ∗ ω ( t ) − c ∗ s i n ( θ ( t ) ) \omega'(t)= -b*\omega(t) - c*sin(\theta(t)) ω(t)=bω(t)csin(θ(t))

随后官网根据这个代换过程定义了一个函数:

def pend(y, t, b, c):
    theta, omega = y
    dydt = [omega, -b*omega - c*np.sin(theta)]
    return dydt

或许有些python基础不是很好的同学对于这个函数比较陌生,我先来解释下,

  • 参数b,c是系统的常数我们暂且承认即可
  • t是微分方程的自变量,这个没有争议
  • theta, omega = y,这句可能会有疑惑,我们传入的y到底是个啥?

还记得前面的一阶代换过程嘛,简单来说就是把y先分成theta和omega,一个代表原微分方程theta第二个代表theta的一阶导;再对这两个求导就分别得到了一阶导和二阶导。

  • 此函数返回的dydt是一个列表,分别代表theta的一阶导 和 二阶导 ,但是两阶导数是通过中间变量omega的一阶导数来表示的。

这里面牵扯了一些数学代换,最终的式子为了变量减少,只能出现不带导数的theta和omega,看不懂先看下去,后面会有一个简单的例子来说明,我们先大概了解官网这个例子在说什么即可。

有些同学或许觉得现在我们就可以调用方程求解了,其实认真看的同学知道,我们此时还缺少关键的初始条件,否则无法确定唯一的一个解。为了方便此时我们把系统变量b,c同时定义好:

b = 0.25
c = 5.0
y0 = [np.pi - 0.1, 0.0] #初始条件

此处初始条件有两个是因为,我们有一个方程组(两个方程),原方程和一阶方程都需要初始条件(同样可以看到后面的简单例子)。

在编程时我们还需要定义自变量,这个也很重要,

t = np.linspace(0, 10, 101)

到此为止,准备工作全部完成,我们可以求解了。

sol = odeint(pend, y0, t, args=(b, c))

其实我们会发现这个结果sol,是一个形状为(101,2)的数组。第一列是theta(t),第二列是omega(t),也就是说得到了两个解,theta(t)是原微分方程的解,omega(t)是原方程的一阶导数方程。

plt.plot(t, sol[:, 0], 'b', label='theta(t)')
plt.plot(t, sol[:, 1], 'g', label='omega(t)')
plt.legend(loc='best')
plt.xlabel('t')
plt.grid()
plt.show()

通过调用以上语句,官网分别画出了结果的图像,如下所示,
sol图像
官网的介绍到此为止了,我不知道有没有小伙伴看完和我一样很懵,定义微分方程为什么是这样的,还有没有别的可能,关于这个odeint有没有别的需要注意的点,这一个例子感觉说的不那么明白,比如我有以下疑问:

  1. 首先,自定义的微分方程的函数,如果我们需要求解的是一阶的怎么办?
  2. 如果是二阶的微分方程,theta, omega = yomega ,theta,= y 和下面的返回值列表有没有一一对应关系
  3. 如果关系,应该如何组织二者的顺序。
  4. 对于二阶微分方程的初值那个列表,第一个数代表得是原方程的初值吗?那第二个是不是应该代表一阶微分方程的初值,为了保证结果的正确,到底应该如何安排顺序?

这是我看完的几个疑问,如果你愿意跟我一起,通过下面的代码进行测试,我相信,你会对这个odeint有更深一点的理解。

测试

1先定义好数学问题

就拿我们前面举过的例子来说吧,对于下面的函数【1】,
y = 4 x 3 + 100 y=4x^3+100 y=4x3+100
我们对它求导得到表达式【2】:
y ′ = 12 x 2 y'=12x^2 y=12x2

这是一个一阶微分方程,表达式【1】是它的一个解(别忘记常数)

我们在此求导得到表达式【3】,
y ′ ′ = 24 x y'' = 24x y=24x

这是一个二阶微分方程,表达式【1】是它的一个解(同样别忘记常数)

先求一阶的结果

如果我们想求表达式【2】y’=12x^2 在初值为100(本文指的是x=0时)的情况下,这个微分方程的解是多少,我们编写如下函数,

initial = 100				# 定义原方程初始值
def f1(y,x):
    return 12*x**2
x = np.linspace(0,10,100) 	#定义自变量
result1 = odeint(f1,initial,x) #调用求解
plt.plot(x,result1)				#求解值
plt.plot(x,4*x**3+initial,'--k') #真实值

这里我们会发现我们需要定义的微分方程函数,返回的都是某个变量的一阶导数,所以说这个odeint在调用时填入的参数fun句柄,应该是以一阶微分形式给出的,所以以后定义这种函数我们应该都化为一阶然后写好自定义函数,再传入odeint里面。
本文初值为100,指的是x=0时,y=100。请思考如果是x=1时,y=104该如何表示!

在这里插入图片描述

上图结果说明一阶的求解结果完全正确。

二阶微分方程的测试

如果我们想求解表达式【3】y’’ = 24x 在初始值100 和 一阶初值 0 的情况下的解,
此时应先化为一阶方程组,令

ω = y ′ \omega = y' ω=y y ′ ′ = ω ′ = 24 x y'' = \omega' =24x y=ω=24x

确认如下结果方程组:
y ′ = ω y' = \omega y=ω ω ′ = 24 x \omega' =24x ω=24x
如此保证方程左边是一阶组,右边是不含导数项。

我们应该编写如下函数,

initial = 100	#原初值
derivative1 = 0 #一阶初值
def f2(y,x):
    y1,w = y
    return np.array([w,24*x]) #返回值列阵 先一阶 再 二阶 由低到高
x = np.linspace(0,10,100)		#定义自变量
result2 = odeint(f2,(initial,derivative1),x)  #初值对应 先原方程 再 一阶 由低到高
plt.plot(x,result2)
plt.plot(x,4*x**3+initial,'--k')

在这里插入图片描述
可以发现原方程的结果是吻合的。

如果我们调换一下初值的顺序(initial,derivative1)(derivative1,initial),即先一阶导再二阶导,会发生什么呢?结果还正确嘛?

initial = 100	
derivative1 = 0 
def f2(y,x):
    y1,w = y
    return np.array([w,24*x]) 
x = np.linspace(0,10,100)
#result2 = odeint(f2,(initial,derivative1),x)  #初值对应 先原方程 再 一阶 由低到高 【注释掉】
result2 = odeint(f2,(derivative1,initial),x)  #初值对应 先一阶 再 原方程  会出现错误【如下图】

plt.plot(x,result2)
plt.plot(x,4*x**3+initial,'--k')

在这里插入图片描述

可以看出来,如果改变初值顺序结果是错误的。那么这个顺序应该跟谁对应呢?

那尝试如果改变初值顺序改变的情况下,把自定义函数的返回值也调换,会不会得到正确结果呢?
我们看下面的代码:

def f2(y,x):
    y1,w = y
    # return np.array([w,24*x]) #返回值列阵 先一阶 再 二阶 由低到高 【注释掉】
    return np.array(24*x,w) #返回值列阵 先 二阶  再 一阶 由高到低
x = np.linspace(0,10,100)

result2 = odeint(f2,(derivative1,initial),x)  #初值对应 先一阶 再 原方程  会出现错误

plt.plot(x,result2)
plt.plot(x,4*x**3+initial,'--k')

结果会报错:

RuntimeError: The size of the array returned by func (1) does not match the size of y0 (2).

这是因为在自定义函数中y1,w = y应该和返回值对应,如此应该调换为w,y1 = y

def f2(y,x):
    # y1,w = y #【注释掉】
    w,y1 = y
    # return np.array([w,24*x]) #返回值列阵 先一阶 再 二阶 由低到高 【注释掉】
    return np.array([24*x,w]) #返回值列阵 先 二阶  再 一阶 由高到低
x = np.linspace(0,10,100)

result2 = odeint(f2,(derivative1,initial),x)  #初值对应 先一阶 再 原方程  会出现错误的结果

plt.plot(x,result2)
plt.plot(x,4*x**3+initial,'--k')

在这里插入图片描述

这样我们得到了正确的结果

总结

这么麻烦,我们其实只说明了一个很简单的问题,初始值、返回值、中间变量这 三个位置的顺序必须完全相同, 正序或者逆序 都可以,但三个必须保持一致,才能出现正确的结果。

这个顺序我的理解是 原方程-一阶导-二阶导 这样的顺序。 初始值对应的 以及 返回值和中间变量替换对应的 应该是同样的次序, 比如 如果返回值列表是[一阶导 二阶导] 那么初始值对应的应该为[原方程初值 一阶导初值],变量替换对应的元组也应该同一阶导和二阶导对应。

这是关于这个函数的第一篇,我也是刚接触这个东西第二天,不确定以后会不会继续写,希望不会误人子弟吧。有些地方表述可能不清楚,以后会修改。欢迎批评指正,另外不要杠我,你杠就是你对。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

用python的scipy中的odeint来解常微分方程中的一些细节问题(适用于小白) 的相关文章

  • python:查找围绕某个 GPS 位置的圆的 GPS 坐标的优雅方法

    我有一组以十进制表示的 GPS 坐标 并且我正在寻找一种方法来查找每个位置周围半径可变的圆中的坐标 这是一个例子 http green and energy com downloads test circle html我需要什么 这是一个圆
  • 中断 Select 以添加另一个要在 Python 中监视的套接字

    我正在 Windows XP 应用程序中使用 TCP 实现点对点 IPC 我正在使用select and socketPython 2 6 6 中的模块 我有三个 TCP 线程 一个读取线程通常会阻塞select 一个通常等待事件的写入线程
  • 元组有什么用?

    我现在正在学习 Python 课程 我们刚刚介绍了元组作为数据类型之一 我阅读了它的维基百科页面 但是 我无法弄清楚这种数据类型在实践中会有什么用处 我可以提供一些需要一组不可变数字的示例吗 也许是在 Python 中 这与列表有何不同 每
  • 在 django ORM 中查询时如何将 char 转换为整数?

    最近开始使用 Django ORM 我想执行这个查询 select student id from students where student id like 97318 order by CAST student id as UNSIG
  • 处理 Python 行为测试框架中的异常

    我一直在考虑从鼻子转向行为测试 摩卡 柴等已经宠坏了我 到目前为止一切都很好 但除了以下之外 我似乎无法找出任何测试异常的方法 then It throws a KeyError exception def step impl contex
  • Python getstatusoutput 替换不返回完整输出

    我发现了这个很棒的替代品getstatusoutput Python 2 中的函数在 Unix 和 Windows 上同样有效 不过我觉得这个方法有问题output被构建 它只返回输出的最后一行 但我不明白为什么 任何帮助都是极好的 def
  • 使用 Python 从文本中删除非英语单词

    我正在 python 上进行数据清理练习 我正在清理的文本包含我想删除的意大利语单词 我一直在网上搜索是否可以使用像 nltk 这样的工具包在 Python 上执行此操作 例如给出一些文本 Io andiamo to the beach w
  • Python zmq SUB 套接字未接收 MQL5 Zmq PUB 套接字

    我正在尝试在 MQL5 中设置一个 PUB 套接字 并在 Python 中设置一个 SUB 套接字来接收消息 我在 MQL5 中有这个 include
  • 将 python2.7 与 Emacs 24.3 和 python-mode.el 一起使用

    我是 Emacs 新手 我正在尝试设置我的 python 环境 到目前为止 我已经了解到在 python 缓冲区中使用 python mode el C c C c将当前缓冲区的内容加载到交互式 python shell 中 显然使用了什么
  • 使用 xlrd 打开 BytesIO (xlsx)

    我正在使用 Django 需要读取上传的 xlsx 文件的工作表和单元格 使用 xlrd 应该可以 但因为文件必须保留在内存中并且可能不会保存到我不知道如何继续的位置 本例中的起点是一个带有上传输入和提交按钮的网页 提交后 文件被捕获req
  • Docker 中的 Python 日志记录

    我正在 Ubuntu Web 服务器上的 Docker 容器中测试运行 python 脚本 我正在尝试查找由 Python Logger 模块生成的日志文件 下面是我的Python脚本 import time import logging
  • 如何通过 TLS 1.2 运行 django runserver

    我正在本地 Mac OS X 机器上测试 Stripe 订单 我正在实现这段代码 stripe api key settings STRIPE SECRET order stripe Order create currency usd em
  • javascript 是否有等效的 __repr__ ?

    我最接近Python的东西repr这是 function User name password this name name this password password User prototype toString function r
  • pip 列出活动 virtualenv 中的全局包

    将 pip 从 1 4 x 升级到 1 5 后pip freeze输出我的全局安装 系统 软件包的列表 而不是我的 virtualenv 中安装的软件包的列表 我尝试再次降级到 1 4 但这并不能解决我的问题 这有点类似于这个问题 http
  • Python3 在 DirectX 游戏中移动鼠标

    我正在尝试构建一个在 DirectX 游戏中执行一些操作的脚本 除了移动鼠标之外 我一切都正常 是否有任何可用的模块可以移动鼠标 适用于 Windows python 3 Thanks I used pynput https pypi or
  • 不同编程语言中的浮点数学

    我知道浮点数学充其量可能是丑陋的 但我想知道是否有人可以解释以下怪癖 在大多数编程语言中 我测试了 0 4 到 0 2 的加法会产生轻微的错误 而 0 4 0 1 0 1 则不会产生错误 两者计算不平等的原因是什么 在各自的编程语言中可以采
  • Pandas 将多行列数据帧转换为单行多列数据帧

    我的数据框如下 code df Car measurements Before After amb temp 30 268212 26 627491 engine temp 41 812730 39 254255 engine eff 15
  • 根据列 value_counts 过滤数据框(pandas)

    我是第一次尝试熊猫 我有一个包含两列的数据框 user id and string 每个 user id 可能有多个字符串 因此会多次出现在数据帧中 我想从中导出另一个数据框 一个只有那些user ids列出至少有 2 个或更多string
  • 使用 z = f(x, y) 形式的 B 样条方法来拟合 z = f(x)

    作为一个潜在的解决方案这个问题 https stackoverflow com questions 76476327 how to avoid creating many binary switching variables in gekk
  • Kivy - 单击按钮时编辑标签

    我希望 Button1 在单击时编辑标签 etykietka 但我不知道如何操作 你有什么想法吗 class Zastepstwa App def build self lista WebOps getList layout BoxLayo

随机推荐

  • python断点下载文件

    使用pytohn编码实现文件的断点下载 span class token keyword import span os span class token keyword import span json span class token k
  • 异常检测(1)—初识异常检测

    1 概念 异常一般是指与标准值 xff08 预期值 xff09 有偏离的样本点 xff0c 也就是跟绝大部分数据 长的不一样 异常往往是 有价值 的事情 xff0c 我们对异常的成因感兴趣 2 类别 有监督 xff1a 数据集有标签无监督
  • 【git】在GitHub上下载历史版本

    GitHub上的项目很多都是从简单到复杂 xff0c 一点点迭代的 当我们需要看懂别人的代码时 xff0c 按照别人commit的历史版本一步一步跟踪 xff0c 或许是个好办法 这时候我们就要用到下载历史版本功能了 1 git clone
  • 实时操作系统UCOS学习笔记1----UCOSII简介

    前面我们所有的实验都是跑的裸机程序 xff08 裸奔 xff09 xff0c 从本章开始 xff0c 我们开始介绍UCOSII xff08 实时多任务操作系统内核 xff09 UCOSII简介 UCOSII的前身是UCOS xff0c 最早
  • 欢聚时代YY/测试实习面试

    去到YY大楼 xff0c 虽然在番禺但是附近很多楼在施工中了 大楼就在万达后面 前台登记 xff0c 小姐姐会让你出示邀请邮件 xff0c 然后直接上去就行了 达到楼层 xff0c 二维码签到 然后找地方坐一下等待面试 一轮是技术面 xff
  • 基于卡尔曼滤波的气压计高度解算

    ax ay az为归一化的加速度数据 1代表重力加速度 gx gy gz 为加速度数据 单位rad s altitude为气压计测量得到的海拔数据 欧拉角 float pitch roll yaw 世界坐标系下机体加速度 float ax
  • Kali安装Xfce4

    Kali安装Xface4 一 配置kali源并更新二 解决报错1 签名无效2 依赖报错 三 安装xfce4 一 配置kali源并更新 此处使用的是gedit编辑器 xff0c gedit etc apt sources list xff0c
  • 串口转WIFI的工作方式理解

    串口无线 AP xff08 COM AP xff09 串口无线 STA xff08 COM STA xff09 和 串口无线 AP 43 STA xff08 COM AP 43 STA xff09 3 个模式 串口WIFI模块是基于Uart
  • 典型环节的频率特性(建议收藏)

    自控笔记 5 3典型环节频率特性 控制系统种类繁多 xff0c 传递函数复杂 xff0c 但任何形式的传递函数都是由有限的典型环节组成 因此 xff0c 掌握典型环节的频率特性是使用频域法分析系统的基础 如下表所示 xff0c 构成系统的最
  • 【WINAPI】CreateSemaphore_信号量

    WINAPI CreateSemaphore 信号量 1 注册信号量函数1 1 参数1 2 返回值 2 释放信号量函数2 1 参数2 2 返回值 3 WaitForSingleObject3 2 参数3 3 返回值 4 例子4 1 运行结果
  • MAVROS二次开发(一)MAVROS的安装

    MAVROS二次开发 一 MAVROS的安装 1 参考网址 https dev px4 io v1 10 en ros mavros installation html https github com mavlink mavros tre
  • MAVROS二次开发(二)(三)添加自定义消息

    MAVROS二次开发 二 MAVROS消息添加 1 自定义rostopic消息 路径 xff1a catkin ws src mavros mavros msgs msg 自定义消息文件名称 xff1a CrawlControlStatus
  • MAVROS二次开发(四)添加消息处理插件

    MAVROS二次开发 四 添加消息处理插件 mavros插件所在路径 xff1a catkin ws src mavros mavros src plugins 1 自定义消息处理插件的编写 参考代码 xff1a catkin ws src
  • MAVROS二次开发(五)进行测试

    MAVROS二次开发 五 进行测试 1 测试环境 PX4 xff1a v1 10 1 xff08 含自定义mavlink消息收发 xff09 ROS xff1a KineticUbuntu xff1a 16 04LTSQGC xff1a S
  • ROS2+PX4开发环境配置

    一 ROS2安装 Ubuntu18 04的ros2版本 xff1a Eloquent 参考网址 xff1a https docs ros org en eloquent Installation Linux Install Debians
  • Windows10下Airsim+PX4(WSL2)+MAVROS仿真环境搭建

    一 Windows10下WSL2安装 1 1 WSL2的安装与配置 首先在Windows10下启用WSL xff0c 以管理员身份打开 PowerShell 工具并运行以下命令 dism span class token punctuati
  • Windows10通过vcpkg快速配置PCL库

    1 安装C 43 43 包管理工具vcpkg https github com microsoft vcpkg span class token function git span clone https github com micros
  • 微软Chromium版Edge浏览器正式稳定版

    微软Chromium版Edge浏览器正式稳定版 近期微软Chromium版Edge浏览器正式稳定版下载已经泄露 xff0c 版本77 0 235 9 此版本没有div什么的那些 xff0c 和之前的图标一样 当安装新Edge稳定版之后 xf
  • C++疑难问题

    acwing中的算法疑惑 1 为什么确定范围 要 43 10 在使用归并排序和快速排序等方法时有效率问题 xff0c 确定范围在1e6 但是选择的是1e 43 10 2 C 43 43 除二乘2简单方法以及算法效率问题 算法效率速度排行 x
  • 用python的scipy中的odeint来解常微分方程中的一些细节问题(适用于小白)

    用python的scipy中的odeint来解常微分方程中的一些细节问题 xff08 适用于小白 xff09 写在前面 最近有些需要解决常微分方程的问题 xff0c 网上查了很多教程都不是很明晰 xff0c 便自己研究了一段时间 xff0c