[Carro inteligente] Explicação detalhada do princípio de controle PID difuso e implementação de código

Controle PID difuso


Este artigo consiste principalmente em três partes: o princípio do controlador PID fuzzy, a implementação e teste do controlador PID fuzzy em C++.

1. Princípio do PID difuso

O processo de controle PID fuzzy é mostrado na figura abaixo. O erro e entre o valor alvo Xtarget e o valor de saída Xout e a taxa de mudança de/dt de e são usados ​​como entrada do controlador fuzzy. O controlador fuzzy primeiro executa fuzzy processamento na entrada e, em seguida, executa o raciocínio difuso e, finalmente, defuzzifica o resultado do raciocínio difuso para produzir os três parâmetros kp, ki, kd do controlador PID , de modo a obter o efeito de ajuste adaptativo dos parâmetros do controlador PID.
insira a descrição da imagem aqui

De acordo com a descrição acima, o controlador fuzzy é composto principalmente de três partes: defuzzificação, raciocínio fuzzy e defuzzificação . As três partes serão explicadas em detalhes a seguir.

1.1 Fuzzificação

Para realizar a fuzzificação, primeiro é necessário inicializar a fuzzificação, que inclui a determinação do domínio do discurso e a determinação da função de pertinência.

1.1.1 Área temática

Pode-se dizer que o domínio do discurso é um intervalo determinado artificialmente. Como a entrada e, de/dt e o intervalo de saída kp, ki, kd são diferentes, é melhor mapear a entrada para o domínio do discurso para unificação em processamento. Após determinar o escopo do domínio do discurso, é necessário realizar a classificação fuzzy no domínio do discurso, que é dividir o domínio do discurso. Assumindo que o domínio do discurso é [-3, 3], divida o domínio do discurso em 5 partes iguais, ou seja, [-3, -2], [-2, -1], [-1, 0], [0 , 1], [1, 2], [2, 3]. Em seguida, divida cada ponto final em graus, na ordem: -3—>NB (negativo grande), -2—>NM (negativo médio), -1——>NS (negativo pequeno), 0—>ZO(zero), 1 ---->PS(positivo pequeno), 2---->PM(positivo médio), 3---->PB(positivo grande). Supondo que o intervalo de entrada e seja [-10, 10], o valor de e neste momento é 8 e o valor após o mapeamento é 2,4 e 2,4 está no intervalo [2, 3], então o ponto está entre o meio e a direita. O diagrama esquemático é o seguinte:

1.1.2 Determinação da função de membro.

Funções de pertinência comuns incluem funções de pertinência triangulares, funções de pertinência trapezoidais e funções de pertinência parabólicas. Tomando a função de pertinência triangular mais simples como exemplo, a forma é mostrada na figura abaixo:

insira a descrição da imagem aqui

Como pode ser visto na figura acima, o intervalo de valores da função de pertinência é [0, 1]. Se o valor da entrada e após o mapeamento for 2,4, então os valores correspondentes à linha vermelha e à linha verde na figura abaixo são 0,6 e 0,4 respectivamente. Esses dois são o grau de pertinência, indicando que a probabilidade de o a entrada pertence a PM é 0,6, e a probabilidade de pertencer a PB é 0,4. Portanto, o grau de adesão também é uma probabilidade.

insira a descrição da imagem aqui

A partir da explicação do domínio do discurso e da função de pertinência acima, o processo de fuzzificação pode ser resumido: mapeamento de intervalo, e o grau de pertinência é calculado de acordo com a função de pertinência. O fluxograma é o seguinte:

insira a descrição da imagem aqui

1.2 Raciocínio confuso

Raciocínio difuso, ou seja, consultar a tabela de acordo com o grau de pertinência de e e de/dt para obter o tamanho da saída, ou seja, NB, NS, etc. Portanto, o trabalho central do raciocínio difuso é construir uma tabela de raciocínio. A tabela de inferência comumente utilizada pelo PID fuzzy é mostrada na figura abaixo:

insira a descrição da imagem aqui

insira a descrição da imagem aqui
insira a descrição da imagem aqui

O seguinte usa um exemplo para ilustrar como usar a tabela de regras.

