去年导师给公司做的三路温控器让我搞的,匆匆忙忙就交差了直到现在反应出了一些问题我也搞了两天。感觉调PID参数太耗时间了,现在改进之后,超调量1度,误差正负0.5度。之前的问题是存在4度的静态偏差,尤其是在温控设定值三十多度四十度时比较明显。PID程序是直接用师兄的复制粘贴过来的,去年调的时候没加积分项原因是加了积分项之后根本就控制不起来了。由于当时比较赶也没有深究,五十度时控制效果很好就也没试验其它值就交差了。
加积分项就控制不了这个问题我想了一晚上,直到早上我醒了有了思路。那就从最根本的开始分析:
1、
fout1 = PIDCalc(&stPID1,ActualTemper1); //PID 计算
if( fout1 > 0 )
{
if( RunFlag ==1 )
DoB = 0; //控制相应的继续加热
}
else if( fout1 <= 0 )
{
if( RunFlag ==1 )
DoB = 1; //相应加热器停止加热
}
说明了这个PID计算的值一直是小于零的。可是为什么小于零呢?来看一下PIDCalc();这个函数
float PIDCalc( PID *pp, float NextPoint )
{
float xdata dError,Error;
dError = pp->LastError - pp->PrevError; // 当前微分
pp->PrevError = pp->LastError;
pp->LastError = Error;
return (pp->Proportion * Error//比例
+ pp->Integral * pp->SumError* 0.01 //积分项
+ pp->Derivative * dError); // 微分项
}
其中返回值是三个数相加的,Error、dError这两个值是确定的可以计算出来的,而SumError是多少呢?初始值根本就不知道,所以问题就在于没有初始化,初始化,初始化。这个一定要记住喽局部变量不初始化就是任意值,定义变量时最好带着初始化了。
初始化之后果然好使了。但是系统震荡明显且振幅大。于是开始调PID的过程了。参考了一位前辈的经验点击打开链接。其中他的那个模型特别好,直接带入计算设定值。效果还是不错的。不过,当设定温度与实际温度相差较大时控制效果很不好。于是加入积分分离,只有当靠近设定温度时才引入积分项。
float PIDCalc( PID *pp, float NextPoint )
{
float xdata dError,Error;
unsigned char index;
Error = pp->SetPoint - NextPoint; // 偏差
if(abs(Error)<5)
{
pp->SumError += Error; // 积分
index = 1;
}
else
{
index = 0;
} //积分分离,防止大幅度增减设定导致积分项一直累加,引起较大超调
dError = pp->LastError - pp->PrevError; // 当前微分
pp->PrevError = pp->LastError;
pp->LastError = Error;
return (pp->Proportion * Error//比例
+ pp->Integral * pp->SumError*index * 0.01 //积分项
+ pp->Derivative * dError); // 微分项
}
就是说,遇到了问题不要慌不要烦从最根本的问题去分析。