增量式pid和位置式pid相比各有什么优缺点?(https://www.zhihu.com/question/32678336)
链接:https://www.zhihu.com/question/32678336/answer/80506140
来源:知乎
著作权归作者所有,转载请联系作者获得授权。
仅考虑PI调节器,PID类似。
请参考机械工业出版社, 阮毅、陈伯时主编的 《电力拖动自动控制系统:运动控制系统(第4版)》, 第46页:
- 位置式PI:
可以看出,比例部分只与 当前的偏差有关,而积分部分则是系统 过去所有偏差的累积。位置式PI调节器的结构清晰,P和I两部分作用分明,参数调整简单明了。
但直观上看,要计算第
然而在具体编程操作中,可在每一拍对积分部分进行累积,再加上当前拍的比例部分,即为当前
- 增量式PI:
两式相减,可得出PI调节器输出 增量
上式仅仅为增量,只需要 当前的和上一拍的偏差即可得出结果,不需要存储每一拍的偏差,因此占内存空间小,这也是普遍认为的增量式的优点。
然而很多场合下需要的往往不只增量,还有上一拍的输出值,于是可知增量式PI调节器算法为
由于
- 结论:
可得
代入上式即可约去
因此,可以理解为无论用增量叠加的方式来计算位置式PI,还是直接计算,结果都是相同的。 两者唯一的区别就是位置式PI需要同时设置积分限幅和输出限幅,而增量式PI只需输出限幅。
arduino PID函数
bool PID::Compute()
{
if(!inAuto) return false;
unsigned long now = millis();
unsigned long timeChange = (now - lastTime);
if(timeChange>=SampleTime)
{
/*Compute all the working error variables*/
double input = *myInput;
double error = *mySetpoint - input;
ITerm+= (ki * error);
if(ITerm > outMax) ITerm= outMax;
else if(ITerm < outMin) ITerm= outMin;
double dInput = (input - lastInput);
/*Compute PID Output*/
double output = kp * error + ITerm- kd * dInput;
if(output > outMax) output = outMax;
else if(output < outMin) output = outMin;
*myOutput = output;
/*Remember some variables for next time*/
lastInput = input;
lastTime = now;
return true;
}
else return false;
}
【
这里微分项采用的是dInput = (input - lastInput),调整的目的是消除称为“Derivative Kick”的现象。--http://tedeum.iteye.com/blog/1797229】
/* SetTunings(...)*************************************************************
* This function allows the controller's dynamic performance to be adjusted.
* it's called automatically from the constructor, but tunings can also
* be adjusted on the fly during normal operation
******************************************************************************/
void PID::SetTunings(double Kp, double Ki, double Kd)
{
if (Kp<0 || Ki<0 || Kd<0) return;
dispKp = Kp; dispKi = Ki; dispKd = Kd;
double SampleTimeInSec = ((double)SampleTime)/1000;
kp = Kp;
ki = Ki * SampleTimeInSec;
kd = Kd / SampleTimeInSec;
if(controllerDirection ==REVERSE)
{
kp = (0 - kp);
ki = (0 - ki);
kd = (0 - kd);
}
}
/* SetSampleTime(...) *********************************************************
* sets the period, in Milliseconds, at which the calculation is performed
******************************************************************************/
void PID::SetSampleTime(int NewSampleTime)
{
if (NewSampleTime > 0)
{
double ratio = (double)NewSampleTime
/ (double)SampleTime;
ki *= ratio;
kd /= ratio;
SampleTime = (unsigned long)NewSampleTime;
}
}
PID调节经验 (http://blog.csdn.net/zyboy2000/article/details/9418257/)
类似的:http://www.openedv.com/posts/list/36701.htm
Kp: 比例系数 ----- 比例带(比例度)P:输入偏差信号变化的相对值与输出信号变化的相对值之比的百分数表示 (比例系数的倒数)
T:采样时间
Ti: 积分时间
Td: 微分时间
温度T: P=20~60%,Ti=180~600s,Td=3-180s
压力P: P=30~70%,Ti=24~180s,
液位L: P=20~80%,Ti=60~300s,
流量L: P=40~100%,Ti=6~60s。
(1)一般来说,在整定中,观察到曲线震荡很频繁,需把比例带增大以减少震荡;当曲线最大偏差大且趋于非周期过程时,需把比例带减少
(2)当曲线波动较大时,应增大积分时间;曲线偏离给定值后,长时间回不来,则需减小积分时间,以加快消除余差。
(3)如果曲线震荡的厉害,需把微分作用减到最小,或暂时不加微分;曲线最大偏差大而衰减慢,需把微分时间加长而加大作用
(4)比例带过小,积分时间过小或微分时间过大,都会产生周期性的激烈震荡。积分时间过小,震荡周期较长;比例带过小,震荡周期较短;微分时间过大,震荡周期最短
(5)比例带过大或积分时间过长,都会使过渡过程变化缓慢。比例带过大,曲线如不规则的波浪较大的偏离给定值。积分时间过长,曲线会通过非周期的不正常途径,慢慢回复到给定值。
注意:当积分时间过长或微分时间过大,超出允许的范围时,不管如果改变比例带,都是无法补救的
1. PID调试步骤
没有一种控制算法比PID调节规律更有效、更方便的了。现在一些时髦点的调节器基本源自PID。甚至可以这样说:PID调节器是其它控制调节算法的吗。
为什么PID应用如此广泛、又长久不衰?
因为PID解决了自动控制理论所要解决的最基本问题,既系统的稳定性、快速性和准确性。调节PID的参数,可实现在系统稳定的前提下,兼顾系统的带载能力和抗扰能力,同时,在PID调节器中引入积分项,系统增加了一个零积点,使之成为一阶或一阶以上的系统,这样系统阶跃响应的稳态误差就为零。
由于自动控制系统被控对象的千差万别,PID的参数也必须随之变化,以满足系统的性能要求。这就给使用者带来相当的麻烦,特别是对初学者。下面简单介绍一下调试PID参数的一般步骤:
1.负反馈
自动控制理论也被称为负反馈控制理论。首先检查系统接线,确定系统的反馈为负反馈。例如电机调速系统,输入信号为正,要求电机正转时,反馈信号也为正(PID算法时,误差=输入-反馈),同时电机转速越高,反馈信号越大。其余系统同此方法。
2.PID调试一般原则
a.在输出不振荡时,增大比例增益P。
b.在输出不振荡时,减小积分时间常数Ti。
c.在输出不振荡时,增大微分时间常数Td。
3.一般步骤
a.确定比例增益P
确定比例增益P 时,首先去掉PID的积分项和微分项,一般是令Ti=0、Td=0(具体见PID的参数设定说明),使PID为纯比例调节。输入设定为系统允许的最大值的60%~70%,由0逐渐加大比例增益P,直至系统出现振荡;再反过来,从此时的比例增益P逐渐减小,直至系统振荡消失,记录此时的比例增益P,设定PID的比例增益P为当前值的60%~70%。比例增益P调试完成。
b.确定积分时间常数Ti
比例增益P确定后,设定一个较大的积分时间常数Ti的初值,然后逐渐减小Ti,直至系统出现振荡,之后在反过来,逐渐加大Ti,直至系统振荡消失。记录此时的Ti,设定PID的积分时间常数Ti为当前值的150%~180%。积分时间常数Ti调试完成。
c.确定微分时间常数Td
积分时间常数Td一般不用设定,为0即可。若要设定,与确定 P和Ti的方法相同,取不振荡时的30%。
d.系统空载、带载联调,再对PID参数进行微调,直至满足要求。
2.PID控制简介
目前工业自动化水平已成为衡量各行各业现代化水平的一个重要标志。同时,控制理论的发展也经历了古典控制理论、现代控制理论和智能控制理论三个阶段。智能控制的典型实例是模糊全自动洗衣机等。自动控制系统可分为开环控制系统和闭环控制系统。一个控制系统包括控制器﹑传感器﹑变送器﹑执行机构﹑输入输出接口。控制器的输出经过输出接口﹑执行机构﹐加到被控系统上﹔控制系统的被控量﹐经过传感器﹐变送器﹐通过输入接口送到控制器。不同的控制系统﹐其传感器﹑变送器﹑执行机构是不一样的。比如压力控制系统要采用压力传感器。电加热控制系统的传感器是温度传感器。目前,PID控制及其控制器或智能PID控制器(仪表)已经很多,产品已在工程实际中得到了广泛的应用,有各种各样的PID控制器产品,各大公司均开发了具有PID参数自整定功能的智能调节器(intelligent regulator),其中PID控制器参数的自动调整是通过智能化调整或自校正、自适应算法来实现。有利用PID控制实现的压力、温度、流量、液位控制器,能实现PID控制功能的可编程控制器(PLC),还有可实现PID控制的PC系统等等。 可编程控制器(PLC) 是利用其闭环控制模块来实现PID控制,而可编程控制器(PLC)可以直接与ControlNet相连,如Rockwell的PLC-5等。还有可以实现PID控制功能的控制器,如Rockwell 的Logix产品系列,它可以直接与ControlNet相连,利用网络来实现其远程控制功能。
1、开环控制系统
开环控制系统(open-loop control system)是指被控对象的输出(被控制量)对控制器(controller)的输出没有影响。在这种控制系统中,不依赖将被控量反送回来以形成任何闭环回路。
2、闭环控制系统
闭环控制系统(closed-loop control system)的特点是系统被控对象的输出(被控制量)会反送回来影响控制器的输出,形成一个或多个闭环。闭环控制系统有正反馈和负反馈,若反馈信号与系统给定值信号相反,则称为负反馈( Negative Feedback),若极性相同,则称为正反馈,一般闭环控制系统均采用负反馈,又称负反馈控制系统。闭环控制系统的例子很多。比如人就是一个具有负反馈的闭环控制系统,眼睛便是传感器,充当反馈,人体系统能通过不断的修正最后作出各种正确的动作。如果没有眼睛,就没有了反馈回路,也就成了一个开环控制系统。另例,当一台真正的全自动洗衣机具有能连续检查衣物是否洗净,并在洗净之后能自动切断电源,它就是一个闭环控制系统。
3、阶跃响应
阶跃响应是指将一个阶跃输入(step function)加到系统上时,系统的输出。稳态误差是指系统的响应进入稳态后﹐系统的期望输出与实际输出之差。控制系统的性能可以用稳、准、快三个字来描述。稳是指系统的稳定性(stability),一个系统要能正常工作,首先必须是稳定的,从阶跃响应上看应该是收敛的﹔准是指控制系统的准确性、控制精度,通常用稳态误差来(Steady-state error)描述,它表示系统输出稳态值与期望值之差﹔快是指控制系统响应的快速性,通常用上升时间来定量描述。
4、PID控制的原理和特点
在工程实际中,应用最为广泛的调节器控制规律为比例、积分、微分控制,简称PID控制,又称PID调节。PID控制器问世至今已有近70年历史,它以其结构简单、稳定性好、工作可靠、调整方便而成为工业控制的主要技术之一。当被控对象的结构和参数不能完全掌握,或得不到精确的数学模型时,控制理论的其它技术难以采用时,系统控制器的结构和参数必须依靠经验和现场调试来确定,这时应用PID控制技术最为方便。即当我们不完全了解一个系统和被控对象﹐或不能通过有效的测量手段来获得系统参数时,最适合用PID控制技术。PID控制,实际中也有PI和PD控制。PID控制器就是根据系统的误差,利用比例、积分、微分计算出控制量进行控制的。
比例(P)控制
比例控制是一种最简单的控制方式。其控制器的输出与输入误差信号成比例关系。当仅有比例控制时系统输出存在稳态误差(Steady-state error)。
积分(I)控制
在积分控制中,控制器的输出与输入误差信号的积分成正比关系。对一个自动控制系统,如果在进入稳态后存在稳态误差,则称这个控制系统是有稳态误差的或简称有差系统(System with Steady-state Error)。为了消除稳态误差,在控制器中必须引入“积分项”。积分项对误差取决于时间的积分,随着时间的增加,积分项会增大。这样,即便误差很小,积分项也会随着时间的增加而加大,它推动控制器的输出增大使稳态误差进一步减小,直到等于零。因此,比例+积分(PI)控制器,可以使系统在进入稳态后无稳态误差。
微分(D)控制
在微分控制中,控制器的输出与输入误差信号的微分(即误差的变化率)成正比关系。 自动控制系统在克服误差的调节过程中可能会出现振荡甚至失稳。其原因是由于存在有较大惯性组件(环节)或有滞后(delay)组件,具有抑制误差的作用,其变化总是落后于误差的变化。解决的办法是使抑制误差的作用的变化“超前”,即在误差接近零时,抑制误差的作用就应该是零。这就是说,在控制器中仅引入“比例”项往往是不够的,比例项的作用仅是放大误差的幅值,而目前需要增加的是“微分项”,它能预测误差变化的趋势,这样,具有比例+微分的控制器,就能够提前使抑制误差的控制作用等于零,甚至为负值,从而避免了被控量的严重超调。所以对有较大惯性或滞后的被控对象,比例+微分(PD)控制器能改善系统在调节过程中的动态特性。
5、PID控制器的参数整定
PID控制器的参数整定是控制系统设计的核心内容。它是根据被控过程的特性确定PID控制器的比例系数、积分时间和微分时间的大小。PID控制器参数整定的方法很多,概括起来有两大类:一是理论计算整定法。它主要是依据系统的数学模型,经过理论计算确定控制器参数。这种方法所得到的计算数据未必可以直接用,还必须通过工程实际进行调整和修改。二是工程整定方法,它主要依赖工程经验,直接在控制系统的试验中进行,且方法简单、易于掌握,在工程实际中被广泛采用。PID控制器参数的工程整定方法,主要有临界比例法、反应曲线法和衰减法。三种方法各有其特点,其共同点都是通过试验,然后按照工程经验公式对控制器参数进行整定。但无论采用哪一种方法所得到的控制器参数,都需要在实际运行中进行最后调整与完善。现在一般采用的是临界比例法。利用该方法进行 PID控制器参数的整定步骤如下:(1)首先预选择一个足够短的采样周期让系统工作﹔(2)仅加入比例控制环节,直到系统对输入的阶跃响应出现临界振荡,记下这时的比例放大系数和临界振荡周期﹔(3)在一定的控制度下通过公式计算得到PID控制器的参数。
3.PID控制器参数的工程整定,各种调节系统中PID参数经验数据以下可参照:
温度T: P=20~60%,T=180~600s,D=3-180s
压力P: P=30~70%,T=24~180s,
液位L: P=20~80%,T=60~300s,
流量L: P=40~100%,T=6~60s。
4. PID常用口诀:
参数整定找最佳,从小到大顺序查
先是比例后积分,最后再把微分加
曲线振荡很频繁,比例度盘要放大
曲线漂浮绕大湾,比例度盘往小扳
曲线偏离回复慢,积分时间往下降
曲线波动周期长,积分时间再加长
曲线振荡频率快,先把微分降下来
动差大来波动慢。微分时间应加长
理想曲线两个波,前高后低4比1
一看二调多分析,调节质量不会低
PID 控制 PWM 輸出方式 加熱區及冷卻區恆溫控制 (http://www.openedv.com/forum.php?mod=viewthread&tid=21281&highlight=PID)
/*
变量名
Pp(K) ;比例输出
Pi(K) ;积分输出
Pd(K) ;微分输出
Kp ;比例系数
Ki ;积分系数
Kd ;微分系数
E(K) ;本次误差值
R(K) ;本次设定值
M(K) ;本次测量值
E(K-1);上次误差值
E(K-2);上上次误差值
Pi(K-1);上次积分输出
;位置型PID算法:
E(K)=R(K)-M(K) ;本次误差=本次设定值-本次测量值
Pp(K)=Kp*E(K) ;本次比例输出=比例系数×本次误差值
Pi(K)=Ki*E(K)+Pi(K-1) ;本次积分输出=积分系数×本次误差值+上次积分输出值
Pd(K)=Kd[E(K)-E(K-1)] ;本次微分输出=微分系数×(本次误差值-上次误差值)
P(K)=Pp(K)+Pi(K)+Pd(K) ;输出值=本次比例输出+本次积分输出+本次微分输出
位置型PID计算公式
;增量型PID算法:
E(K)=R(K)-M(K) ;本次误差=本次设定值-本次测量值
Pp(K)=Kp[E(K)-E(K-1)] ;本次比例输出=比例系数×(本次误差值-上次误差值)
Pi(K)=Ki*E(K) ;本次积分输出=积分系数×本次误差
Pd(K)=Kd[E(K)-2E(K-1)+E(K-2) ;本次微分输出=微分系数×(本次误差值-2×上次误差值+上上次误差值)
P(K)=Pp(K)+Pi(K)+Pd(K) ;输出值=本次比例输出+本次积分输出+本次微分输出
//增量法计算公式:
//Pdt=Kp*[E(t)-E(t-1)]+Ki*E(t)+Kd*[E(t)-2*E(t-1)+E(t-2)]
增量式PID算法的输出量为
ΔUn = Kp[(en-en-1)+(T/Ti)en+(Td/T)(en-2*en-1+en-2)]
*/
/************************************************************************
**位置PID的 KP,KI,KD参数;
**在调试过程中,只对KP,KI,进行了调节,对KP,KI有了一点认识,但对KD仍然没有什么认识
**在本组参数中,只设置了KP。
**同时现在给定的理想值是实际的电机转动过程中输出的脉冲数。
*************************************************************************/
u16 PID_Parameter[90]; //PID 儲存參數
struct PID PID1,PID2,PID3,PID4,PID5,PID6,PID7,PID8;
float HeaterTemp0; //加熱器 上次0量測到溫度 Temperature
float HeaterTemp1; //加熱器 上次1量測到溫度 Temperature
float HeaterTemp2; //加熱器 上次2量測到溫度 Temperature
float HeaterTemp3; //加熱器 上次3量測到溫度 Temperature
float HeaterTemp4; //加熱器 上次4量測到溫度 Temperature
float HeaterAverage1; //加熱器量測到溫度 上次1平均值
float HeaterAverage2; //加熱器量測到溫度 上次2平均值
float HeaterAverage3; //加熱器量測到溫度 上次3平均值
float HeaterAverage4; //加熱器量測到溫度 上次4平均值
float HeaterSumErr; //加熱器 PID 控制參數 : 累積溫度誤差總和值預設值
float HeaterRate; //加熱器 PID 控制參數 : 實際輸出比例值 ( 第 1 段溫度 )
float HeaterRate2; //加熱器 PID 控制參數 : 實際輸出比例值2 ( 第 2 段溫度 )
u16 HeaterI_Set; //加熱器 PID 控制參數 : 積分時間 計數設定
u16 HeaterD_Set; //加熱器 PID 控制參數 : 微分時間 計數設定
float FanSpeed=1000; //設定手動風扇速度測試 0~1000
u8 HeaterI_Count; //加熱器 積分時間 計數器
u8 HeaterD_Count; //加熱器 微分時間 計數器
u8 TempUpDw; //加熱器 溫度上升或是下降旗標
u8 TempUpDwCount; //加熱器 溫度上升或是下降 檢測時間 計數器 1秒檢測一次
u8 HeaterSumErrFg; //加熱器 Kp 積分項 累積溫度誤差總和值預設值
/*====================================================================================================/
PID1 PWM1 TIM4 CH1 PB6 Temp.13~17 Heater
=====================================================================================================*/
void PID_DataDefault(void) //PID1 參數 出廠預設值
{ //PID=100000 PWM=1000 =1/100
// 加熱器 出廠預設值 PWM200~300 = 300~500*60%
PID1.TargetTemp =9600; // 9600 設定目標溫度值 (40000) PWM400
PID1.Kp=180; //;比例常数Proportional Const //[ 100x150=150,00 ; 15% ] ; [ 75000 / 75%]
PID1.Ki=12; // 积分常数Integral Const //[ 5000*10=50,00 ; 0~50 %] ; [ / 50 %* 60 % Out=300 ]
PID1.Kd=50; // 50 微分常数Derivative Const //[PID: 100*100=10,00 ; =+- 5 %]
PID1.Keep=15; // 10 設定保持最低輸出值 //[15*1000=100,00 ; 15%] [20%]
HeaterI_Set=6; // 6 加熱器 PID 控制參數 : 積分時間 計數設定 6*250ms=1秒
HeaterD_Set=12; //12 加熱器 PID 控制參數 : 微分時間 計數設定 12*250ms=3秒
HeaterRate=60; // 60 加熱器 PID 控制參數 : 實際輸出比例值 ( 第 1 段溫度 )
HeaterSumErr=3000; //加熱器 PID 控制參數 : 累積溫度誤差總和值預設值
HeaterRate2=80; // 60 加熱器 PID 控制參數 : 實際輸出比例值2 ( 第 2 段溫度 )
//風扇1 試管1~3環境溫度 出廠預設值
PID2.TargetTemp=6500; //設定目標溫度值
PID2.Kp=150; // 比例常数Proportional Const [200x150=30000 =300/1000 =30% ]
PID2.Ki=10; // 积分常数Integral Const [5000*10=50000 500/1000 =50% ]
PID2.Kd=10; // 微分常数Derivative Const [100*10=1000 ;=10/1000 =+-10%]
PID2.Keep=30; //設定保持最低輸出值
}
/*====================================================================================================/
PID1 程式
=====================================================================================================*/
void PID1_Init(void)
{
//PID=100000 PWM=1000 =1/100
PID1.TargetTemp =PID_Parameter[0]; //9700 設定目標溫度值
PID1.Kp=PID_Parameter[1]; //100 比例常数Proportional Const //[100x100=10000 /100=100 (0.15)]
PID1.Ki=PID_Parameter[2]; // 3积分常数Integral Const //[2000*5=10000/100=100 (0.1)] (0.5 20=10s )
PID1.Kd=PID_Parameter[3]; //50 微分常数Derivative Const //[25*200=5000 /100=50 (+_0.05)] Max=0.1
PID1.Keep=PID_Parameter[4]; //設定保持最低輸出值 //[100/1000 (0.1)]
PID1.Error0=0.0; //目前誤差值
PID1.Error1=0.0; // Error[-1] 上次误差
PID1.SumError = 0; // HeaterSumErr; //累積溫度誤差總和值
PID1.OutputValue=0 ; //实际输出量
PID1.TargetValue =PID1.TargetTemp ; // 设定目标值Desired value Target
}
void PID1_Control(void) //Temp.13~17 Heater
{
//加熱器 控制方式:1 取加熱器溫度感溫棒13, 加熱器中心感溫棒溫度,4次平均值, 加熱週期1秒
MAX31855_13_Read(); //加熱器中心溫度顯示
HeaterTemp4 = HeaterTemp3; //加熱器 上次4量測到溫度 Temperature
HeaterTemp3 = HeaterTemp2; //加熱器 上次3量測到溫度 Temperature
HeaterTemp2 = HeaterTemp1; //加熱器 上次2量測到溫度 Temperature
HeaterTemp1 = HeaterTemp0 ; //加熱器 上次1量測到溫度 Temperature
HeaterTemp0 = MAX31855_13.Thermocouple; //加熱器 上次0量測到溫度 Temperature
PID1.NowTemp=(HeaterTemp0 + HeaterTemp1+ HeaterTemp2+ HeaterTemp3)/4; //控制現在溫度值 ; //加熱器現在量測到溫度 Temperature
// 溫度上升或是下降 檢測
TempUpDwCount++; //溫度上升或是下降 檢測時間 計數器 1秒檢測一次
if (TempUpDwCount>3)
{
if (( PID1.NowTemp > HeaterAverage1 - 30 ) && ( PID1.NowTemp < HeaterAverage1+ 30 ) &&
( PID1.NowTemp> HeaterAverage2 - 30 ) && ( PID1.NowTemp < HeaterAverage2 + 30 )) TempUpDw=0; //溫度上升下降 旗標
if (( PID1.NowTemp < HeaterAverage1 ) && ( PID1.NowTemp < HeaterAverage2 - 25 )) TempUpDw=1 ; //溫度下降 旗標
if (( PID1.NowTemp > HeaterAverage2 ) && ( PID1.NowTemp > HeaterAverage2 + 25 )) TempUpDw=2 ; //溫度上升旗標
HeaterAverage4 = HeaterAverage3; //加熱器量測到溫度 平均值 4
HeaterAverage3 = HeaterAverage2; //加熱器量測到溫度 平均值 3
HeaterAverage2 = HeaterAverage1; //加熱器量測到溫度 平均值 2
HeaterAverage1 = PID1.NowValue; //加熱器量測到溫度 平均值 1
TempUpDwCount=0; //加熱器 溫度上升或是下降 檢測時間 計數器 1秒檢測一次
}
if((PCR_Status==2||Man_HeaterFg==1)&&(MAX31855_14.Thermocouple<PID1.TargetTemp+1000)&&(MAX31855_16.Thermocouple<PID1.TargetTemp+1000)) //加熱器 溫度控制運轉條件檢查
{ // 加熱器 溫度控制運轉條件檢查OK
PID1.NowValue=PID1.NowTemp; //控制現在溫度值
PID1.TargetValue=PID1.TargetTemp; //控制目標溫度值
if (PID1.NowTemp < PID1.TargetTemp - 1000) PID1.PWMResult=1000; //(0~10000) 溫度過低 PID運算範圍外 , PWM 輸出量 暫存值 //加熱器開始溫度輸出量
else if (PID1.NowTemp<PID1.TargetTemp - 500) PID1.PWMResult= HeaterRate2*10; //(0~10000) 溫度過低 PID運算範圍外 , PWM 輸出量 暫存值 //加熱器開始溫度輸出量
else if (PID1.NowTemp>PID1.TargetTemp + 300) PID1.PWMResult=0; //溫度過高 PID運算範圍外 , PWM 輸出量 暫存值
else
{
PID1_Calculate(); //位置PID计算
PID1.PWMResult=(PID1.OutputValue*HeaterRate2)/100/100; //溫度上升中; PID 運算 (0~100000/0~1000)=100 //PID 運算範圍內 輸出值 // PID運算範圍內
}
PID1.PWMOut=(PID1.PWMResult*HeaterRate)/100; //加熱器 溫度控制運轉條件檢查OK; PWM 輸出量 實際輸出值 //
}
else PID1.PWMOut=0; //加熱器 溫度控制運轉條件不合;關閉加熱器溫度 PWM=0 , TIM4_CH1 PB6 PWM1 PWM1.OutValue Rate = 0~10000
TIM_SetCompare1(TIM4,PID1.PWMOut); //輸出到 PWM1占空比 /TIM4_CH1 PB6 PWM1 PWM1.OutValue Rate = 0~10000
}
/*====================================================================================================/
PID1计算部分
=====================================================================================================*/
/*
位置型PID算法:
E(K)=R(K)-M(K) ;本次誤差值=本次設定值-本次量測值
Pp(K)=Kp*E(K) ;本次比例輸出值 =比例增益係數×本次誤差值
Pi(K)=Ki*E(K)+Pi(K-1) ;本次積分輸出值=積分增益係數 ×本次誤差值+上次積分輸出值 (累積溫度誤差總和值, SumErro)
Pd(K)=Kd[E(K)-E(K-1)] ;本次微分輸出值=微分增益係數×(本次誤差值-上次誤差值)
P(K)=Pp(K)+Pi(K)+Pd(K) ;PID輸出值 = 本次比例輸出值+本次積分輸出值+本次微分輸出
*/
void PID1_Calculate(void) //位置PID计算
{
HeaterI_Count++; //加熱器 積分時間 計數器
HeaterD_Count++; //加熱器 微分時間 計數器
/*===PID1誤差總和值預設值===*/
if (( HeaterSumErrFg==0 ) && ( PID1.NowTemp > PID1.TargetTemp -400 ) && ( PID1.NowTemp < PID1.TargetTemp+100 ) && ( TempUpDw !=2 ))
{
PID1.SumError = HeaterSumErr; //加熱器 PID 控制參數 : 累積溫度誤差總和值預設值
HeaterSumErrFg=1; // 累積溫度誤差總和值預設值旗標
}
/*===PID1比例項 計算式===*/
PID1.Error0 = PID1.TargetValue-PID1.NowValue ; //目前誤差值 = 目前溫度控制設定值 - 現在溫度感測值 ;目前誤差值 本次误差=本次设定值-本次测量值
PID1.KpValue = PID1.Kp*PID1.Error0; //比例項 本次比例输出=比例系数×本次误差值 pError=Error-pp->LastError;
/*===PID1 積分項 計算式===*/
if (HeaterI_Count>HeaterI_Set) //檢查積分時間是否到達
{
if ( PID1.NowTemp < PID1.TargetTemp - 25 ) //溫度過低時,少量增加
{
if ( TempUpDw == 0 ) PID1.SumError=PID1.SumError+20; //累積誤差總合值
if ( TempUpDw == 1 ) PID1.SumError+= PID1.Error0; //累積誤差總合值 本次积分输出=积分系数×本次误差值+上次积分输出值
}
if ( PID1.NowTemp > PID1.TargetTemp +25 ) // 溫度過高
{
if ( TempUpDw == 0 ) PID1.SumError=PID1.SumError-20; // 溫度過高時,少量減少
if ( TempUpDw == 2 ) PID1.SumError+= PID1.Error0; //累積誤差總合值 本次积分输出=积分系数×本次误差值+上次积分输出值
}
if (PID1.SumError>5000) PID1.SumError=5000; //累積誤差總和 最大值 HeaterSumMax ; SumError=10000/100=100次
if (PID1.SumError<-1000) PID1.SumError=-1000; //累積誤差總合最小值
PID1.KiValue = PID1.Ki*PID1.SumError; //積分項 本次积分输出=积分系数×本次误差值+上次积分输出值 E(t) //pp->SumError += Error
HeaterI_Count=0; //積分時間
}
/*===PID1 微分項 計算式===*/
if(HeaterD_Count>HeaterD_Set) //檢查微分時間是否到達
{
PID1.KdValue = PID1.Kd*(PID1.Error0-PID1.Error1); //微分項 本次微分输出=微分系数×(本次误差值-上次误差值)dError = pp->LastError - pp->PrevError
PID1.Error1 = PID1.Error0;//保存上1次誤差; PID1 誤差值儲存
HeaterD_Count=0; //微分時間
}
/*===PID1 輸出值 ===*/
PID1.ResultValue = PID1.KpValue + PID1.KiValue + PID1.KdValue ; //Kp+Ki+Kd 運算結果暫存值
if ( TempUpDw == 1 ) PID1.OutputValue=PID1.ResultValue + PID1.Keep*1000; //溫度下降時,立即基本加溫
else PID1.OutputValue=PID1.ResultValue;
if (PID1.OutputValue >100000) PID1.OutputValue = 100000; //PWM 實際輸出最大值限幅
if ( PID1.OutputValue < 0 ) PID1.OutputValue = 0; //PWM 實際輸出最最小值限幅
if (( PID1.NowTemp > PID1.TargetTemp + 75 ) && ( TempUpDw == 2 )) PID1.OutputValue=0; //溫度過高 0.75 度 ;停止加熱器 PID 運算後 輸出值
if ( PID1.NowTemp > PID1.TargetTemp + 200 ) PID1.OutputValue=0; //溫度過高 2 度 ;停止加熱器 PID 運算後 輸出值
}
/*====================================================================================================/
PID2 程式 PWM2 TIM3 CH1 PC6 Tube 1~3 Fan1
=====================================================================================================*/
void PID2_Init(void)
{
PID2.TargetTemp =PID_Parameter[10]; //6100 設定目標溫度值
PID2.Kp=PID_Parameter[11]; //100 比例常数Proportional Const
PID2.Ki=PID_Parameter[12]; //1 积分常数Integral Const
PID2.Kd=PID_Parameter[13]; //1 微分常数Derivative Const
PID2.Keep=PID_Parameter[14]; //100設定保持最低輸出值
PID2.Error0=0.0; //目前誤差值
PID2.Error1=0.0; // Error[-1] 上次误差
PID2.SumError =0.0; //累積誤差總合值
PID2.OutputValue=0.0 ; //实际输出量
PID2.TargetValue =PID2.TargetTemp ; // 设定目标值Desired value Target
}
void PID2_Control(void) //PID2 風扇1 感溫棒2 控制 Temp. 1~6 Fan1,2
{
MAX31855_2_Read(); //風扇1 溫度顯示
PID2.NowTemp=MAX31855_2.Thermocouple; //PWM2
PID2.NowValue=PID2.NowTemp; //控制現在溫度值
PID2.TargetValue=PID2.TargetTemp; //控制目標溫度值
PID2_Calculate(); // float PID_calculate( struct PID *pid_1,float NowValue ); //位置PID计算
if(PID2.NowTemp<PID2.TargetTemp-200) PID2.PWMResult=0;
else if((PID2.NowTemp>=PID2.TargetTemp-200)&&(PID2.NowTemp<PID2.TargetTemp)) PID2.PWMResult=PID2.Keep; //風扇最低保持轉速
else
{
PID2.PWMResult=PID2.OutputValue/100+PID2.Keep; //PID 控制範圍 0~1000 / 0~100000
}
PID2.PWMOut=PID2.PWMResult;
if(Man_FanFg==1) PID2.PWMOut=FanSpeed; //Fan1 手動測試
TIM_SetCompare1(TIM3,PID2.PWMOut); //Fan1 TIM3_CH1 PB6 PWM2 PWM2.OutValue Rate = 0~1000
}
/*====================================================================================================/
PID2计算部分
=====================================================================================================*/
void PID2_Calculate(void)//位置PID计算
{
PID2.Error0 =PID2.NowValue-PID2.TargetValue; //目前誤差值
/*===PID2比例項 計算式===*/
PID2.KpValue = PID2.Kp*PID2.Error0 ; //比例项 本次比例输出=比例系数×本次误差值 pError=Error-pp->LastError;
/*===PID2 積分項 計算式===*/
PID2.SumError+=PID2.Error0; //累積誤差總合值 本次积分输出=积分系数×本次误差值+上次积分输出值
if(PID2.SumError>5000) PID2.SumError=5000; //累積誤差總合最大值
if(PID2.SumError<-2000) PID2.SumError=-2000; //累積誤差總合最小值
PID2.KiValue = PID2.Ki*PID2.SumError; //積分項 本次积分输出=积分系数×本次误差值+上次积分输出值 E(t) //pp->SumError += Error
/*===PID2 微分項 計算式===*/
PID2.KdValue = PID2.Kd*(PID2.Error0-PID2.Error1); //微分項 本次微分输出=微分系数×(本次误差值-上次误差值)dError = pp->LastError - pp->PrevError
PID2.Error1 = PID2.Error0;//保存上1次誤差; PID1 誤差值儲存
/*===PID2 輸出值 ===*/
PID2.ResultValue = PID2.KpValue + PID2.KiValue + PID2.KdValue;//输出值计算,注意加减
PID2.OutputValue=PID2.ResultValue;
if( PID2.OutputValue>100000) PID2.OutputValue=100000; //限幅
if (PID2.OutputValue<0) PID2.OutputValue=0;
}