SaintStefan
12/22/2019 - 6:13 PM

积分分离的增量型PID控制算法C语言实现

/*******************************************************************************
 * 积分分离的增量型PID控制算法C语言实现
 *******************************************************************************
 * 在普通PID控制中,引入积分环节的目的,主要是为了消除静差,提高控制精度。
 * 但是在启动、结束或大幅度增减设定时,短时间内系统输出有很大的偏差,会造成PID运算的积分积累,
 * 导致控制量超过执行机构可能允许的最大动作范围对应极限控制量,
 * 从而引起较大的超调,甚至是震荡,这是绝对不允许的。
 * 为了克服这一问题,引入了积分分离的概念,其基本思路是 
 * 当被控量与设定值偏差较大时,取消积分作用; 
 * 当被控量接近给定值时,引入积分控制,以消除静差,提高精度。
 *******************************************************************************
 * PID增量表达式:∆u(k) = Kp*(error(k) - error(k-1)) + Ki*(error(k)) + Kd*(error(k) - 2*error(k-1) + error(k-2))
 * 最终的结果 = u(k) + ∆u(k)
 ******************************************************************************/
 
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

struct _pid
{
    float SetSpeed;                 // 定义设定值
    float ActualSpeed;              // 定义实际值
    float error;                    // 定义偏差值
    float error_next1;              // 定义偏差值(k-1)
    float error_next2;              // 定义偏差值(k-2)
    float Kp,Ki,Kd;                 // 定义比例、积分、微分系数
}pid;                               // 定义了一个结构名为_pid的结构变量pid

void PID_init()
{
    printf("PID_init begin\n");
    pid.SetSpeed = 0.0;
    pid.ActualSpeed = 0.0;
    pid.error = 0.0;
    pid.error_next2 = 0.0;
    pid.error_next1 = 0.0;
    pid.Kp = 0.2;                   // 需要自行整定
    pid.Ki = 0.04;                  //
    pid.Kd = 0.2;                   //
    printf("PID_init end\n");
}

float PID_realize(float speed)
{
    float incrementSpeed;
    float index;

    pid.SetSpeed = speed;
    pid.error = pid.SetSpeed - pid.ActualSpeed;
    if(fabsf(pid.error) > 200)       // abs()是用来求int型的绝对值,
                                     // fabsf()是用来求float型的绝对值,
                                     // fabs()是用来求double型的绝对值,要用库math.h
    {
        index = 0;
    }
    else
    {
        index = 1;
    }
    incrementSpeed = pid.Kp*(pid.error - pid.error_next1) + index*pid.Ki*pid.error + pid.Kd*(pid.error - 2*pid.error_next1 + pid.error_next2);
    pid.ActualSpeed += incrementSpeed;
    pid.error_next2 = pid.error_next1;
    pid.error_next1 = pid.error;
    return pid.ActualSpeed;
}

int main()
{
    PID_init();
    int count = 0;
    while(count < 1000)             // 运行1000次,得到1000个数据
    {
        float speed = PID_realize(200.0);
        printf("%f\n",speed);
        count++;
    }
    return 0;
}