对传统PID控制算的优化改善
针对传统PID控制算法的优化
一,原理图
根据原理图,MCU通过输出0~100%占空比的PWM来控制温度;通过ADC0808来采集温度
二,PID控制代码
void PIDCalu(PID_para *pid )
{
pid->Yn = 0.3906*GetADC();
pid->En = pid->Rn - pid->Yn;
pid->SumOfEn += Pid.En;
pid->Un = pid->Kp*pid->En +
pid->Ki*Pid.SumOfEn +
pid->Kd*(pid->En - pid->En_1);
pid->En_1 = pid->En;
}
三,分析
PID控制代码并不是难点。难点是Kp,Ki,Kd三个参数的最优配置。这三个参数可能随便配一个差不多的数,温度也能最终稳定下来;但需要的时间、超调量、精准度这些指标,却并不一定是所有情况中最好的。
当Kp,Ki,Kd为5,0.005,20时,期望温度50℃,控制效果为
通过此图可以得知:
a,系统的输出控制,前期主要由比例项决定;后期主要由微分项和积分项决定;
b,比例项的大小决定了前期升温的速度;微分项和积分项决定了后期稳定的精度。
根据这两个结论,我们设计一个公式,让Kp,Ki,Kd参数在控制过程中实时改变。当距离期望温度很大时,便采用较大的Kp,较小的积分项和Kd;而距离期望温度较小时,用较小的Kp,较大的积分项和Kd。
注意,改积分项并不是改改Ki就行了。积分是一种累加运算,你即便在后期改了Ki,那前期的累计值依然在积分项中,影响着后期的控制。所以实际上改积分项应该改不同阶段的积分权值,即:
积分项 =
注意Ki和k(t)并不是一回事。Ki是一个常量,影响了积分项在PID中的整体权重。而k(t)是一个函数,它实时性的为每一个样本e(t0),e(t1),e(t2)...分配了不同的权重。
我们下面采用单一变量法进行实验。
1,验证变参数Kp的效果。
A组:Ki,Kd,Kp为5,0.005,20不变
B组:Ki,Kd不变;令Kp = En/5 + 5;当En从50到0时,Kp相应的从15变化到5。
根据以上实验得知,在其他性能相似的情况下,B组达到稳定状态的速度要比A组好。
2,验证变参数Kd的效果
A组:Kp,Ki,kd为5,0.003,50,期望温度为50度
B组:Kp,Ki不变,Kd = 10/En,当En从10到0.2时,Kd也从1到50;
显然,B优于A。
3,验证变参数Ki的效果
A组:Kp,Ki,kd为5,0.05,50,期望温度为50度
B组:在Kp,Ki,Kd不变的情况下;引入一个“积分强弱”控制因子Kit = 1-En/Rn;原来的积分项公式修改为:
显然,即便在系统肯定会产生超调的情况下,B组的超调也比A组小。
四,改进之后的PID控制代码,加了一个KpKiKdCalu函数,用于实时调整Kp,Ki,Kd.
void KpKiKdCalu(PID_para *pid)
{
//变参数Kp
pid->Kp = Abs(pid->En)/5 + 5;
//变参数Kd
if(Abs(pid->En) < 0.2)
{
pid->Kd = 50;
}
else
{
pid->Kd = 10/ Abs(pid->En) ;
}
//变参数Kit
if(pid->Rn!=0)
{
pid->Kit = 1 - Abs(pid->En / pid->Rn) ;
}
}
void PIDCalu(PID_para *pid )
{
pid->Yn = 0.3906*GetADC();
pid->En = pid->Rn - pid->Yn;
pid->SumOfEn += pid->Kit*pid->En;
pid->Un = pid->Kp*pid->En +
pid->Ki*Pid.SumOfEn +
pid->Kd*(pid->En - pid->En_1);
pid->En_1 = pid->En;
}
Kp,Ki,Kd初始值:5,0.01,50
期望温度50℃,控制效果: