Python 2.7 具有多个参数的ODEINT(时间相关)

Python 2.7 具有多个参数的ODEINT(时间相关),python-2.7,scipy,odeint,Python 2.7,Scipy,Odeint,我试图用ODEINT解一个一阶ODE。下面是代码。我希望在3个时间点得到3个y值。我正在努力解决的问题是通过mt和nt的第n个值来计算dydt的能力。我认为ODEINT会传递所有3个值mt和nt,而只传递第0、第1或第2个值,具体取决于迭代。因此,我得到以下错误: RuntimeError:func(4)返回的数组大小与y0(1)的大小不匹配 有趣的是,如果我将初始条件(也应该是)替换为单个值:a0=[2]*4,代码可以工作,但给出了一个4X4矩阵作为解决方案,这似乎是不正确的 mt = np.

我试图用ODEINT解一个一阶ODE。下面是代码。我希望在3个时间点得到3个y值。我正在努力解决的问题是通过mtnt的第n个值来计算dydt的能力。我认为ODEINT会传递所有3个值mtnt,而只传递第0、第1或第2个值,具体取决于迭代。因此,我得到以下错误:

RuntimeError:func(4)返回的数组大小与y0(1)的大小不匹配

有趣的是,如果我将初始条件(也应该是)替换为单个值:a0=[2]*4,代码可以工作,但给出了一个4X4矩阵作为解决方案,这似乎是不正确的

mt = np.array([3,7,4,2]) # Array of constants
nt = np.array([5,1,9,3]) # Array of constants
c1,c2,c3 = [-0.3,1.4,-0.5] # co-efficients
para = [mt,nt] # Packing parameters

#Test ODE function
def test (y,t,extra):
    m,n = extra
    dydt = c1*c2*m - c1*y - c3*n
    return dydt

a0= [2]  # Initial Condition
tspan = range(len(mt)) # Define tspan

#Solving the ODE
yt= odeint(test, a0,tspan,args=(para,)) 
#Plotting the ODE
plt.plot(tspan,yt,'g')
plt.title('Multiple Parameters Test')
plt.xlabel('Time')
plt.ylabel('Magnitude')
一阶微分方程为:

dy/dt=c1*(c2*mt-y(t))-c3*nt

这个方程代表了小鼠内分泌系统的一部分,我正试图对其进行建模。该系统类似于双罐系统,其中第一罐接收特定激素[以未知速率],但我们的传感器将在特定时间间隔(1秒)检测该水平
(mt)
。然后,该罐进入第二个罐,在第二个罐中,该激素的水平由另一个传感器检测。我使用单独的变量来标记液位,因为检测液位的传感器彼此独立,并且没有相互校准。”c2'可被视为显示两个水平之间相关性的系数。此外,该激素从罐1转移到罐2是由扩散驱动的。这种激素被生化过程进一步消耗(类似于第二个储罐的排放阀)。目前尚不清楚哪些参数会影响消费;但是,另一个传感器可以检测特定时间间隔(本例中也是1秒)消耗的激素量

因此,
mt
nt
是特定时间点激素的浓度/水平。虽然代码中只有4个元素,但在我的研究中,这些数组要长得多。所有传感器以1秒的间隔报告浓度-因此
tspan
由1秒间隔的时间点组成


目的是通过数学方法确定第二个储罐(
y
)中该激素的浓度,然后根据实验数据优化这些系数的值。我能够将这些数组
mt
nt
传递给定义的ODE,并在MATLAB中使用ODE45进行求解,没有问题。我在尝试用Python复制代码时遇到了这个运行时错误。

正如我在一篇评论中提到的,如果你想用一个常微分方程对这个系统建模,你必须假设样本时间之间的
m
n
的值。一种可能的模型是使用线性插值。下面是一个脚本,用于基于示例
mt
nt
创建函数
mfunc(t)

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

mt = np.array([3,7,4,2])  # Array of constants
nt = np.array([5,1,9,3])  # Array of constants

c1, c2, c3 = [-0.3, 1.4, -0.5] # co-efficients

# Create linear interpolators for m(t) and n(t).
sample_times = np.arange(len(mt))
mfunc = interp1d(sample_times, mt, bounds_error=False, fill_value="extrapolate")
nfunc = interp1d(sample_times, nt, bounds_error=False, fill_value="extrapolate")

# Test ODE function
def test (y, t):
    dydt = c1*c2*mfunc(t) - c1*y - c3*nfunc(t)
    return dydt

a0 = [2]  # Initial Condition
tspan = np.linspace(0, sample_times.max(), 8*len(sample_times)+1)
#tspan = sample_times

# Solving the ODE
yt = odeint(test, a0, tspan)

# Plotting the ODE
plt.plot(tspan, yt, 'g')
plt.title('Multiple Parameters Test')
plt.xlabel('Time')
plt.ylabel('Magnitude')
plt.show()
以下是脚本创建的绘图:


请注意,我将
tspan
设置为一组更密集的点,而不是仅在
sample_时间生成解决方案(即在时间0、1、2和3)。这显示了采样时间之间模型的行为。

如果您遵循变量的定义和传递方式,您将看到
test()
中的
m
变为
mt
mt
是长度为4的numpy数组,因此
c1*c2*m
也是长度为4的numpy数组(与
c3*n
一样)。那么
dydt
是一个长度为4的数组。实际上,您正在从
test()
返回一个长度为4的数组。如何更正此问题,使“test()”只获取mt和nt的一个值(第n次迭代的第n个值),并只返回一个值,而不是长度为4的数组?您所说的“第n次迭代”是什么意思?odeint将对
tspan
中的4个点调用函数
test
4次,对吗?我认为ODE对
test
的每次调用都将被称为一次迭代-否?您能否澄清(在问题中)您试图解决的问题?我的解释是你有一个一阶微分方程,但是函数只有在离散时间值t=0,1,2,3时才知道。如果是这种情况,您必须决定如何为任意
t
定义
m(t)
n(t)
。如果你不能做到这一点,那么你就没有一个定义良好的微分方程。如果我的理解不正确,请通过在问题中更详细地解释来澄清这道数学题。太好了!谢谢你,@WarrenWeckesser!