PID控制器离散化
因为计算机处理为数字处理,反馈环节采样和作用环节处理并非理想连续而是离散的。所以需要对连续时间的PID控制器模型进行离散化处理,连续时间PID控制器:
u
(
t
)
=
K
p
e
(
t
)
+
K
i
∫
0
t
e
(
τ
)
d
t
+
K
d
d
e
(
t
)
d
t
u(t)=K_pe(t)+K_i\int_0^te(τ)dt+K_d\frac{de(t)}{dt}
u(t)=Kpe(t)+Ki∫0te(τ)dt+Kddtde(t)
控制器离散化:
u
(
n
)
=
K
p
e
(
n
)
+
K
i
∑
i
=
0
n
e
(
i
)
+
K
d
(
e
(
n
)
−
e
(
n
−
1
)
)
u(n)=K_pe(n)+K_i\sum_{i=0}^{n}e(i)+K_d(e(n)-e(n-1))
u(n)=Kpe(n)+Kii=0∑ne(i)+Kd(e(n)−e(n−1))
n:采样次数
位置式PID算法实现
PID控制器离散化直接算法实现即为位置式PID。
typedef struct {
float target_val; //目标值
float err; //定义当前偏差值
float err_last; //定义上一个偏差值
float Kp, Ki, Kd; //定义比例、积分、微分系数
float integral; //积分值
float control_val; //控制值
} PID_Typedef;
float PID_Process(PID_Typedef *pid_obj,float current_val){
pid_obj->err=pid_obj->target_val-current_val;
pid_obj->integral+=pid_obj->err;
pid_obj->control_val = pid_obj->Kp*pid_obj->err
+ pid_obj->Ki*pid_obj->integral
+ pid_obj->Kd*(pid_obj->err-pid_obj->err_last);
pid_obj->err_last=pid_obj->err;
return pid_obj->control_val;
}
由传统位置式PID控制器到增量式PID控制器的数学推导
传统位置式PID控制存在积分累加环节,计算量相对较大,为了优化算法效率,将每一次控制量拆分,只计算控制量的增量,这就是增量式PID控制器。
将n=(n-1)代入至离散化PID公式,即:
u
(
n
−
1
)
=
K
p
e
(
n
−
1
)
+
K
i
∑
i
=
0
n
−
1
e
(
i
)
+
K
d
(
e
(
n
−
1
)
−
e
(
n
−
2
)
)
u(n-1)=K_pe(n-1)+K_i\sum_{i=0}^{n-1}e(i)+K_d(e(n-1)-e(n-2))
u(n−1)=Kpe(n−1)+Kii=0∑n−1e(i)+Kd(e(n−1)−e(n−2))
增量式PID控制器
Δ
u
=
u
(
n
)
−
u
(
n
−
1
)
\Delta u=u(n)-u(n-1)
Δu=u(n)−u(n−1)即:
Δ
u
=
K
p
(
e
(
n
)
−
e
(
n
−
1
)
)
+
K
i
e
(
n
)
+
K
d
(
e
(
n
)
−
2
e
(
n
−
1
)
+
e
(
n
−
2
)
)
\Delta u=K_p(e(n)-e(n-1))+K_ie(n)+K_d(e(n)-2e(n-1)+e(n-2))
Δu=Kp(e(n)−e(n−1))+Kie(n)+Kd(e(n)−2e(n−1)+e(n−2))
所以得:
u
(
n
)
=
Δ
u
+
u
(
n
−
1
)
u(n)=\Delta u+u(n-1)
u(n)=Δu+u(n−1)
由上式可知,增量式PID控制只与最近的三次采样的误差有关,计算复杂度由O(n)变为O(1)。
增量式PID算法实现
typedef struct {
float target_val; //目标值
float err; //定义当前偏差值
float err_last; //定义上一个偏差值
float err_before_last;//定义上上一个偏差值
float Kp, Ki, Kd; //定义比例、积分、微分系数
float control_val; //控制值
} PID_Typedef;
float PID_Process(PID_Typedef *pid_obj,float current_val){
pid_obj->err=pid_obj->target_val-current_val;
float delta_val = pid_obj->Kp*(pid_obj->err-pid_obj->err_last)
+pid_obj->Ki*pid_obj->err
+pid_obj->Kd*(pid_obj->err-2*pid_obj->err_last+pid_obj->err_before_last);
pid_obj->control_val+=delta_val;
pid_obj->err_before_last=pid_obj->err_last;
pid_obj->err_last=pid_obj->err;
return pid_obj->control_val;
}