有没有更好的方法在 Python 中用 Scipy 的 solve_ivp() 模拟 PID 控制?
Is there a better way to simulate PID control in Python with Scipy's solve_ivp()?
我正在做作业。我正在尝试使用 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]
全局变量是在这个函数外初始化的。您可能会注意到,我专门尝试模拟四轴飞行器,其中四轴飞行器的线性和 angular 运动取决于 omega0dot
,它代表转子速度,我试图用 PID 控制它。
我的困难在于 integrate.solve_ivp()
的 timestep。 PID 控制的积分和微分部分都依赖于时间步长,但是 solve_ivp()
函数有一个可变的时间步长,有时甚至似乎在时间上倒退,有时甚至没有时间步长(即 dt <= 0) .
我想知道是否有更好的方法来进行 PID 控制,或者我是否在解释 solve_ivp()
中的 dt
项是错误的。
让我们看一个更简单的系统,无处不在的spring带阻尼
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 ]
您应该能够在更复杂的模型中使用一阶系统的类似变换。
我正在做作业。我正在尝试使用 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]
全局变量是在这个函数外初始化的。您可能会注意到,我专门尝试模拟四轴飞行器,其中四轴飞行器的线性和 angular 运动取决于 omega0dot
,它代表转子速度,我试图用 PID 控制它。
我的困难在于 integrate.solve_ivp()
的 timestep。 PID 控制的积分和微分部分都依赖于时间步长,但是 solve_ivp()
函数有一个可变的时间步长,有时甚至似乎在时间上倒退,有时甚至没有时间步长(即 dt <= 0) .
我想知道是否有更好的方法来进行 PID 控制,或者我是否在解释 solve_ivp()
中的 dt
项是错误的。
让我们看一个更简单的系统,无处不在的spring带阻尼
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 ]
您应该能够在更复杂的模型中使用一阶系统的类似变换。