模糊PID c语言代码,兼容PID

此博客不讲理论,只贴代码,可直接复制粘贴使用。

在PID控制器的基础上,加入了模糊控制。

PID控制中加入了积分分离等常规操作。模糊PID对kp,ki,kd三个参数进行模糊控制。贴一张模糊规则表。

 

代码使用方法:

1.  定义一个 fuzzy_pid_st的结构体并赋初值:kp,ki,kd,dt,fuzzy等参数

2. 在进行PID控制时,将误差e和误差的微分de分别赋值。

3. 调用PID_control函数,其中out为PID控制器输出。

4. FUZZY_USED为标志位,可以选择是否使用模糊PID

#define FUZZY_SEG_NUMS 7   //7个模糊子集

// NB NM NS ZO PS PM PB
// 0  1  2  3  4  5  6

typedef struct
{
    bool FUZZY_USED;   //是否使用模糊PID

    float max_e;    // e  \in [-max_e,max_e]
    float max_ec;   // ec \in [-max_ec,max_ec]
    float max_kp;   // kp \in kp0+[-max_kp,max_kp] kp0-max_kp>0
    float max_ki;
    float max_kd;

    uint8_t rule_kp[FUZZY_SEG_NUMS][FUZZY_SEG_NUMS];  //模糊规则表
    uint8_t rule_ki[FUZZY_SEG_NUMS][FUZZY_SEG_NUMS];   
    uint8_t rule_kd[FUZZY_SEG_NUMS][FUZZY_SEG_NUMS];

}fuzzy_pid_st;

typedef struct
{
    float e;
    float de;
    float out;

    float kp;   // kp基本值(对于模糊PID)
    float ki;   // ki基本值(对于模糊PID)
    float kd;   // kd基本值(对于模糊PID)

    float dt;       
    float e_min;  // 积分限幅
    float e_max;
    float Integ_e;// 积分限幅
    float Integ_e_max;
    float damp;   //积分衰减系数 可设为0.9995之类的数

    fuzzy_pid_st fuzzy_t;  // 模糊PID
} PID_pm_st;


/************************************************************************
 * @brief 模糊化
 * @note  NULL
 *
 * @param val  输入变量
 * @param max  输入变量的基本论域为 [-max,max]
 * @return  percent 变量的模糊占比
 *
 *************************************************************************/
void fuzzification(float val, float max, float* percent)  //模糊化
{
    float interval[FUZZY_SEG_NUMS];

    float seg_len = 2 * max / (FUZZY_SEG_NUMS - 1);
    for (int i = 0; i < FUZZY_SEG_NUMS; i++)
    {
        percent[i] = 0;                    // percent赋初值
        interval[i] = -max + i * seg_len;  //分段点的值 NB NM NS ZO PS PM PB 的值
    }
    if (val <= interval[0])  // <= 0
    {
        percent[0] = 1;
        return;
    }
    else if (val <= interval[1])  //  [0,1]
    {
        percent[1] = (val - interval[0]) / seg_len;
        percent[0] =1- percent[1];
        return;
    }
    else if (val <= interval[2])  // [1,2]
    {
        percent[2] = (val - interval[1]) / seg_len;
        percent[1] = 1 - percent[2];
        return;
    }
    else if (val <= interval[3])  // [2,3]
    {
        percent[3] = (val - interval[2]) / seg_len;
        percent[2] = 1 - percent[3];
        return;
    }
    else if (val <= interval[4])  // [3,4]
    {
        percent[4] = (val - interval[3]) / seg_len;
        percent[3] = 1 - percent[4];
        return;
    }
    else if (val <= interval[5])  // [4,5]
    {
        percent[5] = (val - interval[4]) / seg_len;
        percent[4] = 1 - percent[5];
        return;
    }
    else if (val <= interval[6])  // [5,6]
    {
        percent[6] = (val - interval[5]) / seg_len;
        percent[5] = 1 - percent[6];
        return;
    }
    else                          // >6
    {
        percent[6] = 1 ;
        return;
    }
}
/************************************************************************
 * @brief 根据模糊规则表,将e和ec映射为响应的控制参数:kp ki kd
 * @note  NULL
 *
 * @param percent_e[7]  误差e的模糊占比
 * @param percent_ec[7] 误差微分ec的模糊占比
 * @param rule[7][7]    误差规则表
 * @return  percent_out 对于的参数的模糊占比
 *
 *************************************************************************/
void fuzzy_rule(const float *percent_e, const float* percent_ec, const uint8_t rule[FUZZY_SEG_NUMS][FUZZY_SEG_NUMS], float* percent_out)  //模糊规则表映射
{
    for (int i = 0; i < FUZZY_SEG_NUMS; i++)
    {
        percent_out[i] = 0;                    // percent赋初值
    }
    for (int i = 0; i < FUZZY_SEG_NUMS; i++)   // e
    {
        for (int j = 0; j < FUZZY_SEG_NUMS; j++)  //ec
        {
            if (percent_e[i] == 0 || percent_ec[j] == 0)
                continue;
            uint8_t index = rule[i][j];
            percent_out[index] += percent_e[i] * percent_ec[j];
        }
    }
}
/************************************************************************
 * @brief 去模糊化,模糊化相反的过程
 * @note  NULL
 *
 * @param percent[7]  输入变量的模糊占比
 * @param max  输入变量的基本论域为 [-max,max]
 * @return  val 输出变量的真值
 *
 *************************************************************************/
