使用scipy solve_ivp求解IVP ODE传参报错及正弦波收敛问题
问题解决:ODE求解报错与正弦波收敛实现
一、错误根源分析
- 变量未定义:
odefcn2中误用未声明的Tc2_vals,实际应为Tc2。 - 数组传递逻辑错误:
solve_ivp的ODE函数是逐时刻调用的,直接传入整个Td_pred数组会导致形状不匹配——函数期望单个数值,而非完整数组序列。 - RNN输入形状不匹配:训练时
x_train的形状与SimpleRNN要求的(样本数, 时间步长, 特征数)不兼容,导致模型训练效果差,后续预测无法有效补偿干扰。
二、分步解决方案
1. 修正RNN模型训练的输入形状
调整训练数据形状,匹配SimpleRNN的输入要求:
# 修正训练数据形状:从(1101,2)转为(1101,2,1),符合SimpleRNN的input_shape=(2,1) x_train = np.transpose(x) x_train = x_train[n:] x_train = x_train.reshape([-1, 2, 1]) # 重新训练模型(若之前因输入形状错误导致效果不佳) Td_model = tf.keras.models.Sequential() Td_model.add(tf.keras.layers.SimpleRNN(200, input_shape=(2,1), activation='tanh')) Td_model.add(tf.keras.layers.Dense(1)) Td_model.compile(loss='mean_absolute_error', optimizer='adam') Td_model.fit(x_train, Td_train, epochs=200, batch_size=16, verbose=0)
2. 修正ODE函数,实现实时预测补偿
将模型预测逻辑整合到ODE函数中,在每个求解时刻,根据当前系统状态x实时预测干扰Td,再用于控制器补偿:
def odefcn2(t, x, model): x1, x2 = x Amp = 1 P = 110 # 真实干扰信号 Td = Amp * np.sin(2 * np.pi / P * t) m = 2 kd = 3 kp = 5 # 将当前状态转为模型要求的输入形状(1,2,1),实时预测干扰 current_state = np.array([[x1, x2]]).reshape(1, 2, 1) Td_pred = model.predict(current_state, verbose=0)[0][0] # 提取单个预测值 if t < 110: Tc2 = -kp * x1 - kd * x2 else: # 用预测的干扰做前馈补偿,抵消真实干扰影响 Tc2 = -kp * x1 - kd * x2 - Td_pred # 返回状态导数:修正之前的变量名错误 return [ x2, (Tc2 + Td) / m ]
3. 正确调用solve_ivp求解ODE
将训练好的模型作为参数传入,而非静态的Td_pred数组:
# 求解补偿后的系统ODE sol2 = solve_ivp(odefcn2, [t[0], t[-1]], x0, args=(Td_model, ), t_eval=t, rtol=1e-5, dense_output=True, method='RK45') x2 = sol2.sol(t) # 绘图验证收敛效果 plt.figure(2) plt.style.use('seaborn-poster') plt.plot(t, x2.T) plt.grid(color='darkgrey', linestyle='-.', linewidth=0.5) plt.xlabel('t') plt.ylabel('x') plt.legend(['x1', 'x2'], shadow=True) plt.title('Compensated 2nd-Order System') plt.show()
三、关键说明
- 实时预测的必要性:静态的
Td_pred基于历史状态生成,而补偿后的系统状态会动态变化,必须用当前状态实时预测干扰,才能有效抵消正弦波的影响。 - 模型优化建议:若预测效果不佳,可尝试增加RNN层数、调整神经元数量,或改用LSTM;也可将
t作为额外特征输入模型,提升干扰预测精度。 - 收敛验证:补偿后蓝色曲线(x1)应逐渐收敛至0,因为前馈补偿抵消了正弦干扰
Td的作用。
内容的提问来源于stack exchange,提问作者Ish
相关产品推荐
相关产品推荐

