位置式PID、增量式PID与经典PID控温效果比较

2020-01-12 17:28发布

本帖最后由 coleyao 于 2012-6-7 20:20 编辑

  理想的控温曲线很多人都了解是个啥样子,但要是想用PID控温,得到理想的控温曲线就没那么容易了(通常认为延时越大,升温越快就越不容易控制)。
不过有了PID温控仿真器之后,PID温控就变得很简单了,我在附件中列举了在这三种PID控温方式得到较理想控温曲线时的PID参数(这些参数在升温速率快慢、延时长短、设定温度距离环境温度远近等各种场合适应性较广),大家有空可以自己确认一下(仿真器中温度采集和控温的周期均为1秒)或者亦可尝试寻找一下各种PID控制方式下最佳的PID参数,这三种PID控制方式我个人觉得经典式PID效果最差,尽管在大延时,高升温速率下也能稳定,但控温时间长,波动较大;位置式PID次之,在升温速率30度每分钟,延时达20秒时仍有较理想的控温曲线,缺点是继续增加升温速率或延时时间则会出现振荡;增量式PID最佳,在升温速率40度每分钟,延时达20秒时仍有较理想的控温曲线,缺点同位置式PID(当然这些是我通过仿真软件得到的结论,本人并没有用增量式或位置式PID解决过实际问题,写这个仿真软件的目的一方面是为了交流和学习,另一方面是为了将PID控制的效果和其它方法如PreF_v方法作个比较,我目前在温控系统中实际用过的是改进型的PreF_v方法)。
  当然,我个人的看法是没有最好,只有更好,使用PreF_v控制方法(仅有两个参数PreK和FdK需要调整,并且本身就是时域的方法,而不是像PID那样用频域方法解决时域问题)在升温速率达到70度每分钟,延时达100秒时仍能得到较理想的控温曲线。(注:仿真软件在51分论坛上可以下载,效果请各网友自行评估。)
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
48条回答
eddia2012
1楼-- · 2020-01-18 03:15
预测式反馈式PID,实际上就是经典的增量PID去去"D"项的结果,也就是PI控制,只是它的恩路与原来的有一些不一样的地方
coleyao
2楼-- · 2020-01-18 03:29
本帖最后由 coleyao 于 2012-10-7 09:18 编辑
eddia2012 发表于 2012-10-6 10:54
预测式反馈式PID,实际上就是经典的增量PID去去"D"项的结果,也就是PI控制,只是它的恩路与原来的有一些不一样 ...


   呵呵,你说的是线性预测(函数近似y=x0+x*y'),从实际控制效果上来说是与PI控制一样的,但物理意义不一样了。
  如果是非线性预测(函数近似y=x0+x*y'+0.5*x*x*y''+...),那么实际上预测式负反馈比PID更全面,只是更高阶的预测效果会不会更好,有没有必要,倒是一个值得探索的问题。。。。
eddia2012
3楼-- · 2020-01-18 04:05
 精彩回答 2  元偷偷看……
coleyao
4楼-- · 2020-01-18 09:40
eddia2012 发表于 2012-10-7 17:42
楼主的这个思路很好,我现在完全理解了它的妙处,这个比PID要好调些,理论上可以做到不超调,这点是很重要 ...

Pre(K)  的确定,请参考我的另一个帖子:http://www.amobbs.com/thread-5484520-1-1.html  。
FuARM
5楼-- · 2020-01-18 14:20
这是本人按照公式写的一个增量式PID的程序,和测试程序,不知正确与否,恳请懂的人指出错误和建议。
想用在小车直流电机的控制上来,直流电机上有挡光片测速。MCU PWM调节转速。

按照推荐的调节PID的步骤,先将Ki=Kp*T/Ti置位0,将Kd=Kp*Td/T=0,当作纯比例控制器来调节,
因此让Ti=10000000.0(足够大就行,让Ki接近0),Td=0。此时A=Kp,B=-Kp;C=0;
增量计算(根据后面的程序改的伪代码):
        e_0 = Set - Get;//目标值-本次测量值
        delta = A*e_0 + B*e_1 + C*e_2 = Kp(e_0 - e_1) ;
        e_2 = e_1;
        e_1 = e_0;
        out += delta;
那么,按照以上推导,在纯比例控制中,增量=Kp*(前两次误差的差值);
我的疑问是:
        假设目标值是100,初始状态e_0=0,e_1=0;
        时刻1测量值是10,那么误差就是90,e_0=90,e_1=0;那么delta增量会有一个值,同时实际输出量out也有一个值
        如果时刻2测量值还是10,那么e_0=90,e_1=90; Kp(e_0 - e_1) =0;delta增量=0,此时out不增加。
        试想,当输出量out还不足以驱动电机或者电机被负载堵转时,误差恒定不变,但是delta却等于0,输出out不变,电机也不会增加力矩,这似乎有悖我们控制电机转速的初衷。

以上是我的理解,不知道正确么,恳请大家指导。

/************************************************************************/
#include <math.h>

#define Kp   (1.0)                //PID调节的比例常数
#define Ti   (10000000.0)       //PID调节的积分常数
#define Td   (0.0)              //PID调节的微分时间常数
#define T    (0.1)              //采样周期

#define AA  (Kp * (1 + (T / Ti) + (Td / T)))   //A
#define BB   ((-Kp) * (1+(2 * Td / T)))        //B
#define CC   (Kp * Td / T)                    //C

//误差的阀值,小于这个数值的时候,不做PID调整,避免误差较小时频繁调节引起震荡
#define Emin 3

//调整值限幅,防止积分饱和
#define Umax 20
#define Umin -20

//输出值限幅
#define Pmax 245
#define Pmin 0


typedef struct PID
{
        int Set;  //目标值
        int Get;  //当前测量值

        int e_1;
        int e_2;
        
        double A;
        double B;
        double C;
        
        int delta;
        int out;
}PID_t;


void pid_init(PID_t * pPID);
void pid_ctrl(PID_t * pPID);


void pid_init(PID_t * pPID)
{
        pPID->Set = 0;
        pPID->Get = 0;
        pPID->e_1 = 0;
        pPID->e_2 = 0;
        pPID->delta = 0;
        pPID->out = 0;
        
        pPID->A=AA;
        pPID->B=BB;
        pPID->C=CC;
}


void pid_ctrl(PID_t * pPID)
{

        int e_0 = pPID->Set - pPID->Get;//求差值
        
        pPID->delta = (int)(pPID->A*e_0 + pPID->B*pPID->e_1 + pPID->C*pPID->e_2);
        pPID->e_2 = pPID->e_1;
        pPID->e_1 = e_0;
        pPID->out += pPID->delta;
}


PID_t PID_A;

void main(void)
{
        int i;
        pid_init(&PID_A);
        
        printf("Kp=%f,Ki=%f,Kd=%f ",Kp,(Kp*T/Ti),(Kp*Td/T));
        printf("A=%f,B=%f,C=%f ",AA,BB,CC);

        printf("input the set val ");
        scanf("%d",&PID_A.Set);
        printf("Set=%d ",PID_A.Set);


        while(1){
                scanf("%d",&PID_A.Get);
                pid_ctrl(&PID_A);
                printf("get=%8d ",PID_A.Get);
                printf("delta=%8d, out=%8d ",PID_A.delta,PID_A.out);
                printf("e_1  =%8d, e_2=%8d ",PID_A.e_1,PID_A.e_2);
        
        }        
        printf("leave");
}




xymbmcu
6楼-- · 2020-01-18 14:55
大家都好好算吧,算好了,我用就行了,呵呵

一周热门 更多>