所谓的积分饱和现象是指如果系统存在一个方向的偏差,PID控制器的输出由于积分作用的不断累加而加大,从而导致执行机构达到极限位置,若控制器输出U(k)继续增大,执行器开度不可能再增大,此时计算机输出控制量超出了正常运行范围而进入饱和区。一旦系统出现反向偏差,u(k)逐渐从饱和区退出。进入饱和区越深则退出饱和区时间越长。在这段时间里,执行机构仍然停留在极限位置而不随偏差反向而立即做出相应的改变,这时系统就像失控一样,造成控制性能恶化,这种现象称为积分饱和现象或积分失控现象。
防止积分饱和的方法之一就是抗积分饱和法,该方法的思路是在计算u(k)时,首先判断上一时刻的控制量u(k-1)是否已经超出了极限范围:如果u(k-1)>umax,则只累加负偏差; 如果u(k-1)<umin,则只累加正偏差。从而避免控制量长时间停留在饱和区。直接贴出代码,不懂的看看前面几节的介绍。
//(1)定义PID 结构体变量
struct pid
{
float SetSpeed; //设定速度
float ActualSpeed; //实际值
float err; //定义偏差值
float err_last; //上一个偏差值
float Kp, Ki, Kd; //p,i,d系数
float voltage; //电压值
float integral; //积分值,即积分部分的累计值
//抗积分饱和
float umax;
float umin;
}pid;
int main()
{
int count = 0;
cout << "Please begin \n";
pid_value_init();
while (count < 100)
{
float speed = PID_realize(200.0);
cout <<"value is " <<speed<<endl ;
cout << " " << endl;
count++;
system("pause");
}
system("pause");
}
//(3) 控制算法注意:这里用了最基本的算法实现形式,没有考虑死区问题,
//没有设定上下限,只是对公式的一种直接的实现,后面的介绍当中还会逐渐的对此改进。
float PID_realize(float speed)
{
int index;
pid.SetSpeed = speed;
pid.err = pid.SetSpeed - pid.ActualSpeed;
//抗积分饱和过程
if (pid.ActualSpeed > pid.umax)
{
if (abs(pid.err) > 200)
{
index = 0;
}
else
{
index = 1;
if (pid.err < 0) //向反向积分
{
pid.integral += pid.err;
}
}
}
else if (pid.ActualSpeed < pid.umin)
{
if (abs(pid.err) > 200)
{
index = 0;
}
else
{
index = 1;
if (pid.err < 0)
{
pid.integral += pid.err;
}
}
}
else
{
if (abs(pid.err) > 200)
{
index = 0;
}
else
{
index = 1;
pid.integral += pid.err;
}
}
pid.voltage = pid.Kp * pid.err + pid.Ki*pid.integral + pid.Kd*(pid.err - pid.err_last);
pid.err_last = pid.err;
pid.ActualSpeed = pid.voltage *1.0;
return pid.ActualSpeed;
}
//(2) 初始化变量
void pid_value_init(void)
{
cout << "pid_value_init begin \n" << endl;
system("pause");
pid.SetSpeed = 0;
pid.ActualSpeed = 0;
pid.err = 0;
pid.err_last = 0;
pid.integral = 0;
pid.voltage = 0;
pid.Kp = 0.1;
pid.Ki = 0.15;
pid.Kd = 0.1;
pid.umax = 400;
pid.umin = -200;
cout << "pid_value_init end \n" << endl;
system("pause");
}