一、二位式控制算法
流程
Sv:目标值
Pv:控制对象当前值
特点
1.输出信号只有H/L两种
2.只考察当前状态值
3.算法输出信号OUT依据:
O
U
T
=
{
P
v
<
S
v
⇒
H
P
v
≥
S
v
⇒
L
OUT=\begin{cases} Pv<Sv \rArr H\\ Pv\ge Sv \rArr L \end{cases}
OUT={Pv<Sv⇒HPv≥Sv⇒L
二、PID控制算法
流程
分析数据序列
从开始以来采样到的数据序列:
X
1
,
X
2
,
X
3
⋯
X
k
−
2
,
X
k
−
1
,
X
k
X_1,X_2,X_3 \cdots X_{k-2},X_{k-1},X_k
X1,X2,X3⋯Xk−2,Xk−1,Xk
通过分析数据序列可得到以下3方面信息:
1.比例控制
E
k
=
S
v
−
X
k
{
E
k
>
0
:
当
前
控
制
未
达
标
E
k
=
0
:
当
前
控
制
正
好
达
标
E
k
<
0
:
当
前
控
制
超
标
E_k=Sv-X_k\begin{cases} E_k>0:当前控制未达标\\ E_k=0:当前控制正好达标\\ E_k<0:当前控制超标 \end{cases}
Ek=Sv−Xk⎩⎪⎨⎪⎧Ek>0:当前控制未达标Ek=0:当前控制正好达标Ek<0:当前控制超标
P
o
u
t
=
K
p
×
E
k
+
O
U
T
0
P_{out}=K_p \times E_k+OUT_0
Pout=Kp×Ek+OUT0
2.积分算法
历史偏差序列:
E
1
,
E
2
,
E
3
⋯
E
k
−
2
,
E
k
−
1
,
E
k
E_1,E_2,E_3 \cdots E_{k-2},E_{k-1},E_k
E1,E2,E3⋯Ek−2,Ek−1,Ek
S
k
=
E
1
+
E
2
+
E
3
+
⋯
+
E
k
−
2
+
E
k
−
1
+
E
k
S_k=E_1+E_2+E_3 +\cdots +E_{k-2}+E_{k-1}+E_k
Sk=E1+E2+E3+⋯+Ek−2+Ek−1+Ek
S
k
{
S
k
>
0
:
从
开
始
以
来
大
部
分
时
间
未
达
标
S
k
=
0
S
k
<
0
:
从
开
始
以
来
大
部
分
时
间
达
标
S_k\begin{cases} S_k>0:从开始以来大部分时间未达标\\ S_k=0\\ S_k<0:从开始以来大部分时间达标 \end{cases}
Sk⎩⎪⎨⎪⎧Sk>0:从开始以来大部分时间未达标Sk=0Sk<0:从开始以来大部分时间达标
I
o
u
t
=
K
p
×
S
k
+
O
U
T
0
I_{out}=K_p\times S_k+OUT_0
Iout=Kp×Sk+OUT0
3.微分算法
最近两次偏差相减:
D
k
=
E
k
−
E
k
−
1
{
D
k
>
0
:
偏
差
有
增
大
趋
势
D
k
=
0
:
偏
差
没
有
变
化
D
k
<
0
:
偏
差
有
减
小
趋
势
D_k=E_k-E_{k-1}\begin{cases} D_k>0:偏差有增大趋势\\ D_k=0:偏差没有变化\\ D_k<0:偏差有减小趋势 \end{cases}
Dk=Ek−Ek−1⎩⎪⎨⎪⎧Dk>0:偏差有增大趋势Dk=0:偏差没有变化Dk<0:偏差有减小趋势
D
o
u
t
=
K
p
×
D
k
+
O
U
T
0
D_{out}=K_p\times D_k+OUT_0
Dout=Kp×Dk+OUT0
PID控制算法的数学模型
P I D o u t = P o u t + I o u t + D o u t = ( K p × E k + O U T 0 ) + ( K p × S k + O U T 0 ) + ( K p × D k + O U T 0 ) = K p × ( E k + S k + D k ) + O U T 0 \begin{aligned} PID_{out}&=P_{out}+I_{out}+D_{out} \\&=(K_p \times E_k+OUT_0)+(K_p\times S_k+OUT_0)+(K_p\times D_k+OUT_0) \\&=K_p \times (E_k+S_k+D_k)+OUT_0 \end{aligned} PIDout=Pout+Iout+Dout=(Kp×Ek+OUT0)+(Kp×Sk+OUT0)+(Kp×Dk+OUT0)=Kp×(Ek+Sk+Dk)+OUT0
基于单片机的PID控制算法
S
k
S_k
Sk 的处理:
S
k
=
1
T
i
×
∑
k
=
0
n
E
k
×
T
S_k=\dfrac{1}{T_i} \times \sum_{k=0}^n{E_k} \times T
Sk=Ti1×k=0∑nEk×T
D
k
D_k
Dk 的处理:
D
k
=
T
d
×
(
E
k
−
E
k
−
1
T
)
D_k=T_d \times (\dfrac{E_k-E_{k-1}}{T} )
Dk=Td×(TEk−Ek−1)
其中:
T
T
T为采样周期(计算周期)、
T
i
T_i
Ti为积分常数、
T
d
T_d
Td为微分常数
位置式PID控制算法
O U T = ( K p × E k ) + ( K p × T T i × ∑ k = 0 n E k ) + ( K p × T d T × ( E k − E k − 1 ) ) + O U T 0 (1) OUT=(K_p \times E_k)+(K_p \times \dfrac{T}{T_i} \times \sum_{k=0}^n{E_k})+(K_p \times \dfrac{T_d}{T} \times (E_k-E_{k-1}))+OUT_0 \tag{1} OUT=(Kp×Ek)+(Kp×TiT×k=0∑nEk)+(Kp×TTd×(Ek−Ek−1))+OUT0(1)
增量式PID控制算法
Δ O U T = O U T k − O U T k − 1 O U T k − 1 = ( K p × E k − 1 ) + ( K p × T T i × ∑ k = 0 n − 1 E k ) + ( K p × T d T × ( E k − 1 − E k − 2 ) ) + O U T 0 ∴ Δ O U T = ( 1 ) − ( 2 ) Δ O U T = K p × ( E k − E k − 1 ) + K p × T T i × E k + K p × T d T × ( E k − 2 E k − 1 + E k − 2 ) (2) \begin{aligned} \Delta OUT&=OUT_k-OUT_{k-1} \\ OUT_{k-1}&=(K_p \times E_{k-1})+(K_p \times \dfrac{T}{T_i} \times \sum_{k=0}^{n-1}{E_k})+(K_p \times \dfrac{T_d}{T} \times (E_{k-1}-E_{k-2}))+OUT_0 \tag{2} \\ \therefore \Delta OUT&=(1)-(2) \\ \Delta OUT&=K_p \times(E_k-E_{k-1})+K_p \times \dfrac{T}{T_i} \times E_k+K_p \times \dfrac{T_d}{T} \times (E_k-2E_{k-1}+E_{k-2}) \end{aligned} ΔOUTOUTk−1∴ΔOUTΔOUT=OUTk−OUTk−1=(Kp×Ek−1)+(Kp×TiT×k=0∑n−1Ek)+(Kp×TTd×(Ek−1−Ek−2))+OUT0=(1)−(2)=Kp×(Ek−Ek−1)+Kp×TiT×Ek+Kp×TTd×(Ek−2Ek−1+Ek−2)(2)
单片机中增量式PID控制算法实现
void PID_Init() //PID初始化
{
pid.sv=0; //设定值
pid.pv=0; //当前值
pid.Ek=0; //当前偏差值
pid.Ek_1=0; //上次偏差值
pid.Ek_2=0; //前次偏差值
pid.out=0; //输出值
pid.increase=0; //增量值
/*以下3个为经验值*/
pid.Kp=?;
pid.Ki=?;
pid.Kd=?;
}
float PID_Calc(float sv,float pv) //PID计算
{
float dacx;
pid.sv=(float)sv; //设定值
pid.pv=(float)Get_Adc_Average(pv,20); //设置AD采样通道
pid.Ek=pid.sv-pid.pv; //当前偏差值
pid.out=pid.Kp*(pid.Ek-pid.Ek_1)+pid.Ki*pid.Ek+pid.Kp*(pid.Ek-2*pid.Ek_1+pid.Ek_2);
if(pid.increase>20)
{
pid.increase=20;
}else if(pid.increase<-20){
pid.increase=-20;
}
pid.out+=pid.increase;
HAL_DAC_SetValue(&DAC1_Handler,DAC_CHANNEL_1,DAC_ALIGN_12B_R,pid.out);//设置DAC值
dacx=HAL_DAC_GetValue(&DAC1_Handler,DAC_CHANNEL_1) * (3.3/4096);
printf("t0.txt=\"%f\"",dacx); //在串口屏上打印DAC值
printf("%c%c%c",0xff,0xff,0xff);
pid.Ek_2=pid.Ek_1; //更新偏差值
pid.Ek_1=pid.Ek;
return 0;
}
/*
此代码通过单片机AD/DA功能实现,仅供参考
有很多不当之处请见谅,若能指出则更好 ○| ̄|_
*/
本文部分内容来源于网络,内容均为非盈利,如有侵权请告知,马上删除。