FuzzyPID

发布于:2024-06-30 ⋅ 阅读:(19) ⋅ 点赞:(0)

#include <stdio.h>

typedef struct FuzzyPID

{

       int  num_area ; //划分区域个数

    //float e_max;  //误差做大值

    //float e_min;  //误差最小值

    //float ec_max;  //误差变化最大值

    //float ec_min;  //误差变化最小值

    //float kp_max, kp_min;

    float e_membership_values[7] ; //输入e的隶属值

    float ec_membership_values[7] ;//输入de/dt的隶属值

    float kp_menbership_values[7] ;//输出增量kp的隶属值

    float ki_menbership_values[7] ; //输出增量ki的隶属值

    float kd_menbership_values[7] ;  //输出增量kd的隶属值

    float fuzzyoutput_menbership_values[7];

    //int menbership_values[7] = {-3,-};

    float kp;                       //PID参数kp

    float ki;                       //PID参数ki

    float kd;                       //PID参数kd

    float qdetail_kp;               //增量kp对应论域中的值

    float qdetail_ki;               //增量ki对应论域中的值

    float qdetail_kd;               //增量kd对应论域中的值

    float qfuzzy_output;

    float detail_kp;                //输出增量kp

    float detail_ki;                //输出增量ki

    float detail_kd;                //输出增量kd

    float fuzzy_output;

    float qerro;                    //输入e对应论域中的值

    float qerro_c;                  //输入de/dt对应论域中的值

    float errosum;

    float e_gradmembership[2];      //输入e的隶属度

    float ec_gradmembership[2];     //输入de/dt的隶属度

    int e_grad_index[2];            //输入e隶属度在规则表的索引

    int ec_grad_index[2];           //输入de/dt隶属度在规则表的索引

    float gradSums[7] ;

    float KpgradSums[7];   //输出增量kp总的隶属度

    float KigradSums[7] ;   //输出增量ki总的隶属度

    float KdgradSums[7] ;   //输出增量kd总的隶属度

   

    int  Kp_rule_list[7][7];

    int  Ki_rule_list[7][7];

    int  Kd_rule_list[7][7];

    int  Fuzzy_rule_list[7][7];


 

    //private:

}FuzzyPID;

typedef struct

{

    float e_max ;//误差最大范围

    float e_min ;//误差最小

    float ec_max;//误差的微分范围

    float ec_min;//误差的微分范围

    float kp_max;//p的范围

    float kp_min;

    float ki_max ;//i的范围

    float ki_min;

    float kd_max;//d的范围

    float kd_min;

    float erro;//误差

    float erro_c;//误差的微分

    float erro_pre;//上一次的误差

    float erro_ppre;//上上次的误差

}range;//修改变量

typedef struct

{

    float erro;

    float erro_c;

    float erro_pre;

    float erro_ppre;


 

}Error;

#define NB -3

#define NM - 2

#define NS - 1

#define ZO 0

#define PS 1

#define PM 2

#define PB 3

int  Kp_rule[7][7] = { {PB,PB,PM,PM,PS,ZO,ZO},     //kp规则表

                               {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} };

int  Ki_rule[7][7] = { {NB,NB,NM,NM,NS,ZO,ZO},     //ki规则表

                            {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} };

int  Kd_rule[7][7] = { {PS,NS,NB,NB,NB,NM,PS},    //kd规则表

                            {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,NS,PS,PS,PS,PS,PB},

                            {PB,PM,PM,PM,PS,PS,PB} };

int  Fuzzy_rule[7][7] = { {PB,PB,PB,PB,PM,ZO,ZO},

                               {PB,PB,PB,PM,PM,ZO,ZO},

                               {PB,PM,PM,PS,ZO,NS,NM},

                               {PM,PM,PS,ZO,NS,NM,NM},

                               {PS,PS,ZO,NM,NM,NM,NB},

                               {ZO,ZO,ZO,NM,NB,NB,NB},

                               {ZO,NS,NB,NB,NB,NB,NB} };

float values[7] = { -3,-2,-1,0,1,2,3 }; //输入e的隶属值

void FuzzyPID_Init(FuzzyPID* pid)  //构造函数

{

    int i, j;

    pid->num_area = 8;

    pid->kp = 0;

    pid->ki = 0;

    pid->kd = 0;

    pid->fuzzy_output = 0;

    pid->qdetail_kp = 0;

    pid->qdetail_ki = 0;

    pid->qdetail_kd = 0;

    pid->qfuzzy_output = 0;

    pid->errosum = 0;

    for ( i = 0; i < 7; i++)

    {

        for ( j = 0; j < 7; j++)

        {

            pid->Kp_rule_list[i][j] = Kp_rule[i][j];

            pid->Ki_rule_list[i][j] = Ki_rule[i][j];

            pid->Kd_rule_list[i][j] = Kd_rule[i][j];

            pid->Fuzzy_rule_list[i][j] = Fuzzy_rule[i][j];

        }

    }

    for ( i = 0; i < 7; i++)

    {

        pid->e_membership_values[i] = values[i];

        pid->ec_membership_values[i] = values[i];

        pid->kp_menbership_values[i] = values[i];

        pid->ki_menbership_values[i] = values[i];

        pid->kd_menbership_values[i] = values[i];

        pid->fuzzyoutput_menbership_values[i] = values[i];

        pid->gradSums[i] = 0;

        pid->KpgradSums[i] = 0;

        pid->KigradSums[i] = 0;

        pid->KdgradSums[i] = 0;

    }

}




 

