模糊PID控制算法 之 C语言实现

5 篇文章 2 订阅
2 篇文章 0 订阅

fuzzy-pid

鉴于控制算法常于嵌入式平台使用,所以博主使用C语言实现模糊PID控制算法,该项目已上传至GitHub以及码云。实现的功能包括但不限于:

  • 隶属度函数 Membership function
    • 高斯隶属度函数 Gaussian membership function
    • 广义钟形隶属度函数 Generalized bell-shaped membership function
    • S形隶属度函数 Sigmoidal membership function
    • 梯形隶属度函数 Trapezoidal membership function
    • 三角形隶属度函数 Triangular membership function
    • Z形隶属度函数 Z-shaped membership function
  • 模糊算子 Fuzzy operator
    • 并算子 Union operator
    • 交算子 Intersection operator
    • 平衡算子 Equilibrium operator
  • 中心平均解模糊器 Center average defuzzifier

API使用的示例代码如下:

#include "fuzzyPID.h"

#define DOF 6

int main() {
    // Default fuzzy rule base of delta kp/ki/kd
    int rule_base[][qf_default] = {
            //delta kp rule base
            {PB, PB, PM, PM, PS, ZO, ZO},
            {PB, PB, PM, PS, PS, ZO, NS},
            {PM, PM, PM, PS, ZO, NS, NS},
            {PM, PM, PS, ZO, NS, NM, NM},
            {PS, PS, ZO, NS, NS, NM, NM},
            {PS, ZO, NS, NM, NM, NM, NB},
            {ZO, ZO, NM, NM, NM, NB, NB},
            //delta ki rule base
            {NB, NB, NM, NM, NS, ZO, ZO},
            {NB, NB, NM, NS, NS, ZO, ZO},
            {NB, NM, NS, NS, ZO, PS, PS},
            {NM, NM, NS, ZO, PS, PM, PM},
            {NM, NS, ZO, PS, PS, PM, PB},
            {ZO, ZO, PS, PS, PM, PB, PB},
            {ZO, ZO, PS, PM, PM, PB, PB},
            //delta kd rule base
            {PS, NS, NB, NB, NB, NM, PS},
            {PS, NS, NB, NM, NM, NS, ZO},
            {ZO, NS, NM, NM, NS, NS, ZO},
            {ZO, NS, NS, NS, NS, NS, ZO},
            {ZO, ZO, ZO, ZO, ZO, ZO, ZO},
            {PB, PS, PS, PS, PS, PS, PB},
            {PB, PM, PM, PM, PS, PS, PB}};

    // Default parameters of membership function
    int mf_params[4 * qf_default] = {-3, -3, -2, 0,
                                     -3, -2, -1, 0,
                                     -2, -1,  0, 0,
                                     -1,  0,  1, 0,
                                      0,  1,  2, 0,
                                      1,  2,  3, 0,
                                      2,  3,  3, 0};

    // Default parameters of pid controller
    float fuzzy_pid_params[DOF][pid_params_count] = {{0.65f,  0,     0,    0, 0.5f,  -2.4f,    1},
                                                     {-0.34f, 0,     0,    0, 0.5f, 0.536f, 2.3f},
                                                     {-1.1f,  0,     0,    0, 0.5f,  0.00f,    1},
                                                     {-2.4f,  0,     0,    0, 0.5f,   2.3f,    1},
                                                     {1.2f,   0,     0,    0, 0.5f,  -0.7f, 2.3f},
                                                     {1.2f,   0.05f, 0.1f, 0,    0,      0,    1}};

    // Obtain the PID controller vector according to the parameters
    struct PID **pid_vector = fuzzy_vector_pid_init(fuzzy_pid_params, 2.0f, 4, 1, 0, mf_params, rule_base, DOF);

    printf("output:\n");
    bool direct[DOF] = {true, false, false, false, true, true};
    float real = 0;
    float idea = max_error * 0.9f;
    for (int j = 0; j < 500; ++j) {
        int out = fuzzy_pid_motor_pwd_output(real, idea, direct[5], pid_vector[5]);
        real += (float) (out - middle_pwm_output) / (float) middle_pwm_output * (float) max_error * 0.1f;
        printf("%d,%f\n", out, real);
    }

    delete_pid_vector(pid_vector, DOF);
    return 0;
}

下面进行详细讲解,一般的模糊控制流程图如下:
在这里插入图片描述

可以需要根据参考输入与被控对象的实际输出产生的误差 e e e 、误差变化量 Δ e \Delta e Δe 以及整定得的模糊规则表获取最终的模糊控制量。本项目主要针对模糊PID控制算法,所以选择的模糊条件语句为双输入多输出,即:

