英文:
Why does changing my time step result in zeros when solving a system of ODEs?
问题
我已正确解决了一组常微分方程(ODEs),以计算给定转向输入的汽车轨迹:
A
是描述车辆参数的矩阵;b
是基于车辆参数的向量;u
是转向输入;V
是速度。参数 A
、b
和 V
不随时间变化。转向输入(弧度)是时间相关的步进输入,如代码中所示。
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
# 模型参数
m = 1500 # 质量
I = 2500 # 转动惯量
lf = 1.1
lr = 1.6
Cf = 55000 # 轮胎刚度
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: # 转向输入
u = 0.2
elif t > 3.5 and t < 4:
u = -0.2
elif t > 8 and t < 8.5:
u = -0.2
elif t > 10.5 and t < 11:
u = 0.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] # 初始条件
t = np.arange(0, 20, 0.005) # 时间步进,从0到20秒,间隔为0.005秒
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是x位置,x4是y位置
plt.xlim([0, 600])
plt.ylim([0, 40])
现在,根据时间步进的不同,我得到完全不同的结果:
- 对于0.005和0.08,我得到正确的解决方案。
- 对于0.03,我得到一个只有零的解决方案。
- 对于0.08,我得到一个不正确的非零解决方案。
为什么改变时间步进会导致其他变量为零?如何在事先不知道正确解决方案的情况下确定哪些时间步进值提供正确的解决方案?
英文:
I have correctly solved a system of ODEs to calculate a car’s trajectory from a given steering input:
A
is a matrix describing the vehicle parameters; b
is a vector based on vehicle parameters; u
is the steering input; and V
is the velocity. The parameters A
, b
and V
are not time dependent. The steering input (radians) is a time-dependent step input as shown in the code.
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])
Now, depending on the timestep, I get totally different results:
- For 0.005 and 0.08, I get a correct solution.
- For 0.03, I get a solution that is only zero.
- For 0.08, I get an incorrect non-zero solution.
Why would changing the timestep result in a zeros for the other variables?
How can one know which timestep values provide a correct solution without knowing the correct solution beforehand?
答案1
得分: 1
以下是翻译好的部分:
u
突然在与您的积分时间相比非常小的时间尺度上发生变化。odeint
的t
参数不是规定强制积分步骤,而是指定解决方案进行评估的时间点。odeint
可能决定采取比t
中给定的更粗糙的步骤,然后在给定的t
点上插值结果。但是,t
确实会影响步骤大小的猜测,因此实际采取的步骤。(我不能完全确定,因为我找不到这方面的文档,但这是积分器的常见行为,与您的观察完全吻合。)
结果,odeint
可能完全跳过 u
不同的区间(转向输入),因此您的汽车计算为直行而不是转弯。例如,在这种情况下,您的函数 func
在 1 到 1.5 之间的任何时间都不会被评估,因此 odeint
不可能知道它在该区间内改变了行为。
为了避免这种情况,设置参数 hmax
,它控制了最大步长,以便至少有一个步骤必须位于转向区间内:
x = odeint(func, x0, t, hmax=0.49)
自适应积分器将负责进一步按比例减小步骤。
英文:
What you observe is probably due to the following:
u
suddenly changes on very small time scales compared to your integration time.- The
t
argument ofodeint
is not prescribing mandatory integration steps, but rather points at which the solution is evaluated.odeint
may decide to take coarser steps than given int
and then interpolate the result at the points given int
. However,t
does affect the guess of step sizes and thus the steps actually taken. (I am not completely sure about this since I cannot find it documented, but it’s a common behaviour for integrators and perfectly matches your observations.)
As a result, odeint
may completely step over the intervals where u
is different (steering inputs) and thus your car is computed to drive straight instead of taking a turn. For example in such a case, your function func
simply never gets evaluated for any time between 1 and 1.5 and thus odeint
cannot possibly know that it changes its behaviour in that interval.
To avoid this, set the parameter hmax
which governs the maximum step size such that at least one step has to be within a steering interval:
x = odeint(func,x0,t,hmax=0.49)
The adaptive integrator will then take care to further scale down the steps accordingly.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论