打印

温控pid程序

[复制链接]
5706|47
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
cl234583745|  楼主 | 2014-12-22 13:45 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 cl234583745 于 2014-12-22 13:57 编辑

为啥温度最后一直都是35读左右呢?p值再高,开始几次总超过设定值。怎么回事呢?感觉不论p是多少,开始都升上去,震荡几次后,最后输出温度都是30-35度

void Pid_init()                                                   ///pid初始化
{   
        hightime= 0;
        e1 = 0;
        e2 = 0;
        e3 = 0;
        kp = 40.0;
        ki = 0.0;
        kd = 0.0;        
}

void pid_ys()                                                 //增量pid计算(原始的没有计算死区)hightime为输出结果
{
                                           
                        e1 = settemp-rltemp;
                        duk=(kp*(e1-e2)+ki*e1+kd*(e1+e3-e2*2))/10;
                        uk = uk+duk;
                        if(uk>100)
                        uk = 100;                  
                        else if(uk<-100)
                        uk = -100;
                        if(uk<0)
                        {
                                hightime=-uk;
                        }
                        else
                        {
                                hightime=uk;
                        }
                        e3 = e2;
                        e2 = e1;        
}
//////////////////////////////////////////////////////////////定时器1,定时1ms.每100ms运算一次输出结果hightime
            if(jr_time<100)
            {
                jr_time++;   
            }
            else
            {
                jr_time=0;
                pid_ys();
            }

///////////////////////////////////////////////////////////////定时器2,定时1ms. 输出周期100ms
    if(guoling_标志寄存器2==1)   //1ms时间到了
    {   guoling_标志寄存器2=0;
        if(++count<=(hightime))
            KKG_WEAT=1;
        else if(count<=100)
        {
                KKG_WEAT=0;
        }
        else
                count=0;  
        TPM1SC|=0x18;
    }




相关帖子

沙发
wangtao478552| | 2014-12-22 16:41 | 只看该作者
什么鬼,硬件上是PWM控制阻性负载作为热源,自然冷却吗?

使用特权

评论回复
板凳
cl234583745|  楼主 | 2014-12-22 16:56 | 只看该作者
wangtao478552 发表于 2014-12-22 16:41
什么鬼,硬件上是PWM控制阻性负载作为热源,自然冷却吗?

占空比低,不加热,不就冷了吗

使用特权

评论回复
地板
wangtao478552| | 2014-12-22 17:00 | 只看该作者
cl234583745 发表于 2014-12-22 16:56
占空比低,不加热,不就冷了吗

什么鬼只是口头禅

                        if(uk<0)
                        {
                                hightime=-uk;//改为hightime=0;???
                        }
                        else
                        {
                                hightime=uk;
                        }

使用特权

