衍生PID算法——变比例不完全积分式PID

1,PID算法简介

PID算法是当下应用最广泛的控制算法,它具有结构简单,易于理解,控制效果直观,参数较为整定简单,变形多样等优点,更有甚者称之为万能控制算法。
但是,严格意义上讲,PID算法仅仅对线性系统,或近似线性系统,或系统常处于线性段的系统能够取得良好的控制效果。
(线性系统判断依据——满足叠加原理)
那么,对于一个非线性的控制,我们常使用一些PID算法的变形,比如积分分离式PID,微分先行PID,带低通滤波的PID等等。

在这里,提出一种变形——变比例不完全积分式PID。

2,背景

学习PID大多是从电机调速开始的,而电机调速几乎是最简单的控制系统了,因为电压与转速之间是有严格的公式存在,尽管有摩擦或者电网扰动等非线性特性存在,但也是可以进行忽略线性化的。因此,电机调速确实是很典型的学习PID算法的实例,但是对于深度学习尚显不足。

那么,对于一种典型的非线性系统,如流体(气体,液体)控制系统等。我们知道,流体是有别于固态实体的,对于他们的控制已经有了很多的研究。

设想这样一个系统,”风力悬浮球高度控制”,顾名思义,我们使用轴流风扇,使用高度反馈来控制管中小球的高度。我们知道,风扇的风力和转速肯定是成某种正比关系的,电机的电压和电机的转速是成某种正比关系的,那么风力和电压之间是否的严格的线性关系呢,这就不得而知了,那么风力和小球的高度是不是严格的线性关系呢,还要考虑到小球的速度,加速度,重力等问题…,以上所谈都是关于系统的建模问题,我们今天不是来讨论模型的,那样就失去了PID算法的无模型控制的简单之美。

实验中发现,小球在最底部到升起的那一瞬间,是需要较大的风力的,而升起之后,风力变化又不需要像升起时候那么大。这必然是一个典型的非线性系统了。

那么,如果我们使用传统的PID算法进行控制,当我们给定一个阶跃信号时,假设说需要小球稳定在50cm处,此时小球在0cm处,让小球升起需要很大的风力。
如果,这时我们给一个较大的比例系数,又由于小球在升起之后运动时风力不需要很大,在加上积分作用,此时较大的比例就会引起强烈震荡,如果其他参数不合适甚至会导致系统发散。
如果,我们给一个较小的比例,靠积分的作用逐渐使得小球上升呢?这也会有问题,在偏差较大的段使用积分,会导致系统超调量增大,调整时间变长,甚至引起发散震荡。

那么,我们自然会想到一种变形——积分分离式PID。

3,纯积分分离式PID算法的缺陷

积分分离式PID是指,在偏差较大的段不进行积分,只靠比例作用,在偏差较小时进行积分,减小稳态误差,用于减小超调,减小调整时间。但是,如果对于快速变化的流体控制来说,在初始段需要较大的风力,在小球升起的时候只需要很小的风力变化,那么假设说我们在初始段给了一个较大的比例,并且不进行积分,那么小球将会在没有积累到足够的积分项之前产生较大的震荡,而在达到稳态之后,又由于较大的比例,可能会引起系统震荡。这样的系统虽然也能达到稳定,但是有较长的调整时间,这不是我们希望看到的。
衍生PID算法——变比例不完全积分式PID_第1张图片
这是纯积分分离式PID的响应波形,可以看到在达到期望值之前有一个较大的震荡。
那么,综上所诉,我们没有建模,根据实验经验,得到了我们这个系统的特点:在小球升起时需要较大的力,小球运动时风力不需要很大的变化。我们需要减小震荡和调整时间。

4,变比例不完全积分式PID介绍

变比例积分分离式实际上是在积分分离式PID的基础所进行的变形,在小球升起(偏差较大的段)使用一个较大的比例,在接近稳态时使用一个较小的比例;
为防止当积分分离使得系统在初始段震荡,而如果不积分分离又容易出现较大超调的情况,我们在初始段进行不完全积分——即在积分时对偏差乘以系数。
通过这样的一种调整,我们我们在初始段(偏差较大的段)使用了较大的比例和不完全积分,在接近稳态段使用较小的比例和完全积分。既减小了上升时间,又减小超调量提升稳态精度,经过试验验证,这种方式对于此流体系统效果奇佳!
衍生PID算法——变比例不完全积分式PID_第2张图片
这是使用变比例不完全积分式PID之后的响应波形,跟积分分离相比可以看到调整时间减小,超调减小。

5,C语言代码实现

//系统所有参数结构体
typedef struct{
    float Kp;           //比例系数
    float Ki;           //积分时间
    float Kd;           //微分时间

    float ExpValu;      //期望值
    float NowValu;      //当前值

    float Diff;         //微分

    float Inte;         //积分
    float InteLimitPost;//积分正限幅
    float InteLimitNega;//积分负限幅

    float NoInteKp;     //偏差过大 不完全积分时的Kp 

    float Err;          //本次偏差
    float ErrLimit;     //积分分离阈值
    float IntePar;      //不完全积分时积分系数 ,如果是0则完全不积分 

    float ErrLast;      //上次偏差

    float OutValu;      //输出值
    float OutLimitPost; //输出正限幅
    float OutLimitNega; //输出负限幅 
}PIDTypedef;

//PID算法核心
void PIDCalculate(PIDTypedef *pidset)
{
    static float Real_Kp = 0;
    //计算偏差
    pidset->Err = pidset->ExpValu - pidset->NowValu;
    //计算微分
    pidset->Diff = pidset->Err - pidset->ErrLast;

    //积分分离 
    //如果偏差过大,则减小积分,P进行调整 
    if((pidset->Err > pidset->ErrLimit) || (pidset->Err < -pidset->ErrLimit)) 
    {
        Real_Kp = pidset->NoInteKp; 
        //进行不完全积分
        pidset->Inte += (pidset->IntePar)*pidset->Err;

    }else
    {
        Real_Kp = pidset->Kp;
        //完全积分
        pidset->Inte += pidset->Err;
    } 
    //积分限幅
    if(pidset->Inte > pidset->InteLimitPost)
    {
        pidset->Inte = pidset->InteLimitPost;
    }else if(pidset->Inte < pidset->InteLimitNega)
    {
        pidset->Inte = pidset->InteLimitNega;
    }

    //计算输出值 
    pidset->OutValu =  (Real_Kp * pidset->Err) + \
                        (pidset->Ki * pidset->Inte) +\
                         (pidset->Kd * pidset->Diff);
    //输出限幅
    if(pidset->OutValu > pidset->OutLimitPost)
    {
        pidset->OutValu = pidset->OutLimitPost; 
    }else if(pidset->OutValu < pidset->OutLimitNega)
    {
        pidset->OutValu = pidset->OutLimitNega;
    }
    //上次偏差
    pidset->ErrLast = pidset->Err;
}

//PID控制器

float PIDController(PIDTypedef *pidset,float expvalue,float nowvalue)
{
    pidset->ExpValu = expvalue;
    pidset->NowValu = nowvalue;

    PIDCalculate(pidset);

    return (pidset->OutValu);
}

以上代码有足够注释,但是不免有未完善之处,望以批判态度进行移植学习。

6,算法延伸

上述代码中的变比例和不完全积分系数使用了一个固定的值,其实应当也可以使用变量,比如比例可以随着偏差变化,不完全积分系数随着偏差变化等。
可根据需要进行延伸,变形,扩展,这应当是PID算法的一大特性吧。这里,向PID算法致敬,向控制学致敬!

最后贴一下风力悬浮球高度控制系统视频

你可能感兴趣的:(算法)