You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用scipy.integrate.RK45求解微分方程的问题及代码故障排查

嘿,我明白你现在卡在哪了——直接调用RK45后打印出来的是个求解器对象,根本不是你想要的数值数组对吧?这是因为RK45属于显式迭代型的求解器,它不会一次性输出整个区间的结果,得你手动驱动它一步步计算,然后把结果收集起来。我来一步步帮你搞定,先从你测试的非耦合方程入手,再扩展到耦合方程组的情况。

一、先解决非耦合方程的问题

首先得修正你现有代码里的几个小问题:

  • RK45要求的函数签名是fun(t, y),你的f(t,x)符合要求,但要注意参数顺序是时间t在前,状态变量在后。
  • 你构造RK45对象时的参数顺序错了!正确的参数顺序是:RK45(fun, t0, y0, t_bound, max_step=inf, rtol=1e-3, atol=1e-6, ...),你把max_step、rtol的位置搞混了,而且e**-6建议写成1e-6更规范。

下面是修正后的完整代码,能正确收集解并绘图:

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

# 定义微分方程:x' = -x
def f(t, x):
    return -x

# 初始化求解器:t0=0,初始值x0=[1],求解到t_bound=10
solver = RK45(f, t0=0, y0=[1], t_bound=10, rtol=1e-6, atol=1e-6)

# 用来收集结果的列表
t_values = []
x_values = []

# 循环推进求解,直到到达目标时间t_bound
while solver.status == 'running':
    solver.step()  # 计算下一个时间步的解
    t_values.append(solver.t)  # 记录当前时间
    x_values.append(solver.y[0])  # 记录当前x的值(y是数组,取第一个元素)

# 转成numpy数组方便后续处理
t_values = np.array(t_values)
x_values = np.array(x_values)

# 打印前5个结果示例
print("前5个时间点的解:")
for t, x in zip(t_values[:5], x_values[:5]):
    print(f"t={t:.4f}, x={x:.4f}")

# 绘制解曲线
plt.figure(figsize=(8, 4))
plt.plot(t_values, x_values, label='x(t) = e^(-t)')
plt.xlabel('t')
plt.ylabel('x')
plt.title('非耦合微分方程x\'=-x的解')
plt.legend()
plt.grid(True)
plt.show()
二、扩展到耦合微分方程组的情况

假设你的耦合方程组是:
$x' = f(x, y, t)$
$y' = g(x, y, t)$

这里用一个具体的耦合例子($x' = -x + y$,$y' = x - 2y$)来演示完整的求解和绘图流程:

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

# 定义耦合微分方程组:状态变量数组[y1, y2]对应x和y
def coupled_fun(t, y):
    x, y_var = y  # 解包状态变量,用y_var避免和函数参数y冲突
    dx_dt = -x + y_var  # x' = -x + y
    dy_dt = x - 2 * y_var  # y' = x - 2y
    return [dx_dt, dy_dt]

# 初始条件:t0=0,x0=1,y0=0
t0 = 0
y0 = [1, 0]
t_bound = 10

# 初始化求解器
solver = RK45(coupled_fun, t0=t0, y0=y0, t_bound=t_bound, rtol=1e-6, atol=1e-6)

# 收集结果
t_values = []
x_values = []
y_values = []

while solver.status == 'running':
    solver.step()
    t_values.append(solver.t)
    x_values.append(solver.y[0])
    y_values.append(solver.y[1])

# 转成numpy数组
t_values = np.array(t_values)
x_values = np.array(x_values)
y_values = np.array(y_values)

# 绘制时间序列解曲线
plt.figure(figsize=(10, 5))
plt.plot(t_values, x_values, label='x(t)')
plt.plot(t_values, y_values, label='y(t)')
plt.xlabel('t')
plt.ylabel('x, y')
plt.title('耦合微分方程组的解')
plt.legend()
plt.grid(True)
plt.show()

# 绘制相图(x vs y),观察变量间的关系
plt.figure(figsize=(6, 6))
plt.plot(x_values, y_values)
plt.xlabel('x')
plt.ylabel('y')
plt.title('耦合方程组的相图')
plt.grid(True)
plt.show()
关键注意点总结
  • RK45是迭代式求解器,必须手动循环调用.step()推进求解,这是它和odeint、solve_ivp(后者可直接返回结果)的核心区别。
  • 自定义的微分方程函数必须遵循fun(t, y)的签名,y是状态变量的数组,返回值是对应导数的数组。
  • 初始化求解器时,t_bound是你要求解的最终时间,rtol和atol控制求解精度,数值越小精度越高。
  • 每次调用.step()后,可通过solver.t获取当前时间,solver.y获取当前状态变量的值。

内容的提问来源于stack exchange,提问作者Sharma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:03:39