评论回复
5
cl234583745|  楼主 | 2014-12-23 07:55 | 只看该作者
wangtao478552 发表于 2014-12-22 17:00
什么鬼只是口头禅

                        if(uk

那我估计温度更升不起来了。本来是吧负的变成正的,这样就是0了

使用特权

评论回复
6
cl234583745|  楼主 | 2014-12-23 08:12 | 只看该作者
怎么没有人会吗?还是我说的不明确呢

使用特权

评论回复
7
cauhorse| | 2014-12-23 09:43 | 只看该作者
楼主控制什么装置?加热对象比较大的话,0.1s加热周期有点太短了;
见楼主用的增量式数字PID,需要确认算法中的积分环节是否真实有效,如果加热功率足够,而目标值始终低于设定值,正常的积分环节会一直累加至饱和,现象就是加热功率全开,楼主注意观察一下;
通常做温度控制,积分分离+位置式PI算法就可运行得很好了,甚至有控制器只运行积分算法,也能把温度控制得很稳定,就是动态特性差点,楼主可以单独试验,先调比例看上升速度和超调量,接近控制值再调一下积分,最后根据需要加微分,很多时候也可以不加,除非应用中要求温度随时间不断改变,这时可以关注一下动态特性,纯延迟太大的系统(你加热,过老长时间它才开始升温)有时单PID是控制不好的,得做一些补偿。

使用特权

评论回复
8
cl234583745|  楼主 | 2014-12-23 09:55 | 只看该作者
cauhorse 发表于 2014-12-23 09:43
楼主控制什么装置?加热对象比较大的话,0.1s加热周期有点太短了;
见楼主用的增量式数字PID,需要确认算法 ...

加热片
周期是0.1s  是长了还是短了?原来周期是1s听人说周期太长,反应太慢,我才改短一点的?
昨天下午还有几次调好了呢?后来逐渐降低p时候就不好使了,不知道怎么回事,就再也不好使了。

你不推荐用增量式,推荐位置式吗?u(k)=e(k)*kP+Σe(k)*kI+kD*(e(k)-e(k-1))这是位置式公式,但我不清楚Σe(k)在我的程序中怎么表示呀?

使用特权

评论回复
9
cauhorse| | 2014-12-23 10:08 | 只看该作者
cl234583745 发表于 2014-12-23 09:55
加热片
周期是0.1s  是长了还是短了?原来周期是1s听人说周期太长,反应太慢,我才改短一点的?
昨天下午 ...

多大的加热对象或者加热空间?如果比较小,可以用短周期。因为一般控温都会多多少少有延迟,调节周期太短也不利于温度控制,比方120立升用3秒的周期就不错,短了对控温精度、稳定性也没有显著提升,反倒让MCU负荷变重了不少。
“P改小不好使”可能跟你的加热对象有关系,看一下P改小后温度静态误差有没有变化?
用位置式还是比较方便的。积分环节就是累加:sum_I = sum_I + (kI * ek);
你看,只要反馈值低于设定值,sum_I就会在每个计算周期中一直累加,直到饱和为止,这样加热过程就不会停止,累加速度只与kI有关。如果用单片机,只要注意sum_I累加后不要造成变量溢出就行了,因为溢出后,有符号的变量会变号,输出会剧烈变化。

使用特权

评论回复
10
cl234583745|  楼主 | 2014-12-23 10:30 | 只看该作者
cauhorse 发表于 2014-12-23 10:08
多大的加热对象或者加热空间?如果比较小,可以用短周期。因为一般控温都会多多少少有延迟,调节周期太短 ...

大约10*10cm的翅片加热片

Σe(k)*kI中的Σe(k)不是温差的和吗?sum_I = sum_I + (kI * ek);是什么东东。
在我的程序中e1 = settemp-rltemp;

使用特权

评论回复
11
cauhorse| | 2014-12-23 10:43 | 只看该作者
cl234583745 发表于 2014-12-23 10:30
大约10*10cm的翅片加热片

Σe(k)*kI中的Σe(k)不是温差的和吗?sum_I = sum_I + (kI * ek);是什么东东 ...

这样写:
e1 = settemp - rltemp;      /*计算偏差值*/
sum_I = sum_I + (kI * e1);  /*计算积分环节的累加值,即温度偏差值的积分求和*/
那个sum_I就是你要的Σe(k)*kI,这个Σ求和就是在每次定时计算环节中的累加,就是用上式的“+”来实现的。

使用特权

评论回复
12
cl234583745|  楼主 | 2014-12-23 11:13 | 只看该作者
本帖最后由 cl234583745 于 2014-12-23 11:29 编辑
cauhorse 发表于 2014-12-23 10:43
这样写:
e1 = settemp - rltemp;      /*计算偏差值*/
sum_I = sum_I + (kI * e1);  /*计算积分环节的累 ...

sum_I 什么时候要清零吗?一直累计吗?

下面这样对吗?
e1 = settemp-rltemp;
            sum_I = sum_I +  e1;
                        uk=(kp*e1+ki*sum_I+kd*(e1-e2))/10;                      //u(k)=e(k)*kP+Σe(k)*kI+kD*(e(k)-e(k-1))
            e2=e1;

使用特权

评论回复
13
cauhorse| | 2014-12-23 12:04 | 只看该作者
cl234583745 发表于 2014-12-23 11:13
sum_I 什么时候要清零吗?一直累计吗?

下面这样对吗?

sum不需要清零,初始化为零即可,如果上来积分量太大,可以做积分分离算法。正常控制时,累加过程按偏差值符号是不断变化的,把积分上下限限定好就可以了,比如累加值限制在[-1000,+1000],举个栗子。还要注意不要让积分变量溢出。
这样写没太大问题,但是ki*sum_I的结果会不会出现溢出?整个uk的计算值需要检查,也不可溢出,这点光靠阈值限定是不够的。

使用特权

评论回复
14
cl234583745|  楼主 | 2014-12-23 13:03 | 只看该作者
本帖最后由 cl234583745 于 2014-12-23 13:05 编辑
cauhorse 发表于 2014-12-23 12:04
sum不需要清零,初始化为零即可,如果上来积分量太大,可以做积分分离算法。正常控制时,累加过程按偏差 ...

谢谢你。你讲的很好,但我有的地方还是理解不够深刻。并且现在只知道位置式和增量式。积分分离算法还是不知道。

你是说ki*sum_I的结果也要限制吗?如何约束呢?值应该是怎么样的呢?
而不不止是下面的控制结果uk的阈限
if(uk>100)
                        uk = 100;                  
                        else if(uk<-100)
                        uk = -100;
                        if(uk<0)
                        {
                                hightime=-uk;
                        }
                        else
                        {
                                hightime=uk;
                        }

使用特权

评论回复
15
cl234583745|  楼主 | 2014-12-23 13:21 | 只看该作者
本帖最后由 cl234583745 于 2014-12-23 13:30 编辑
cauhorse 发表于 2014-12-23 12:04
sum不需要清零,初始化为零即可,如果上来积分量太大,可以做积分分离算法。正常控制时,累加过程按偏差 ...

现在我调试位置式的结果是:
void Pid_init()
{   
        hightime= 0;
        e1 = 0;
        e2 = 0;
        e3 = 0;
        kp = 11.0;
        ki = 0.0;
        kd = 0.0;
        sum_I=0;
               
}
温度变化趋势和uk的输出结果hightime:越接近设定值hightime就越小。但达到设定值后维持不住呀?怎么调呢?温度又下来了,此时hightime应该快速增加以抵消温度下降吧?感觉接近设定和远离设定时候,输出结果uk也就是hightime变化速率是一样的???应该是接近时候迅速减小,远离时候迅速增大才能维持到设定温度吧?

使用特权

评论回复
16
cauhorse| | 2014-12-23 14:14 | 只看该作者
一种方法是量化每次采样值,使计算得到的偏差不至于太大,单次积分求就不会溢出;另一种方法就是利用变量类型本身加以防范。这个问题可能需要你遇到类似的情况之后才能理解。
ki不能为零,否则静差无法消除,积分系数得有正值。越接近设定值,比例环节的计算结果自然是越小的,此时加热对象可能与环境温度温差大,热散失也快,所以温度不易保持,这个对控制对象特性有关;
程序可能有不合理之处,单边控制,输出低于下限直接关断就行了,你取反是何用意?

if(uk<0)
{
    hightime=-uk;
}
uk输出为负,说明控制环节希望受控对象降温。实际如不存在制冷装置,这时仅将加热器关闭就行了,你取反之后,输出又为正,如何实现自动调节?

使用特权

评论回复
17
cl234583745|  楼主 | 2014-12-23 14:45 | 只看该作者
本帖最后由 cl234583745 于 2014-12-23 14:49 编辑
cauhorse 发表于 2014-12-23 14:14
一种方法是量化每次采样值,使计算得到的偏差不至于太大,单次积分求就不会溢出;另一种方法就是利用变量类 ...

就这几行你帮我看看吧?晕死了。现在现象就是温度在35度-设定值间震荡。
减小p以达到消除震荡时候。温度就一直是35度,调节id也升不上去了。
uint hightime;         //占空比调节参数
uint rltemp,settemp;
float e1,e2,e3,duk,uk,sum_I;
void Pid_init()
{   
        hightime= 0;
        e1 = 0;
        e2 = 0;
        e3 = 0;
        kp = 8.0;
        ki = 0.0;
        kd = 0.0;
        sum_I=0;
               
}


         if(rltemp<settemp)         //        如果实际温度小于设定值
    {
            e1 = settemp-rltemp;
            sum_I = sum_I +  e1;
                        uk=(kp*e1+ki*sum_I+kd*(e1-e2))/10;  //u(k)=e(k)*kP+Σe(k)*kI+kD*(e(k)-e(k-1))
            e2=e1;
            if(uk>100)
                        uk = 100;                  
                        else if(uk<-100)
                        uk = -100;
                        if(uk<0)
                        {
                                hightime=0;
                        }
                        else
                        {
                                hightime=uk;
                        }
    }
    else
        hightime=0;                  //停止加热

使用特权

评论回复
18
cauhorse| | 2014-12-23 23:11 | 只看该作者
uint rltemp,settemp;
定义成无符号整型了?
e1作为偏差是具有符号的,不然PID算法的调节作用无法实现,先理解这一点。

使用特权

评论回复
19
cl234583745|  楼主 | 2014-12-24 08:09 | 只看该作者
定义是,但结果传给了e1,强制类型转换不可以吗?编译器自己转换了

使用特权

评论回复
20
cl234583745|  楼主 | 2014-12-24 08:25 | 只看该作者
cauhorse 发表于 2014-12-23 23:11
uint rltemp,settemp;
定义成无符号整型了?
e1作为偏差是具有符号的,不然PID算法的调节作用无法实现,先 ...


定义是,但结果传给了e1,强制类型转换不可以吗?编译器自己转换了

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

99

主题

644

帖子

1

粉丝