Suponha que a entrada e neste momento seja 8, de/dt seja -12, e a faixa de e seja [-10,10], e a faixa de de/dt seja [-20,20]. Então, por meio de fuzzificação, os graus de pertinência de e são 0,6 (PM) e 0,4 (PB), e os graus de pertinência de de/dt são 0,8 (NM) e 0,2 (NS). Então, os graus de pertinência de e e de/dt são dois Combinando os dois e realizando uma pesquisa na tabela, obtém-se o relacionamento na tabela a seguir:

insira a descrição da imagem aqui

Em seguida, calcule o grau de pertinência de cada saída Kp, Ki, Kd.

Tome Kp como exemplo:

insira a descrição da imagem aqui

Da mesma forma, Ki e Kd também calculam o grau de pertinência.

Finalmente, o grau de pertinência de cada saída é integrado, como Kp. De acordo com o cálculo acima, o grau de pertinência de Kp é 0,8 (ZO), 0,12 (NS) e 0,08 (NM).

1.3 Desfoque

A defuzzificação consiste em calcular o valor da saída no domínio do discurso de acordo com o grau de pertinência de cada saída obtido por inferência difusa e, em seguida, obter a saída de acordo com a relação de mapeamento de intervalo.

1.3.1 Calcular o valor da saída no domínio do discurso

O exemplo acima é usado para ilustrar o processo de cálculo. Pode ser visto acima que o grau de pertinência de Kp é 0,8 (ZO), 0,12 (NS) e 0,08 (NM). Na explicação do universo, o valor de ZO foi definido como 0, o valor de NS é definido como -1 e o valor de NM O valor é definido como -2. Então a expectativa de Kp é:

insira a descrição da imagem aqui

Tomando a expectativa como o valor de Kp no domínio do discurso, após determinar o intervalo de Kp, o valor de saída de Kp pode ser obtido de acordo com a fórmula de mapeamento de intervalo.

O acima é o fluxo do controlador difuso.

Vale a pena notar que a saída Kp, Ki, Kd são incrementos. Durante a inicialização, o intervalo (intervalo) de entrada e saída deve ser determinado para mapeamento de intervalo.

2.1 Implementação C++ do controlador PID difuso

Esta versão da função de pertinência é uma função de pertinência triangular fixa e o domínio do discurso é fixado em [-3, 3] .

FuzzyPID.h

#ifndef FuzzyPID_H
#define FuzzyPID_H
class FuzzyPID
{
    
    
public:
    FuzzyPID();
    ~FuzzyPID();
    void Get_grad_membership(float erro, float erro_c);
    float Quantization(float maximum, float minimum, float x);
    float Inverse_quantization(float maximum, float minimum, float qvalues);
    void GetSumGrad();
    void GetOUT();
    float FuzzyPIDcontroller(float e_max, float e_min, float ec_max, float ec_min, float kp_max, float kp_min, float erro, float erro_c, float ki_max, float ki_min,float kd_max, float kd_min,float erro_pre, float errp_ppre);
    const int  num_area = 8; //划分区域个数
    //float e_max;  //误差做大值
    //float e_min;  //误差最小值
    //float ec_max;  //误差变化最大值
    //float ec_min;  //误差变化最小值
    //float kp_max, kp_min;
    float e_membership_values[7] = {
    
    -3,-2,-1,0,1,2,3}; //输入e的隶属值
    float ec_membership_values[7] = {
    
     -3,-2,-1,0,1,2,3 };//输入de/dt的隶属值
    float kp_menbership_values[7] = {
    
     -3,-2,-1,0,1,2,3 };//输出增量kp的隶属值
    float ki_menbership_values[7] = {
    
     -3,-2,-1,0,1,2,3 }; //输出增量ki的隶属值
    float kd_menbership_values[7] = {
    
     -3,-2,-1,0,1,2,3 };  //输出增量kd的隶属值
    float fuzzyoutput_menbership_values[7] = {
    
     -3,-2,-1,0,1,2,3 };

    //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] = {
    
