调整时间步长求解汽车轨迹ODE系统时异常的原因及验证方法
汽车ODE轨迹求解的时间步长问题
我实现了一个基于转向输入求解汽车轨迹的ODE系统:
A为车辆参数矩阵,b为车辆参数向量,u为转向输入,V为速度,A、b、V均不随时间变化;转向输入(弧度)为代码中所示的时变阶跃输入。
代码如下:
import numpy as np import matplotlib.pyplot as plt from scipy.integrate import odeint # model parameters m = 1500 #mass I = 2500 #moment inertia lf = 1.1 lr = 1.6 Cf = 55000 #tire stiffness Cr = 60000 V = 27.77 A = np.array([[-2*(Cf+Cr)/(m*V), (2*(Cr*lr-Cf*lf)/(m*V**2))-1,0,0,0],[2*(Cr*lr-Cf*lf)/I, -2*((Cf*lf**2)+(Cr*lr**2))/(I*V),0,0,0]]) b = np.array([(2*Cf)/(m*V),(2*Cf*lf)/I]) def func(x,t): x1 = x[0] x2 = x[1] x3 = x[2] x4 = x[3] x5 = x[4] if t>1 and t<1.5: # steering inputs u = .2 elif t>3.5 and t<4: u=-.2 elif t>8 and t<8.5: u = -.2 elif t>10.5 and t<11: u = .2 else: u=0 dx1dt = np.dot(A[0,:],x) +b[0]*u dx2dt = np.dot(A[1,:],x) + b[1]*u dx3dt = V*np.cos(x5+x1) dx4dt = V*np.sin(x5+x1) dx5dt = x2 return [dx1dt, dx2dt,dx3dt,dx4dt,dx5dt] x0 =[0,0,0,0,0] # initial conditions t = np.arange(0,20,.005) #timestep 0 to 20 seconds at .005sec interval x = odeint(func,x0,t) x1 = x[:,0] x2 = x[:,1] x3 = x[:,2] x4 = x[:,3] x5 = x[:,4] plt.plot(x3,x4) # x3 is x position, x4 is y position plt.xlim([0,600]) plt.ylim([0,40])
调整时间步长时得到完全不同的结果:
- 时间步长为0.005时,得到正确解;
- 时间步长为0.03时,仅得到全零解;
- 时间步长为0.08时,得到错误的非零解。
问题解答
1. 为何调整时间步长会导致全零解?
你的转向输入是区间型阶跃信号(例如1<t<1.5时u=0.2),而odeint仅在你传入的t数组采样点上评估输入u。当时间步长为0.03时,采样点刚好完全错过所有转向输入的区间:
- 以第一个输入区间
(1,1.5)为例,0.03步长的采样点是1.0、1.03、1.06……1.47、1.5,这些点要么等于区间边界,要么在区间外,完全不满足1<t<1.5的条件,导致全程u=0。 - 初始条件
x0全为0,当输入u恒为0时,ODE的解自然保持全零状态。
你可以打印步长0.03的t数组验证这一点,会发现没有任何采样点落在转向输入的开区间内。
2. 未知正确解时判断合适的时间步长
可以通过以下几种实用方法判断:
- 输入采样验证:先确认时变输入的最小区间长度(这里是0.5秒),确保时间步长远小于最小区间的1/10(例如0.05秒以内),避免采样点错过输入区间。同时手动检查采样点是否覆盖了输入区间内的点。
- 步长收敛测试:
- 先选一个极小步长(如0.001)计算基准解;
- 逐步增大步长,对比不同步长下的关键输出(如轨迹y坐标、横摆角速度
x2); - 当步长增大到某一值时,输出与基准解的误差超过可接受范围(如1%),则该步长过大。
- 启用自适应步长:
odeint默认支持自适应步长,无需手动指定等间隔t数组。只需传入时间起点、终点或少量关键点(如t = np.linspace(0,20,1000)或t = [0,20]),求解器会自动调整步长,既保证精度又不会错过转向输入。 - 物理合理性校验:结合常识判断结果——比如汽车有转向输入时不可能静止,若出现不符合物理规律的结果,说明步长或输入处理存在问题。
内容的提问来源于stack exchange,提问作者mattkopp
相关产品推荐
相关产品推荐

