我正在尝试使用dopri5
中的scipy.integrate.ode
积分器来解决一个简单示例。正如文档所述
这是由于Dormand& amp; amp; amp; amp; amp; amp;和/或王子(具有步长控制和密集输出)。
这应该有效。所以这是我的例子:
import numpy as np
from scipy.integrate import ode
import matplotlib.pyplot as plt
def MassSpring_with_force(t, state):
""" Simple 1DOF dynamics model: m ddx(t) + k x(t) = f(t)"""
# unpack the state vector
x = state[0]
xd = state[1]
# these are our constants
k = 2.5 # Newtons per metre
m = 1.5 # Kilograms
# force
f = force(t)
# compute acceleration xdd
xdd = ( ( -k*x + f) / m )
# return the two state derivatives
return [xd, xdd]
def force(t):
""" Excitation force """
f0 = 1 # force amplitude [N]
freq = 20 # frequency[Hz]
omega = 2 * np.pi *freq # angular frequency [rad/s]
return f0 * np.sin(omega*t)
# Time range
t_start = 0
t_final = 1
# Main program
state_ode_f = ode(MassSpring_with_force)
state_ode_f.set_integrator('dopri5', rtol=1e-6, nsteps=500,
first_step=1e-6, max_step=1e-3)
state2 = [0.0, 0.0] # initial conditions
state_ode_f.set_initial_value(state2, 0)
sol = np.array([[t_start, state2[0], state2[1]]], dtype=float)
print("Time\t\t Timestep\t dx\t\t ddx\t\t state_ode_f.successful()")
while state_ode_f.t < (t_final):
state_ode_f.integrate(t_final, step=True)
sol = np.append(sol, [[state_ode_f.t, state_ode_f.y[0], state_ode_f.y[1]]], axis=0)
print("{0:0.8f}\t {1:0.4e} \t{2:10.3e}\t {3:0.3e}\t {4}".format(
state_ode_f.t, sol[-1, 0]- sol[-2, 0], state_ode_f.y[0], state_ode_f.y[1], state_ode_f.successful()))
我得到的结果是:
Time Timestep dx ddx state_ode_f.successful()
0.49763822 4.9764e-01 2.475e-03 -8.258e-04 False
0.99863822 5.0100e-01 3.955e-03 -3.754e-03 False
1.00000000 1.3618e-03 3.950e-03 -3.840e-03 False
发出警告:
c:\ python34 \ lib \ site-packages \ scipy \ integrate_ode.py:1018:UserWarning:dopri5:需要更大的nmax self.messages.get(idid,'Unexpected idid =%s'%idid))
结果是incorect。如果我使用vode
积分器运行相同的代码,我会得到预期的结果。
修改
此处描述了类似的问题: Using adaptive step sizes with scipy.integrate.ode
建议的解决方案建议设置nsteps=1
,它正确地解决了ODE并使用步长控制。但是,集成商会将state_ode_f.successful()
作为False
返回。
答案 0 :(得分:0)
不,没有错。您告诉集成商执行t_final
的集成步骤,然后执行该步骤。不报告积分器的内部步骤。
明智的做法是将所需的采样点作为算法的输入,例如设置为dt=0.1
并使用
state_ode_f.integrate( min(state_ode_f.t+dt, t_final) )
step
中没有单一dopri5
方法,只有vode
定义了它,请参阅源代码https://github.com/scipy/scipy/blob/v0.14.0/scipy/integrate/_ode.py#L376,这可以解释观察到的差异。< / p>
正如您在Using adaptive step sizes with scipy.integrate.ode中发现的那样,可以通过设置迭代范围nsteps=1
来强制执行单步行为。每次都会产生警告,因此必须禁止这些特定警告才能看到合理的结果。
对于与时间相关的力,不应使用参数(积分间隔的常数)。在评估MassSpring_with_force
内使用f=force(t)
。可能您可以将force
的函数句柄作为参数传递。