    0,0,0,0,0,0,0};
    float KpgradSums[7] = {
    
     0,0,0,0,0,0,0 };   //输出增量kp总的隶属度
    float KigradSums[7] = {
    
     0,0,0,0,0,0,0 };   //输出增量ki总的隶属度
    float KdgradSums[7] = {
    
     0,0,0,0,0,0,0 };   //输出增量kd总的隶属度
    int NB = -3, NM = -2, NS = -1, ZO = 0, PS = 1, PM = 2, PB = 3; //论域隶属值

    int  Kp_rule_list[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_list[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_list[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_list[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}};


//private:

};
#endif

FuzzyPID.cpp

#include "FuzzyPID.h"
FuzzyPID::FuzzyPID()  //构造函数
{
    
    
    kp = 0;
    ki = 0;
    kd = 0;
    fuzzy_output = 0;
    qdetail_kp = 0;
    qdetail_ki = 0;
    qdetail_kd = 0;
    qfuzzy_output = 0;
    errosum = 0;
}

FuzzyPID::~FuzzyPID()//析构函数
{
    
    
}

//输入e与de/dt隶属度计算函数///
void FuzzyPID::Get_grad_membership(float erro,float erro_c)  
{
    
    
    if (erro > e_membership_values[0] && erro < e_membership_values[6])
    {
    
    
        for (int i = 0; i < num_area - 2; i++)
        {
    
    
            if (erro >= e_membership_values[i] && erro <= e_membership_values[i + 1])
            {
    
    
                e_gradmembership[0] = -(erro - e_membership_values[i + 1]) / (e_membership_values[i + 1] - e_membership_values[i]);
                e_gradmembership[1] = 1+(erro - e_membership_values[i + 1]) / (e_membership_values[i + 1] - e_membership_values[i]);
                e_grad_index[0] = i;
                e_grad_index[1] = i + 1;
                break;
            }
        }
    }
    else
    {
    
    
        if (erro <= e_membership_values[0])
        {
    
    
            e_gradmembership[0] = 1;
            e_gradmembership[1] = 0;
            e_grad_index[0] = 0;
            e_grad_index[1] = -1;
        }
        else if (erro >= e_membership_values[6])
        {
    
    
            e_gradmembership[0] = 1;
            e_gradmembership[1] = 0;
            e_grad_index[0] = 6;
            e_grad_index[1] = -1;
        }
    }

    if (erro_c > ec_membership_values[0] && erro_c < ec_membership_values[6])
    {
    
    
        for (int i = 0; i < num_area - 2; i++)
        {
    
    
            if (erro_c >= ec_membership_values[i] && erro_c <= ec_membership_values[i + 1])
            {
    
    
                ec_gradmembership[0] = -(erro_c - ec_membership_values[i + 1]) / (ec_membership_values[i + 1] - ec_membership_values[i]);
                ec_gradmembership[1] = 1 + (erro_c - ec_membership_values[i + 1]) / (ec_membership_values[i + 1] - ec_membership_values[i]);
                ec_grad_index[0] = i;
                ec_grad_index[1] = i + 1;
                break;
            }
        }
    }
    else
    {
    
    
        if (erro_c <= ec_membership_values[0])
        {
    
    
            ec_gradmembership[0] = 1;
            ec_gradmembership[1] = 0;
            ec_grad_index[0] = 0;
            ec_grad_index[1] = -1;
        }
        else if (erro_c >= ec_membership_values[6])
        {
    
    
            ec_gradmembership[0] = 1;
            ec_gradmembership[1] = 0;
            ec_grad_index[0] = 6;
            ec_grad_index[1] = -1;
        }
    }

}

/获取输出增量kp,ki,kd的总隶属度/
void FuzzyPID::GetSumGrad()
{
    
    
    for (int i = 0; i <= num_area - 1; i++)
    {
    
    
        KpgradSums[i] = 0;
        KigradSums[i] = 0;
    KdgradSums[i] = 0;

    }
  for (int i=0;i<2;i++)
  {
    
    
      if (e_grad_index[i] == -1)
      {
    
    
       continue;
      }
      for (int j = 0; j < 2; j++)
      {
    
    
          if (ec_grad_index[j] != -1)
          {
    
    
              int indexKp = Kp_rule_list[e_grad_index[i]][ec_grad_index[j]] + 3;
              int indexKi = Ki_rule_list[e_grad_index[i]][ec_grad_index[j]] + 3;
              int indexKd = Kd_rule_list[e_grad_index[i]][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]];
              KpgradSums[indexKp]= KpgradSums[indexKp] + (e_gradmembership[i] * ec_gradmembership[j]);
              KigradSums[indexKi] = KigradSums[indexKi] + (e_gradmembership[i] * ec_gradmembership[j]);
              KdgradSums[indexKd] = KdgradSums[indexKd] + (e_gradmembership[i] * ec_gradmembership[j]);
          }
          else
          {
    
    
            continue;
          }

      }
  }

}

