odeint与interp1d的交互中可能存在错误?

4 投票
1 回答
659 浏览
提问于 2025-04-16 15:38

我刚开始学习Python和SciPy,之前是用MATLAB的。我在测试SciPy库里的odeint函数时,发现了一个可能的bug。看看下面这段代码:

from scipy import *
from scipy.integrate import odeint
from scipy.interpolate import interp1d
from pylab import *

# ODE system with forcing function u(t)
def sis(x,t,u):
    return [x[1], u(t)]

# Solution time span
t = linspace(0, 10, 1e3)

# Profile for forcing function u(t)
acel = lambda t: 3*(t<2)-3*(t>8)

# Interpolator for acelerator
acel_interp = interp1d(t, acel(t), bounds_error=False, fill_value=0)    

# ODE integration with u(t) = acel, a lambda function
x_1 = odeint(sis, [0,0], t, args=(acel,) )            # Correct result
# ODE integration with u(t) = acel_interp, an interpolator
x_2 = odeint(sis, [0,0], t, args=(acel_interp,) )     # Incorrect result

我做了一个图,展示了这两个结果的差异,点这里查看.

你觉得这个结果之间的差异有什么问题吗?对我来说,这种差异似乎没有理由。我使用的是NumPy 1.5.0版本和SciPy 0.8.0版本,Python版本是2.6.6。

1 个回答

3

这不是一个错误。问题在于你把 bound_error 设置成了 False,并且用零填充了那些值。如果你在原来的代码中把 bound_error 设置为 True,你会发现你超出了插值的范围,因此在积分时填入了零(这样得到的值就和你在那些超出范围的点上用 lambda 计算的值不同了)。

试试下面的代码,你会发现一切正常。基本上,我只是把 t 的范围扩展到了足够大的值,以覆盖你在插值时使用的范围。

from scipy import *
from scipy.integrate import odeint
from scipy.interpolate import interp1d
from pylab import *

# ODE system with forcing function u(t)
def sis(x,t,u):
    return [x[1], u(t)]

# Solution time span
t = linspace(0, 10, 1e3)
t_interp = linspace(0,20,2e3)

# Profile for forcing function u(t)
acel = lambda t: 3*(t<2)-3*(t>8)

# Interpolator for acelerator
acel_interp = interp1d(t_interp, acel(t_interp))    

# ODE integration with u(t) = acel, a lambda function
x_1 = odeint(sis, [0,0], t, args=(acel,) )            
# ODE integration with u(t) = acel_interp, an interpolator
x_2 = odeint(sis, [0,0], t, args=(acel_interp,) )     

撰写回答