//输入e与de/dt隶属度计算函数///

void Get_grad_membership(FuzzyPID* pid,float erro, float erro_c)

{

    int i;

    //当误差在这个范围

    if (erro > pid->e_membership_values[0] && erro < pid->e_membership_values[6])

    {

        //6个区域

        for ( i = 0; i < pid->num_area - 2; i++)

        {

            //如果误差在区间区域内

            if (erro >= pid->e_membership_values[i] && erro <= pid->e_membership_values[i + 1])

            {

                //e的隶属度

                //PM

                pid->e_gradmembership[0] = -(erro - pid->e_membership_values[i + 1]) / (pid->e_membership_values[i + 1] - pid->e_membership_values[i]);

                //PB

                pid->e_gradmembership[1] = 1 + (erro - pid->e_membership_values[i + 1]) / (pid->e_membership_values[i + 1] - pid->e_membership_values[i]);

                //记录是在哪两个区间内

                pid->e_grad_index[0] = i;

                pid->e_grad_index[1] = i + 1;

                break;

            }

        }

    }

    else

    {

        //如果误差的止小于等于论域的最小值

        if (erro <= pid->e_membership_values[0])

        {

            pid->e_gradmembership[0] = 1;

            pid->e_gradmembership[1] = 0;

            pid->e_grad_index[0] = 0;

            pid->e_grad_index[1] = -1;

        }//超出范围了

        else if (erro >= pid->e_membership_values[6])

        {

            pid->e_gradmembership[0] = 1;

            pid->e_gradmembership[1] = 0;

            pid->e_grad_index[0] = 6;

            pid->e_grad_index[1] = -1;

        }

    }

    //误差的微分

    if (erro_c > pid->ec_membership_values[0] && erro_c < pid->ec_membership_values[6])

    {

        for ( i = 0; i < pid->num_area - 2; i++)

        {

            if (erro_c >= pid->ec_membership_values[i] && erro_c <= pid->ec_membership_values[i + 1])

            {

                pid->ec_gradmembership[0] = -(erro_c - pid->ec_membership_values[i + 1]) / (pid->ec_membership_values[i + 1] - pid->ec_membership_values[i]);

                pid->ec_gradmembership[1] = 1 + (erro_c - pid->ec_membership_values[i + 1]) / (pid->ec_membership_values[i + 1] - pid->ec_membership_values[i]);

                pid->ec_grad_index[0] = i;

                pid->ec_grad_index[1] = i + 1;

                break;

            }

        }

    }

    else

    {

        if (erro_c <= pid->ec_membership_values[0])

        {

            pid->ec_gradmembership[0] = 1;

            pid->ec_gradmembership[1] = 0;

            pid->ec_grad_index[0] = 0;

            pid->ec_grad_index[1] = -1;

        }

        else if (erro_c >= pid->ec_membership_values[6])

        {

            pid->ec_gradmembership[0] = 1;

            pid->ec_gradmembership[1] = 0;

            pid->ec_grad_index[0] = 6;

            pid->ec_grad_index[1] = -1;

        }

    }

}

// //获取输出增量kp, ki, kd的总隶属度 /

void GetSumGrad(FuzzyPID* pid)

{

    int i,j;

    //划分八个区域

    for ( i = 0; i <= pid->num_area - 1; i++)

    {

        pid->KpgradSums[i] = 0;

        pid->KigradSums[i] = 0;

        pid->KdgradSums[i] = 0;

        //把PID的各个隶属值清零

    }

    for ( i = 0; i < 2; i++)//循环两次

    {

        if (pid->e_grad_index[i] == -1)//误差有没有爆表

        {

            continue;

        }

        for ( j = 0; j < 2; j++)//

        {

            if (pid->ec_grad_index[j] != -1)//误差的微分有没有爆表

            {

                int indexKp = pid->Kp_rule_list[pid->e_grad_index[i]][pid->ec_grad_index[j]] + 3;

                int indexKi = pid->Ki_rule_list[pid->e_grad_index[i]][pid->ec_grad_index[j]] + 3;

                int indexKd = pid->Kd_rule_list[pid->e_grad_index[i]][pid->ec_grad_index[j]] + 3;

                //gradSums[index] = gradSums[index] + (e_gradmembership[i] * ec_gradmembership[j])* Kp_rule_list[e_grad_index[i]][ec_grad_index[j]];

                pid->KpgradSums[indexKp] = pid->KpgradSums[indexKp] + (pid->e_gradmembership[i] * pid->ec_gradmembership[j]);

                pid->KigradSums[indexKi] = pid->KigradSums[indexKi] + (pid->e_gradmembership[i] * pid->ec_gradmembership[j]);

                pid->KdgradSums[indexKd] = pid->KdgradSums[indexKd] + (pid->e_gradmembership[i] * pid->ec_gradmembership[j]);

            }

            else

            {

                continue;

            }

        }

    }

}

