解一组赋(常数不断变化!))使用scipy.integrate.odeint?

ercv8c1e  于 8个月前  发布在  其他
关注(0)|答案(4)|浏览(66)

我现在有一个时间依赖常数的颂歌系统。例如

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“的每一个时间步,我想插入在每一个时间步,当使用scipy ode求解器.这是可能的吗?
谢谢你,谢谢

z9ju0rcb

z9ju0rcb1#

是的,这是可能的。在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]

最后,请注意u0targs保持不变,您可以再次调用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()

我希望这对你有帮助。

ycggw6v2

ycggw6v22#

不,从字面意义上来说,
“我目前有一个列表的“a“的每个时间步,我想插入在每个时间步”
因为求解器具有自适应步长控制,也就是说,它将使用您无法控制的内部时间步长,并且每个时间步长使用函数的几个求值。因此,求解器时间步和数据时间步之间没有联系。
然而,在给定数据定义分段常数阶跃函数的扩展意义上,有几种方法可以得到解。
1.您可以使用此时间段的常参数ODE函数从跳跃点到跳跃点进行积分。之后,使用numpy数组操作(如concatenate)来组装完整的解决方案。
1.可以使用插值函数,如numpy.interpscipy.interpolate.interp1d。第一个给出了分段线性插值,这在这里可能不是期望的。第二个返回一个函数对象,可以配置为“零阶保持”,这是一个分段常数阶跃函数。
1.您可以实现自己的逻辑,从时间t到这些参数的正确值。这主要适用于数据有某种结构的情况,例如,如果它们具有f(int(t/h))的形式。
注意,数值积分的逼近阶不仅受RK(solve_ivp)或多步(odeint)方法的阶的限制,而且还受微分方程(部分)的可微阶的限制。如果ODE比方法的阶次更不光滑,则违反了步长控制机制的隐式假设,这可能导致非常小的步长需要大量的积分步骤。

t1qtbnec

t1qtbnec3#

我可能有点晚了,但最近出现了这个问题,因为系统需要在运动历史上进行卷积积分(波流体动力学)。
我找到了一个解决方案,它不需要知道常数a作为时间先验的函数。
这个简化的问题是一个Spring,有阻尼,以及一个卷积的Spring速度的历史在一个脉冲响应函数,结果在一个fbias项。
解决方案是用set_f_params不断更新ode积分器。这要求传递所有参数。

from scipy.integrate import *
import numpy as np
import pandas as pd
import scipy
import collections

vec = ['x','v']
iv = {'x':1,'v':0,'t':0,'fb':0}

@np.vectorize
def irf(tau,omg=10,exp=0.1):
    return np.cos(omg*tau)*np.exp(-exp*tau)

end_time = 10
dt = 0.01
t = np.arange(0,end_time,dt)
r = irf(t) #in timespace

dt = 0.1
d = collections.defaultdict(list)

def store(row):
    for k,v in row.items():
        d[k].append(v)
        
store(iv)

def physics(t,y,k,u,fbias):
    x,v = y[0],y[1]
    
    a = -k * x - v * k+fbias
    return np.array([v,a])
    
sim = ode(physics)
sim.set_integrator('dopri5',method='bdf')
sim.set_initial_value([iv[var] for var in vec])

while sim.successful() and sim.t < end_time:
    _t = sim.t + dt

    #memory term
    v = d['v']
    nl = min(len(r),len(v))
    if nl == 0:
        fbias = 0
    else:
        fbias = 0.05*np.sum(scipy.signal.convolve(r[:nl],v[-nl:],mode='full'))
    
    sim.set_f_params(10,0.1,fbias)
    
    row = {var:v for var,v in zip(vec,sim.integrate(_t))}
    row['t'] = _t
    row['fb'] = fbias
    store(row)
    print(_t,)
    
df = pd.DataFrame(d)
df.plot('t','x')
n3schb8v

n3schb8v4#

我也遇到了类似的问题。在我的例子中,参数a, b,c不是与时间的直接函数,而是由当时的x, y,z确定的。所以我必须在时间t得到x, y, z,并计算a, b, c,用于在t+dtx, y, z的积分计算。事实证明,如果我改变dt值,整个积分结果将发生巨大变化,甚至是不合理的。

相关问题