浅谈-非线性预测式负反馈控制(温控)
本帖最后由 coleyao 于 2012-10-12 19:29 编辑以前我曾经在论坛上讨论过预测式负反馈控制,那时的看法是线性预测各方面都优于非线性预测,似乎非线性预测没有必要使用。前一阵子折腾了一阵,作了一个改进型预测式负反馈控制算法的效果仿真(使用非线性预测),结果却意外的发现,在系统参数相同的情况下,经过精心调整的非线性预测负反馈系统的稳态精度要高于线性预测负反馈系统,差不多稳态精度能提高一倍的样子,如图所示(两种算法针对环境温度波动的干扰都已作了最大优化),这另一方面似乎也说明了PID控制中的D分量不是可有可无的!
另外说一句,之前好像有人提到我写的建议温控算法仿真软件在WIN7下不能使用,看起来不是这样,我的附图就是在Win7Home 普通版下截取的! 一值注意楼主的这个理论,“非线性预测”它的相应的公式吗?或是算法,谢谢! Pref_adv能给个算法参考试下吗? 期待下文呢 本帖最后由 coleyao 于 2012-12-10 11:21 编辑
YOU1 发表于 2012-12-9 20:13 static/image/common/back.gif
期待下文呢
呵呵,线性预测的公式是 ERRTadj=FdK*(ERRT+PreK*vT);也就是对ERRT作了一定程度的预测,预测深度是PreK;
非线性预测的公式是ERRTadj=FdK*(ERRT+PreK*vTadj); 也就是说不光根据ERRT的速度vT来调整,同时对vT作一定程度的预测,预测深度为PreK',根据预测后的vT对预测的ERRT进行修正,也即双重预测。
其实非线性预测不是所有时候都优于线性预测的,只是某些场合,它确实效果要优于线性预测,原因是它对速度vT作了一定的修正(本来vT就不是常量,所以理论上修正过的vT更合理)。
当然了,具体的效果有心的网友可以自己验证一下,我就不再举例了! 个人觉得预测式负反馈才是原先的所谓PID算法的精髓所在,因此原先写过一篇名为“让PID成为历史”的帖子,点击量那是刚刚的啊,可是最终还是觉得有点太张扬了,把帖子名字改掉了{:lol:} 呵呵,控制如人生啊!预测得少了,容易振荡,总是与目标插肩而过,抓不住目标;预测得多了,事事都考虑到了,又会导致增速缓慢,达到目标的时间太长了! {:smile:}
呵呵,控制如人生啊!预测得少了,容易振荡,总是与目标插肩而过,抓不住目标;预测得多了,事事都考虑到了,又会导致增速缓慢,达到目标的时间太长了!
//---------------------------------------------------------
经典
非线性预测的公式是ERRTadj=FdK*(ERRT+PreK*vTadj); 其中vTadj=vT+PreK' *aT,也就是说不光根据ERRT的速度vT来调整,同时对vT作一定程度的预测,预测深度为PreK',根据预测后的vT对预测的ERRT进行修正,也即双重预测
//--------------------------------------------------------------------------------------------------
受益非浅! eddia2012 发表于 2012-12-10 11:41 static/image/common/back.gif
非线性预测的公式是ERRTadj=FdK*(ERRT+PreK*vTadj); 其中vTadj=vT+PreK' *aT,也就是说不光根据ERRT的速 ...
其实vTadj=vT+PreK' *aT可以根据需要来简化处理,简化之后变成了vTadj=(m+1)*vT-m*vT_Last。
呵呵,很有趣的公式,未来=现在-过去{:biggrin:} 这个是精确温度控制,可惜没有实例程序!!! liudaolunhui 发表于 2012-12-10 12:12 static/image/common/back.gif
这个是精确温度控制,可惜没有实例程序!!!
不仅是精确温度控制,而且应该是个很容易掌握的控制方式,我现在已经基本上可以做到参数自整定了,不过只是用仿真软件进行了验证,没有严格上产品验证! 恩!!!!! {:smile:}能写出这么好的东西很不错了,希望好贴顶起来!
阿莫老大能否给Cool! 楼主要是有一个实例就好了,呵呵
//实例,三路预测式负反馈控温,1片89S52,注释没那么详细,大家就将就看吧{:titter:}
//-------------------定时中断5,使用定时器2-----------------------
void int_time_st(void) interrupt 5 using 1 // 31.25ms timer
{
CountT++;
if(CountT>159) { CountT=0; }
TF2=0;
}
void HeatControlPre(void)
{
static unsigned int CountHeat,MaxCounHeat,pPhPWM=9000; //以5秒为周期的计数器及计数最大值,当前pwm指针
static uint idata Last_temPT,vPT,ErrorPT,EPT_adj; //前5秒内记忆的温度数据(每一秒一个数据),温升速率,温度偏差,调整后的温度偏差
static uchar plvPT,plErrorPT,plEPT_adj,kP_Pre=0; //温升速率正负,温度偏差正负,调整后的温度偏差正负,预测k系数
static uint idata pHhPWM=100,Last_temHT,vHT,ErrorHT,EHT_adj;
static uchar plvHT,plErrorHT,plEHT_adj,kH_Pre=0;
static uint idata pKhPWM=100,Last_temKT,vKT,ErrorKT,EKT_adj;
static uchar plvKT,plErrorKT,plEKT_adj,kK_Pre=0;
if(PHToDeal)
{
PHToDeal=0;SetPT&=0xfff0; SetPT|=0x08;
if((CountHeat>1000)&&((CountT>>5)==4)){ MaxCounHeat=CountHeat;CountHeat=0; }
if(temPT>SetPT) { ErrorPT=temPT-SetPT; plErrorPT=1; }else {ErrorPT=SetPT-temPT; plErrorPT=0;}
if(temPT>Last_temPT) { vPT=temPT-Last_temPT; plvPT=1; } else { vPT=Last_temPT-temPT; plvPT=0;}
if(plErrorPT)
{
if(plvPT) {EPT_adj=kP_Pre*vPT+ErrorPT; plEPT_adj=1; }
else {
if(ErrorPT>(kP_Pre*vPT)) { EPT_adj=ErrorPT-kP_Pre*vPT; plEPT_adj=1; }
else{ EPT_adj=kP_Pre*vPT-ErrorPT; plEPT_adj=0; }
}
}
else
{
if(plvPT==0) {EPT_adj=kP_Pre*vPT+ErrorPT; plEPT_adj=0; }
else {
if(ErrorPT>(kP_Pre*vPT)) { EPT_adj=ErrorPT-kP_Pre*vPT; plEPT_adj=0; }
else{ EPT_adj=kP_Pre*vPT-ErrorPT; plEPT_adj=1; }
}
}
if(plEPT_adj)//re
{
if((pPhPWM+(EPT_adj>>2))<MaxCounHeat) pPhPWM+=((EPT_adj>>2));
}
else
{
if(pPhPWM>((EPT_adj>>2))) pPhPWM-=((EPT_adj>>2));
}
Last_temPT=temPT;
if(80>(EPT_adj>>2))kP_Pre=82-(EPT_adj>>2);
}
if(HHToDeal)
{
HHToDeal=0; SetHT&=0xfff0; SetHT|=0x08;
//if(CountT==1){ MaxCounHeat=CountHeat;CountHeat=0; }
if(temHT>SetHT) { ErrorHT=temHT-SetHT; plErrorHT=1; }else {ErrorHT=SetHT-temHT; plErrorHT=0;}
if(temHT>Last_temHT) { vHT=temHT-Last_temHT; plvHT=1; } else { vHT=Last_temHT-temHT; plvHT=0;}
if(plErrorHT)
{
if(plvHT) {EHT_adj=kH_Pre*vHT+ErrorHT; plEHT_adj=1; }
else {
if(ErrorHT>(kH_Pre*vHT)) { EHT_adj=ErrorHT-kH_Pre*vHT; plEHT_adj=1; }
else{ EHT_adj=kH_Pre*vHT-ErrorHT; plEHT_adj=0; }
}
}
else
{
if(plvHT==0) {EHT_adj=kH_Pre*vHT+ErrorHT; plEHT_adj=0; }
else {
if(ErrorHT>(kH_Pre*vHT)) { EHT_adj=ErrorHT-kH_Pre*vHT; plEHT_adj=0; }
else{ EHT_adj=kH_Pre*vHT-ErrorHT; plEHT_adj=1; }
}
}
if(plEHT_adj)//re
{
if((pHhPWM+(EHT_adj>>1))<MaxCounHeat) pHhPWM+=((EHT_adj>>1));
}
else
{
if(pHhPWM>((EHT_adj>>1))) pHhPWM-=((EHT_adj>>1));
}
Last_temHT=temHT;
if(40>(EHT_adj>>3))kH_Pre=50-(EHT_adj>>3);
}
if(KHToDeal)
{
KHToDeal=0;SetKT&=0xfff0; SetKT|=0x08;
// if(CountT==1){ MaxCounHeat=CountHeat;CountHeat=0; }
if(temKT>SetKT) { ErrorKT=temKT-SetKT; plErrorKT=1; }else {ErrorKT=SetKT-temKT; plErrorKT=0;}
if(temKT>Last_temKT) { vKT=temKT-Last_temKT; plvKT=1; } else { vKT=Last_temKT-temKT; plvKT=0;}
if(plErrorKT)
{
if(plvKT) {EKT_adj=kK_Pre*vKT+ErrorKT; plEKT_adj=1; }
else {
if(ErrorKT>(kK_Pre*vKT)) { EKT_adj=ErrorKT-kK_Pre*vKT; plEKT_adj=1; }
else{ EKT_adj=kK_Pre*vKT-ErrorKT; plEKT_adj=0; }
}
}
else
{
if(plvKT==0) {EKT_adj=kK_Pre*vKT+ErrorKT; plEKT_adj=0; }
else {
if(ErrorKT>(kK_Pre*vKT)) { EKT_adj=ErrorKT-kK_Pre*vKT; plEKT_adj=0; }
else{ EKT_adj=kK_Pre*vKT-ErrorKT; plEKT_adj=1; }
}
}
if(plEKT_adj)//re
{
if((pKhPWM+(EKT_adj)>>1)<MaxCounHeat) pKhPWM+=((EKT_adj)>>1);
}
else
{
if(pKhPWM>((EKT_adj)>>1)) pKhPWM-=((EKT_adj)>>1);
}
Last_temKT=temKT;
if(40>(EKT_adj)>>3)kK_Pre=(40-(EKT_adj>>3));
}
if((CountHeat>pPhPWM)&&(temPT<0x5D0)) PHeaterOn;
else if(CountHeat<pPhPWM) PHeaterOff;
if((CountHeat>pHhPWM)&&(temHT<0x5D0)) HHeaterOn;
else if(CountHeat<pHhPWM) HHeaterOff;
if((CountHeat>pKhPWM)&&(temKT<0x5D0)) KHeaterOn;
else if(CountHeat<pKhPWM) KHeaterOff;
CountHeat++;
}
main()
{
uchar idata temk;
SP=0x4F;
InitSys();
while(1)
{
if(setitem==0)
{
Ttick=CountT;
temk=GetKey();
switch(temk)
{
case NoKeyPressed: nop; break;
case KeySetPressed: { setitem=1; } break;
case KeyHeatPressed: { if(Heating)Heating=0; else Heating=1; } break;
case KeyUpPressed: { PassWordCnt++; } break;
case KeyDnPressed: { PwDeal(); } break;
case KeySetLasted: { setitem=4; } break;
case KeyHeatLasted: nop; break;
case KeyUpLasted: { setitem=6; } break;
case KeyDnLasted: { setitem=5; } break;
case KeyRollPressed: { TankSel++; if(TankSel>2)TankSel=0;} break;
case KeyMultiPressed: nop; break;
default: nop; break;
}
SetMenuDeal();
RefreshSegLed();
if(TankSel==0) { ShowT(temPT);BLedPiaoOff=0; BLedHongOff=1; BLedKaoOff=1; }
if(TankSel==1) { ShowT(temKT);BLedPiaoOff=1; BLedHongOff=0; BLedKaoOff=1; }
if(TankSel==2) { ShowT(temHT);BLedPiaoOff=1; BLedHongOff=1; BLedKaoOff=0; }
Ttick_cmp=Ttick;
}
else BLedTestOff=1;
if((setitem>0)&&(setitem<4)) SetMenuDeal();
if(setitem==4) ShowVerMenu();
if(setitem==5) RuntimeMenu();
if(setitem==6) ErrorRocMenu();
HeatDeal();
ErrorDeal();
}
nop;
} {:titter:}cool呵! 非常难得的资料,像这样的有实例有理论的东西,
请莫老大给条裤子!!! coleyao 发表于 2012-12-10 06:28 static/image/common/back.gif
个人觉得预测式负反馈才是原先的所谓PID算法的精髓所在,因此原先写过一篇名为“让PID成为历史”的帖子,点 ...
现在有那个帖子的链接吗,想瞧瞧{:smile:} ding{:smile:} YOU1 发表于 2012-12-10 20:10 static/image/common/back.gif
现在有那个帖子的链接吗,想瞧瞧
在论坛左侧把鼠标停留在要查看资料的作者图标上,点开那个小图标“详细资料”,然后查看主题,就可以看到所有该作者发的帖子了! 谢谢ColeYao的无私奉献!
参数自整定和最大温升速率相关之间很难整,没有找到最合适的关系. 10度/M---1度/6S,时间已知,功率已知,那么上升1度的热能就知道了,但将热能和温度拉上关系会很麻烦,因为要涉及到比热. 通过仿真软件的学习,以及楼主提供的资料, 温差和功率之间存在着不明不白的关系(是指超调后)!我觉得超过设置线,仿真软件似乎是按时间值回调功率值的?!如果按温差,e(t)>0后,变化0.1或1度,如何知道该回调多少功率呢?!
有些场合,往往要求第一次必须超调(融化的快些) 楼主提供的代码或许有答案(太晚了,明天看). Qhjh 发表于 2012-12-11 01:02
谢谢ColeYao的无私奉献!
参数自整定和最大温升速率相关之间很难整,没有找到最合适的关系. 10度/M---1度/6S, ...
—般不采用超调的方式,通常设—个预热期,预热温度会比设定温度略高,时间可单独设置,采用超调方式有点难兼故每—个指标的。
coleyao 发表于 2012-12-10 20:45 static/image/common/back.gif
在论坛左侧把鼠标停留在要查看资料的作者图标上,点开那个小图标“详细资料”,然后查看主题,就可以看到 ...
找到了谢谢{:smile:} ,菜鸟学习一下 {:smile:}谢谢ColeYao的无私奉献!
不知您的代码中两个系数PreK等是怎么测出来的? coleyao
谢谢了 正在做一个温控的东西 可以尝试用pid的方式 收藏,最近在做温控系统,滞后很严重。希望能用楼主的算法成功。 {:smile:}最近正在学习电机控制恒速, 讲解很直观. 多谢分享 coleyao 发表于 2012-12-10 06:04
呵呵,线性预测的公式是 ERRTadj=FdK*(ERRT+PreK*vT);也就是对ERRT作了一定程度的预测,预测深度是PreK; ...
自整定的控制算法能指教一下嘛? 学习学习啊 学习啊学习啊 chinaboy25 发表于 2020-3-27 09:40
自整定的控制算法能指教一下嘛?
真的很难找啊!这个自整定PID。 学习一下
页:
[1]