float de_fuzzification(float max, float* percent)  //去模糊化
{
    float val=0;
    float interval[FUZZY_SEG_NUMS];
    float seg_len = 2 * max / (FUZZY_SEG_NUMS - 1);
    for (int i = 0; i < FUZZY_SEG_NUMS; i++)
    {
        interval[i] = -max + i * seg_len;  //分段点的值 NB NM NS ZO PS PM PB 的值

        val += percent[i] * interval[i];
    }
    return val;
}

/* 浮点数绝对值 */
float abs_1f(float val)
{
    return (val > 0 ? val : -val);
}
/* 浮点数符号 */
float sign_1f(float val)
{
    return (val > 0 ? 1.0f : -1.0f);
}
/* 浮点数限幅 */
float limit_abs1f(float val, float limit)
{
    if (abs_1f(val) > limit)
        return (sign_1f(val) * limit);
    else
        return val;
}

/* PID控制器 */
void PID_control(PID_pm_st* PID_pm)
{
    float kp, ki, kd;
    kp = PID_pm->kp;
    ki = PID_pm->ki;
    kd = PID_pm->kd;
    /* 根据模糊规则表计算kp ki kd */
    if (PID_pm->fuzzy_t.FUZZY_USED == true)
    {
        float percent_e[7];
        float percent_ec[7];
        float percent_kp[7];
        float percent_ki[7];
        float percent_kd[7];

        float d_kp,d_ki,d_kd;

        /* e和ec模糊化 */
        fuzzification(PID_pm->e,PID_pm->fuzzy_t.max_e, percent_e);
        fuzzification(PID_pm->de, PID_pm->fuzzy_t.max_ec, percent_ec);
       
        /* 根据模糊规则计算参数 */
        fuzzy_rule(percent_e, percent_ec, PID_pm->fuzzy_t.rule_kp, percent_kp);
        fuzzy_rule(percent_e, percent_ec, PID_pm->fuzzy_t.rule_ki, percent_ki);
        fuzzy_rule(percent_e, percent_ec, PID_pm->fuzzy_t.rule_kd, percent_kd);

        /* kp ki kd 去模糊化*/
        d_kp = de_fuzzification(PID_pm->fuzzy_t.max_kp, percent_kp);
        d_ki = de_fuzzification(PID_pm->fuzzy_t.max_ki, percent_ki);
        d_kd = de_fuzzification(PID_pm->fuzzy_t.max_kd, percent_kd);

        kp += d_kp;
        ki += d_ki;
        kd += d_kd;

    }
   
    PID_pm->Integ_e += limit_abs1f(PID_pm->e, PID_pm->e_max) * PID_pm->dt; // 【积分分离】限制e的幅值
    PID_pm->Integ_e = limit_abs1f(PID_pm->Integ_e, PID_pm->Integ_e_max);   // 限制integ_e的幅值
    PID_pm->Integ_e = PID_pm->Integ_e * PID_pm->damp;                      //damp为积分随着时间的衰减系数

    PID_pm->out = kp * PID_pm->e + kd * PID_pm->de + ki * PID_pm->Integ_e;
}

  • 17
    点赞
  • 108
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
自适应模糊PID算法在温度控制方面具有很好的应用效果,可以实现更加精确的温度控制。下面是一个简单的C语言代码示例: ```c #include <stdio.h> // 定义PID参数 float kp = 0.5; // 比例系数 float ki = 0.2; // 积分系数 float kd = 0.1; // 微分系数 // 定义PID变量 float error = 0; // 当前温度误差 float integral = 0; // 温度误差积分项 float derivative = 0; // 温度误差微分项 float lastError = 0; // 上一次温度误差 // 定义温度变量 float setTemp = 37.0; // 目标温度 float currentTemp = 30.0; // 当前温度 // PID算法函数 float pid_algorithm() { // 计算温度误差 error = setTemp - currentTemp; // 计算积分项 integral += error; // 计算微分项 derivative = error - lastError; lastError = error; // 计算PID输出 float output = kp * error + ki * integral + kd * derivative; return output; } int main() { // 模拟温度控制过程 for (int i = 0; i < 10; i++) { // 通过传感器获取当前温度 currentTemp += pid_algorithm(); // 输出当前温度 printf("当前温度:%.2f\n", currentTemp); } return 0; } ``` 以上是一个简单的自适应模糊PID算法C语言代码示例,首先定义了PID参数(比例系数、积分系数和微分系数),然后定义了PID变量(温度误差、温度误差积分项、温度误差微分项和上一次温度误差)。 在主函数中,通过循环模拟了一个温度控制过程。在每次循环中,通过传感器获取当前温度,并利用PID算法计算出控制输出。最后输出当前温度。注意:此示例仅供参考,实际使用时需根据具体需求进行参数调整和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值