尝试解决家庭作业问题,可能需要一些帮助。我正在尝试使用Scipy的integrate.solve_ivp()
函数在Python中模拟PID控件。
我的方法是在函数的右侧运行PID代码,使用全局变量并将其在每个时间步结束时附加到全局矩阵,如下所示:
solution = integrate.solve_ivp(rhs, tspan, init, t_eval=teval)
def rhs(dt, init):
global old_time, omega0dot, rhs_t, omega0dotmat
timestep = dt - old_time
old_time = dt
# UNPACK INITIAL
x = init[0]
y = init[1]
z = init[2]
xdot = init[3]
ydot = init[4]
zdot = init[5]
alpha = init[6]
beta = init[7]
gamma = init[8]
alphadot = init[9]
betadot = init[10]
gammadot = init[11]
# SOLVE EQUATIONS
(xddot, yddot, zddot, alphaddot, betaddot, gammaddot) = dynamics(k_d, k_m, x, y, z, xdot, ydot, zdot, alpha, beta, gamma, alphadot, betadot, gammadot, omega0dot)
# CONTROL SYSTEMS
z_des = 10
err_z = z_des - z
zPID = (1*err_z) + hover
omega0dot = zPID
rhs_t.append(dt)
omega0dotmat.append(omega0dot)
return [xdot, ydot, zdot, xddot, yddot, zddot, alphadot, betadot, gammadot, alphaddot, betaddot, gammaddot]
全局变量在此函数之外初始化。您可能会注意到,我正在专门尝试模拟四旋翼飞机,其中四旋翼的线性运动和角运动取决于omega0dot
,integrate.solve_ivp()
代表转子速度,我正尝试使用PID进行控制。
我的困难在于solve_ivp()
的时间步长。 PID控制的积分和微分部分都依赖于时间步长,但是dt
函数具有可变的时间步长,有时似乎甚至会倒退时间,有时甚至没有时间步长(即dt <= 0) 。
我想知道是否有更好的方法来进行此PID控制,或者我是否错误地解释了solve_ivp()
中的{{1}}术语。任何帮助表示赞赏!
谢谢
答案 0 :(得分:2)
让我们看一个更简单的系统,即带阻尼的无处不在的弹簧
y'' + c*y' + k*y = u(t)
其中u(t)
可以代表电磁体施加的力(这立即提出了通过引入更现实的电压和磁场关系使系统更复杂的方法)。
现在在PID控制器中,我们对参考输出e = yr - y
和
u(t) = kD*e'(t) + kP*e(t) + kI*integral(e(t))
要使用ODE求解器对此进行处理,我们立即看到需要使用新组件E(t)
扩展状态,其中E'(t)=e(t)
。下一个困难是实现不一定可区分的表达式的派生。通过避免使用非标准的一阶实现(该标准将使用[y,y',E]
作为状态)来完全区分该表达式,可以实现这一点。
本质上,将公式中的所有派生表达式以其综合形式收集为
v(t)=y'(t)+c*y-kD*e(t).
然后回到导数获得一阶系统
v'(t) = y''(t) + c*y'(t) - kD*e'(t)
= kP*e(t) + kI*E(t) - k*y(t)
y'(t) = v(t) - c*y(t) + kD*e(t)
E'(t) = e(t)
这现在允许将受控系统实现为ODE系统,而无需涉及全局内存或类似操作的技巧
def odePID(t,u,params):
c,k,kD,kP,kI = params
y,v,E = u
e = yr(t)-y
return [ v-c*y+kD*e, kP*e+kI*E-k*y, e ]
您应该能够在更复杂的模型中使用一阶系统的类似转换。