//计算输出增量kp, kd, ki对应论域值//

void GetOUT(FuzzyPID* pid)

{

    int i;

    for ( i = 0; i < pid->num_area - 1; i++)

    {

        pid->qdetail_kp +=pid->kp_menbership_values[i] * pid->KpgradSums[i];

        pid->qdetail_ki += pid->ki_menbership_values[i] * pid->KigradSums[i];

        pid->qdetail_kd += pid->kd_menbership_values[i] * pid->KdgradSums[i];

    }

}

///区间映射函数///

float Quantization(float maximum, float minimum, float x)

{

    float qvalues = 6.0 * (x - minimum) / (maximum - minimum) - 3;

    //float qvalues=6.0*()

    return qvalues;

    //qvalues[1] = 3.0 * ecerro / (maximum - minimum);

}

//反区间映射函数

float Inverse_quantization(float maximum, float minimum, float qvalues)

{

    float x = (maximum - minimum) * (qvalues + 3) / 6 + minimum;

    return x;

}

//模糊PID控制实现函数/

float FuzzyPIDcontroller(FuzzyPID* pid, range* rang, Error* error, float Target, float actual)

{

   

    error->erro_ppre = error->erro_pre;

    error->erro_pre = error->erro;

    error->erro = Target - actual;

    error->erro_c = error->erro - error->erro_pre;

    pid->errosum += error->erro;

    //Arear_dipart(e_max, e_min, ec_max, ec_min, kp_max, kp_min,ki_max,ki_min,kd_max,kd_min);

    pid->qerro = Quantization(rang->e_max, rang->e_min, error->erro);//区间映射

    pid->qerro_c = Quantization(rang->ec_max, rang->ec_min, error->erro_c);//区间映射

    //把他们缩小到0123范围内

    Get_grad_membership(pid,pid->qerro, pid->qerro_c);

    //获取输出增量kp, ki, kd的总隶属度

    GetSumGrad(pid);

    //计算输出增量kp, kd, ki对应论域值//

    GetOUT(pid);

    pid->detail_kp = Inverse_quantization(rang->kp_max, rang->kp_min, pid->qdetail_kp);

    pid->detail_ki = Inverse_quantization(rang->ki_max, rang->ki_min, pid->qdetail_ki);

    pid->detail_kd = Inverse_quantization(rang->kd_max, rang->kd_min, pid->qdetail_kd);

    pid->qdetail_kd = 0;

    pid->qdetail_ki = 0;

    pid->qdetail_kp = 0;

    /*if (qdetail_kp >= kp_max)

        qdetail_kp = kp_max;

    else if (qdetail_kp <= kp_min)

        qdetail_kp = kp_min;

    if (qdetail_ki >= ki_max)

        qdetail_ki = ki_max;

    else if (qdetail_ki <= ki_min)

        qdetail_ki = ki_min;

    if (qdetail_kd >= kd_max)

        qdetail_kd = kd_max;

    else if (qdetail_kd <= kd_min)

        qdetail_kd = kd_min;*/

    pid->kp = pid->kp + pid->detail_kp;

    pid->ki = pid->ki + pid->detail_ki;

    pid->kd  =pid->kd + pid->detail_kd;

    //确定范围

    if (pid->kp < 0)

        pid->kp = 0;

    if (pid->ki < 0)

        pid->ki = 0;

    if (pid->kd < 0)

        pid->kd = 0;

    pid->detail_kp = 0;

    pid->detail_ki = 0;

    pid->detail_kd = 0;

    //增量式PID

    float output = pid->kp * (error->erro - error->erro_pre) + pid->ki * error->erro + pid->kd * (error->erro - 2 * error->erro_pre + error->erro_ppre);

    return output;

}

range rang = { 40,-40,5,-5,100,-100,0.1,-0.1,0.01,-0.01 };

Error error = { 0,0,0,0 };

int main()

{

    FuzzyPID myfuzzypid;

    FuzzyPID_Init(&myfuzzypid);

    float Target =20;//目标值

    float actual = 0;//实际值

    for (int i = 0; i < 100; i++)

    {

        float u;

        u = FuzzyPIDcontroller(&myfuzzypid, &rang, &error, Target, actual);

        actual += u;

        printf("i:%d\tTarget:%f\tActual:%f\t\n",i,Target,actual);

        //std::cout << "i:" << i << "\t" << "Target:" << Target << "\t" << "Actual:" << actual << std::endl;

    }

}