IF  e  is  A ∨ Δ e  is  B  THEN  Δ k p  is  C 1  and  Δ k i  is  C 2  and  Δ k d  is  C 3 ⋯ \text{IF } e \text{ is } A \vee \Delta e \text{ is } B \text{ THEN } \Delta k_p \text{ is } C_1 \text{ and } \Delta k_i \text{ is } C_2 \text{ and } \Delta k_d \text{ is } C_3 \cdots IF e is AΔe is B THEN Δkp is C1 and Δki is C2 and Δkd is C3

其中 ∨ \vee 代表并 (and) 操作,当然也可以用或 (or, ∧ \wedge ) 生成条件语句。同时由于模糊概念的存在,误差 e e e 、误差变化量 Δ e \Delta e Δe A A A B B B 呈一定概率,该概率则使用隶属度函数计算得出。项目的源码实现如下:

int j = 0;
for (int i = 0; i < qf_default; ++i) {
    float temp = mf(e, fuzzy_struct->mf_type[0], fuzzy_struct->mf_params + 4 * i);
    if (temp > 1e-4) {
        membership[j] = temp;
        index[j++] = i;
    }
}

count[0] = j;

for (int i = 0; i < qf_default; ++i) {
    float temp = mf(de, fuzzy_struct->mf_type[1], fuzzy_struct->mf_params + 4 * i);
    if (temp > 1e-4) {
        membership[j] = temp;
        index[j++] = i;
    }
}

count[1] = j - count[0];

其中使用 fuzzy_struct->mf_type 存储隶属度函数类型, fuzzy_struct->mf_params 存储隶属度函数所需的参数,通过调用 mf 便可实现隶属度的计算,同时多输入的情况下需要使用交并函数(模糊算子)求出联合隶属度。项目的源码实现如下:

// Joint membership
float joint_membership[count[0] * count[1]];

for (int i = 0; i < count[0]; ++i) {
    for (int j = 0; j < count[1]; ++j) {
        joint_membership[i * count[1] + j] = fo(membership[i], membership[count[0] + j], fuzzy_struct->fo_type);
    }
}

其中使用 fuzzy_struct->fo_type 存储交并函数类型,通过调用 fo 实现联合隶属度的求取。在得到每个语言值的联合隶属度,便可以通过模糊推理求取。项目的源码实现如下:

// Mean of centers defuzzifier, only for two input multiple index
void moc(const float *joint_membership, const unsigned int *index, const unsigned int *count, struct fuzzy *fuzzy_struct) {

    float denominator_count = 0;
    float numerator_count[fuzzy_struct->output_num];
    for (unsigned int l = 0; l < fuzzy_struct->output_num; ++l) {
        numerator_count[l] = 0;
    }

    for (int i = 0; i < count[0]; ++i) {
        for (int j = 0; j < count[1]; ++j) {
            denominator_count += joint_membership[i * count[1] + j];
        }
    }

    for (unsigned int k = 0; k < fuzzy_struct->output_num; ++k) {
        for (unsigned int i = 0; i < count[0]; ++i) {
            for (unsigned int j = 0; j < count[1]; ++j) {
                numerator_count[k] += joint_membership[i * count[1] + j] *
                                      fuzzy_struct->rule_base[k * qf_default * qf_default + index[i] * qf_default +
                                                              index[count[0] + j]];
            }
        }
    }

    for (unsigned int l = 0; l < fuzzy_struct->output_num; ++l) {
        fuzzy_struct->output[l] = numerator_count[l] / denominator_count;
    }
}

最终便可以实现模糊PID控制算法了。同时项目中提供了便捷的模糊PID控制器的数组生成器,便于生成多个控制器服务于多自由度控制需求,调用接口如下:

struct PID **
fuzzy_pid_vector_init(float params[][pid_params_count], float delta_k, unsigned int mf_type, unsigned int fo_type,
                      unsigned int df_type, int *mf_params, int rule_base[][qf_default],
                      unsigned int count);

其中 count 用于设定控制器个数,rule_base 用于传递模糊规则库,delta_k 用于控制PID的三个参数在初始值的基础上可以调节的程度,params 用于传递基础的PID参数,mf_typefo_typedf_type三个参数分别决定了隶属度函数类型、模糊算子类型以及解模糊器类型。

文中的理论分析以及模糊规则表摘自东北大学毛志忠老师编写的《先进控制技术》

  • 33
    点赞
  • 297
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FlameAlpha

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值