我目前有一个具有时间相关常数的颂歌系统。 E.g。
def fun(u, t, a, b, c):
x = u[0]
y = u[1]
z = u[2]
dx_dt = a * x + y * z
dy_dt = b * (y-z)
dz_dt = -x*y+c*y-z
return [dx_dt, dy_dt, dz_dt]
常数是" a"," b"和" c"。我目前有一个" a" s用于每个时间步骤,我希望在每个时间步骤插入,当使用scipy ode求解器时...这可能吗?
谢谢!
答案 0 :(得分:8)
是的,这是可能的。在a
不变的情况下,我猜您调用scipy.integrate.odeint(fun, u0, t, args)
,其中fun
定义为您的问题,u0 = [x0, y0, z0]
是初始条件,t
是要为ODE求解的一系列时间点,args = (a, b, c)
是要传递给fun
的额外参数。
如果a
取决于时间,您只需重新考虑a
作为函数,例如(给定常量a0
):
def a(t):
return a0 * t
然后你必须修改fun
来计算每个时间步的衍生物,以考虑先前的变化:
def fun(u, t, a, b, c):
x = u[0]
y = u[1]
z = u[2]
dx_dt = a(t) * x + y * z # A change on this line: a -> a(t)
dy_dt = b * (y - z)
dz_dt = - x * y + c * y - z
return [dx_dt, dy_dt, dz_dt]
最后,请注意u0
,t
和args
保持不变,您可以再次致电scipy.integrate.odeint(fun, u0, t, args)
。
关于这种方法的正确性的一句话。数值积分近似的表现受到影响,我不知道如何(没有理论上的保证),但这是一个有效的简单例子:
import matplotlib.pyplot as plt
import numpy as np
import scipy as sp
import scipy.integrate
tmax = 10.0
def a(t):
if t < tmax / 2.0:
return ((tmax / 2.0) - t) / (tmax / 2.0)
else:
return 1.0
def func(x, t, a):
return - (x - a(t))
x0 = 0.8
t = np.linspace(0.0, tmax, 1000)
args = (a,)
y = sp.integrate.odeint(func, x0, t, args)
fig = plt.figure()
ax = fig.add_subplot(111)
h1, = ax.plot(t, y)
h2, = ax.plot(t, [a(s) for s in t])
ax.legend([h1, h2], ["y", "a"])
ax.set_xlabel("t")
ax.grid()
plt.show()
我希望这会对你有所帮助。
答案 1 :(得分:1)
不,这是不可能的,因为求解器将使用您无法控制的内部时间步长,并且每个时间步都使用该函数的多个评估。
如果参数是分段常数,那么您可以从跳转点到跳转点进行积分。
如果是分段线性,则可以使用插值函数。
对于其他任何事情,你必须实现自己的逻辑,从t
时间到这些参数的正确值。
注意,数值积分的近似顺序不仅受RK方法的阶数限制,而且受微分方程(部分)的微分阶数的限制。