使用dopri5绘制Python

使用dopri5绘制Python,python,plot,ode,Python,Plot,Ode,我的目标是绘制以下一组耦合ODE: odeint方法给了我一些问题(比如一些x_i的负值,这在分析上是不会发生的),所以我决定使用四阶Runge-Kutta解算器。我在下面的示例中使用了dopri5方法(): 将scipy作为sp导入 导入pylab作为plt 将numpy作为np导入 导入scipy.integrate作为spi #常数 c13=6.2 c14=1.0 c21=7.3 c32=2.4 c34=12.7 c42=5.7 c43=5.0 e12=1.5 e23=2.5 e24=2

我的目标是绘制以下一组耦合ODE:

odeint方法给了我一些问题(比如一些x_i的负值,这在分析上是不会发生的),所以我决定使用四阶Runge-Kutta解算器。我在下面的示例中使用了dopri5方法():

将scipy作为sp导入
导入pylab作为plt
将numpy作为np导入
导入scipy.integrate作为spi
#常数
c13=6.2
c14=1.0
c21=7.3
c32=2.4
c34=12.7
c42=5.7
c43=5.0
e12=1.5
e23=2.5
e24=2.0
e31=3.0
e41=4.8
#时间
t_端=700
t_start=0
t_阶跃=1
t_间隔=sp.arange(t_开始、t_结束、t_步骤)
#初始条件
ic=[0.2,0.3,0.3,0.5]
def型号(t、ic):
等式=np.零((4))
等式[0]=(ic[0]*(1-ic[0]*ic[0]-ic[1]*ic[1]-ic[2]*ic[2]-ic[3]*ic[3])-c21*((ic[1]*ic[1]*ic[0])+e31*((ic[2]*ic[2])*ic[0])+e41*((ic[3]*ic[3])*ic[0]))
等式[1]=(ic[1]*(1-ic[0]*ic[0]-ic[1]*ic[1]-ic[2]*ic[2]-ic[3]*ic[3])+e12*((ic[0]*ic[0]*ic[1])-c32*((ic[2]*ic[2])-c42*((ic[3]*ic[3])*ic[1]))
等式[2]=(ic[2]*(1-ic[0]*ic[0]-ic[1]*ic[1]-ic[2]*ic[2]-ic[3]*ic[3])-c13*((ic[0]*ic[0]*ic[2])+e23*((ic[1]*ic[1]*ic[2])-c43*((ic[3]*ic[3])*ic[2]))
等式[3]=(ic[3]*(1-ic[0]*ic[0]-ic[1]*ic[1]-ic[2]*ic[2]-ic[3]*ic[3])-c14*((ic[0]*ic[0]*ic[3])+e24*((ic[1]*ic[1])-c34*((ic[2]*ic[2])*ic[3]))
返回等式
ode=spi.ode(型号)
ode.set_积分器('dopri5')
ode.设置初始值(ic、t\U开始)
ts=[]
ys=[]
而ode.successful()和ode.t
这将生成以下绘图:

然而,我的图有一些奇怪的地方——x1值似乎在1以上随机增加。因为(1,0,0,0)是动力系统的一个固定点,所以它在1以上出现尖峰对我来说没有太大意义(如果尖峰显示出某种重复模式,可能是有原因的,但它们在图中看起来是随机的,所以我想知道这是否更多地与数值积分有关,而不是与实际的动力学有关)。改变参数也会改变尖峰(我尝试过的一些参数值仍然有尖峰,但实际上很少)。因此,我有两个问题:

1) 是什么导致这些尖峰出现的?我最初的想法是“t_步”很大,所以我试着玩弄它(这就引出了我的第二个问题)

2) 我尝试将步长从1更改为0.1。然而,它产生了这个图,它实际上看起来与步长为1时有很大的不同(我认为较低的步长会产生更精确的图?)在这个图中,每个x_I在1附近花费的时间似乎比步长为1而不是0.1时长,尖峰的高度都是相等的——考虑到曲线有一些实质性的差异,我怎么知道哪个曲线更准确呢


我正在研究的问题的真正关键是查找x3和x4之间的相互作用,但我想确保模拟设置正确,以便我能够获得有关x3和x4的准确结果

通过Gronwall引理,“尼斯”常微分方程的误差传播是以Lipschitz常数
L
为因子的指数控制的。这意味着在时间
t
发生的任何局部错误贡献(可能)被时间
t
exp(L(t-t))
因子放大

慷慨大方的人可以为您的系统使用
L=10
。在
10
的时间间隔内,这会使误差放大
exp(100)=2.688e+43
,或使数值与初始值和精确解完全解耦

因此,更令人惊讶的是,在
t=80
之前,这两种解决方案的相似性被保留了多远


理论注释,尖峰:没有任何东西限制变量停留在区间[0,1]内或具有具有相同效果的守恒量。最好使用Ljapunov函数,如
V(x)=sum(x*x)
,然后给出边界,将解限制在两个球体之间


不动点都是双曲型的,雅可比矩阵有秩亏且无迹,不包括稳定不动点。尖峰只是这些双曲点的稳定和不稳定流形/轴方向的结果

通过Gronwall引理,“尼斯”常微分方程的误差传播是以Lipschitz常数
L
为因子的指数控制的。这意味着在时间
t
发生的任何局部错误贡献(可能)被时间
t
exp(L(t-t))
因子放大

慷慨大方的人可以为您的系统使用
L=10
。在
10
的时间间隔内,这会使误差放大
exp(100)=2.688e+43
,或使数值与初始值和精确解完全解耦

因此,更令人惊讶的是,在
t=80
之前,这两种解决方案的相似性被保留了多远


理论注释,尖峰:没有任何东西限制变量停留在区间[0,1]内或具有具有相同效果的守恒量。最好使用Ljapunov函数,如
V(x)=sum(x*x)
,然后给出边界,将解限制在两个球体之间

不动点都是双曲型的,雅可比矩阵有秩亏且无迹,不包括稳定不动点。尖峰只是稳定和不稳定流形/轴方向的结果
import scipy as sp
import pylab as plt
import numpy as np
import scipy.integrate as spi

#Constants
c13 = 6.2
c14 = 1.0
c21 = 7.3
c32 = 2.4
c34 = 12.7
c42 = 5.7
c43 = 5.0

e12 = 1.5
e23 = 2.5
e24 = 2.0
e31 = 3.0
e41 = 4.8

#Time
t_end = 700
t_start = 0
t_step = 1
t_interval = sp.arange(t_start, t_end, t_step)

#Initial Condition
ic = [0.2,0.3,0.3,0.5]

def model(t,ic):
    Eqs= np.zeros((4))
    Eqs[0] = (ic[0]*(1-ic[0]*ic[0]-ic[1]*ic[1]-ic[2]*ic[2]-ic[3]*ic[3])-c21*((ic[1]*ic[1])*ic[0])+e31*((ic[2]*ic[2])*ic[0])+e41*((ic[3]*ic[3])*ic[0]))
    Eqs[1] = (ic[1]*(1-ic[0]*ic[0]-ic[1]*ic[1]-ic[2]*ic[2]-ic[3]*ic[3])+e12*((ic[0]*ic[0])*ic[1])-c32*((ic[2]*ic[2])*ic[1])-c42*((ic[3]*ic[3])*ic[1]))
    Eqs[2] = (ic[2]*(1-ic[0]*ic[0]-ic[1]*ic[1]-ic[2]*ic[2]-ic[3]*ic[3])-c13*((ic[0]*ic[0])*ic[2])+e23*((ic[1]*ic[1])*ic[2])-c43*((ic[3]*ic[3])*ic[2]))
    Eqs[3] = (ic[3]*(1-ic[0]*ic[0]-ic[1]*ic[1]-ic[2]*ic[2]-ic[3]*ic[3])-c14*((ic[0]*ic[0])*ic[3])+e24*((ic[1]*ic[1])*ic[3])-c34*((ic[2]*ic[2])*ic[3]))
    return Eqs

ode =  spi.ode(model)

ode.set_integrator('dopri5')
ode.set_initial_value(ic,t_start)
ts = []
ys = []

while ode.successful() and ode.t < t_end:
    ode.integrate(ode.t + t_step)
    ts.append(ode.t)
    ys.append(ode.y)

t = np.vstack(ts)
x1,x2,x3,x4 = np.vstack(ys).T

plt.subplot(1, 1, 1)
plt.plot(t, x1, 'r', label = 'x1')
plt.plot(t, x2, 'b', label = 'x2')
plt.plot(t, x3, 'g', label = 'x3')
plt.plot(t, x4, 'purple', label = 'x4')
plt.xlim([0,t_end])
plt.legend()
plt.ylim([-0.2,1.3])

plt.show()