计算输出增量kp,kd,ki对应论域值//
void FuzzyPID::GetOUT()
{
    
    
    for (int i = 0; i < num_area - 1; i++)
    {
    
    
        qdetail_kp += kp_menbership_values[i] * KpgradSums[i];
        qdetail_ki += ki_menbership_values[i] * KigradSums[i];
        qdetail_kd+= kd_menbership_values[i] * KdgradSums[i];
    }
}

//模糊PID控制实现函数/
float FuzzyPID::FuzzyPIDcontroller(float e_max, float e_min, float ec_max, float ec_min, float kp_max, float kp_min, float erro, float erro_c,float ki_max,float ki_min,float kd_max,float kd_min,float erro_pre,float errp_ppre)
{
    
    
    errosum += erro;
    //Arear_dipart(e_max, e_min, ec_max, ec_min, kp_max, kp_min,ki_max,ki_min,kd_max,kd_min);
    qerro = Quantization(e_max, e_min, erro);
    qerro_c = Quantization(ec_max, ec_min, erro_c);
    Get_grad_membership(qerro, qerro_c);
    GetSumGrad();
    GetOUT();
    detail_kp = Inverse_quantization(kp_max, kp_min, qdetail_kp);
    detail_ki = Inverse_quantization(ki_max, ki_min, qdetail_ki);
    detail_kd = Inverse_quantization(kd_max, kd_min, qdetail_kd);
    qdetail_kd = 0;
    qdetail_ki = 0;
    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;*/
    kp = kp + detail_kp;
    ki = ki + detail_ki;
    kd = kd + detail_kd;
    if (kp < 0)
        kp = 0;
    if (ki < 0)
        ki = 0;
    if (kd < 0)
        kd = 0;
    detail_kp = 0;
  detail_ki=0;
  detail_kd=0;
  float output = kp*(erro - erro_pre) + ki * erro + kd * (erro - 2 * erro_pre + errp_ppre);
    return output;
}

///区间映射函数///
float FuzzyPID::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 FuzzyPID::Inverse_quantization(float maximum, float minimum, float qvalues)
{
    
    
    float x = (maximum - minimum) *(qvalues + 3)/6 + minimum;
    return x;
}

Teste o controlador PID difuso:

#include <iostream>
#include "FuzzyPID.h"

int main()
{
    
    
    FuzzyPID myfuzzypid;
    float Target = 600;
    float actual = 0;
    float e_max =1000;
    float e_min = -1000;
    float ec_max = 800;
    float ec_min = -800;
    float kp_max =100;
    float kp_min = -100;
    float ki_max = 0.1;
    float ki_min = -0.1;
    float kd_max = 0.01;
    float kd_min = -0.01;
    float erro;
    float erro_c;
    float erro_pre = 0;
    float erro_ppre = 0;
    erro =Target - actual;
    erro_c = erro - erro_pre;
    for (int i = 0; i < 100; i++)
    {
    
    
        float u;
        u = myfuzzypid.FuzzyPIDcontroller(e_max, e_min, ec_max, ec_min, kp_max, kp_min, erro, \
                                          erro_c,ki_max,ki_min,kd_max,kd_min,erro_pre,erro_ppre);
        actual +=u;
        erro_ppre = erro_pre;
        erro_pre = erro;
        erro = Target - actual;
        erro_c= erro - erro_pre;
        std::cout << "i:" << i << "\t" << "Target:" << Target << "\t" << "Actual:" << actual  << std::endl;
    }
}

Resultado da execução :

img

Este artigo reproduz principalmente a parte do princípio de controle difuso e as rotinas de código e as publica no CSDN para conveniência de gerenciamento e coleta.

Endereço original: https://www.codeong.com/cs105632129/

Acho que você gosta

Origin blog.csdn.net/weixin_45636061/article/details/124996230
Recomendado
Clasificación