【问题标题】:Imitate ode45 function from MATLAB in Python在 Python 中模仿 MATLAB 中的 ode45 函数
【发布时间】:2018-07-03 19:58:42
【问题描述】:

我想知道如何将 MATLAB 函数 ode45 导出到 python。根据文档应该是这样的:

 MATLAB:  [t,y]=ode45(@vdp1,[0 20],[2 0]);

 Python:  import numpy as np
          def  vdp1(t,y):
              dydt= np.array([y[1], (1-y[0]**2)*y[1]-y[0]])
              return dydt
          import scipy integrate 
          l=scipy.integrate.ode(vdp1([0,20],[2,0])).set_integrator("dopri5")

结果完全不同,Matlab 返回的维度与 Python 不同。

【问题讨论】:

  • 看看我的旧答案中的this example
  • vdp1([0,20],[2,0]) 是一个数组,是将两个列表传递给您的函数的结果。 ode 需要一个函数,例如 vdp1 本身。在 MATLAB 中,您将 @vdp1,而不是 vdpt1([0 20],[2 0]) 传递给 `ode45。

标签: python matlab scipy differential-equations ode45


【解决方案1】:

函数scipy.integrate.solve_ivp默认使用RK45方法,与Matlab的ODE45函数使用方法类似,都使用具有四阶方法精度的 Dormand-Pierce 公式。

vdp1 = @(T,Y) [Y(2); (1 - Y(1)^2) * Y(2) - Y(1)];
[T,Y] = ode45 (vdp1, [0, 20], [2, 0]);
from scipy.integrate import solve_ivp

vdp1 = lambda T,Y: [Y[1], (1 - Y[0]**2) * Y[1] - Y[0]]
sol = solve_ivp (vdp1, [0, 20], [2, 0])

T = sol.t
Y = sol.y

Ordinary Differential Equations (solve_ivp)

【讨论】:

  • 请注意,Matlab 的 ode45 有一个默认为 4 的“优化”选项。也就是说,每个计算点从段中添加 3 个额外的插值点到返回向量。在 python solve_ivp 中没有这样的选项,因此具有相同的容差导致大致相同的工作 ode45 将返回更多的点,从而提供更平滑的绘图。
【解决方案2】:

正如@LutzL 提到的,您可以使用更新的 API,solve_ivp

results = solve_ivp(obj_func, t_span, y0, t_eval = time_series)

如果未指定t_eval,那么每个时间戳不会有一条记录,这主要是我假设的情况。

另一个注意事项是,对于 odeint 和其他积分器,输出数组是 [len(time), len(states)] 形状的 ndarray,但是对于 solve_ivp,输出是一维的 list(length of state vector) ndarray(长度等于t_eval)。

所以如果你想要相同的顺序,你必须合并它。你可以这样做:

Y =results
merged = np.hstack([i.reshape(-1,1) for i in Y.y])

首先,您需要对其进行整形以使其成为[n,1] 数组,然后将其水平合并。 希望这会有所帮助!

【讨论】:

  • 感谢清理。
  • 这会像 ode45 那样做可变步长吗?
  • 你不讨厌有人来,问一个问题而不选一个正确的吗? (也当有人复活旧帖子时)
【解决方案3】:

integrate.ode 的界面不像更简单的方法odeint 那样直观,但是它不支持选择 ODE 积分器。主要区别在于ode 不会为您运行循环;如果您需要在一堆点上找到解决方案,则必须说明在哪些点上,并一次计算一个点。

import numpy as np
from scipy import integrate
import matplotlib.pyplot as plt

def vdp1(t, y):
    return np.array([y[1], (1 - y[0]**2)*y[1] - y[0]])
t0, t1 = 0, 20                # start and end
t = np.linspace(t0, t1, 100)  # the points of evaluation of solution
y0 = [2, 0]                   # initial value
y = np.zeros((len(t), len(y0)))   # array for solution
y[0, :] = y0
r = integrate.ode(vdp1).set_integrator("dopri5")  # choice of method
r.set_initial_value(y0, t0)   # initial values
for i in range(1, t.size):
   y[i, :] = r.integrate(t[i]) # get one more value, add it to the array
   if not r.successful():
       raise RuntimeError("Could not integrate")
plt.plot(t, y)
plt.show()

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-24
  • 1970-01-01
相关资源
最近更新 更多