SoFunction
Updated on 2025-03-10

Implementing fuzzy PID control algorithm in c#

The effect of running depends on the test method of each class, and call it yourself to test it.

The purpose is to see which algorithm is easy to use. When transplanting, it is simple and has not understood the algorithm. The code structure has not been changed. It is just ported to C# to view the code and test. It is also very convenient for everyone to copy it. Copy the entire class to the .cs file.

This algorithm works normally when the actual value is lower than the target value. There will be problems after it exceeds it. I don’t know how to train it.

using System;
using ;
using ;
using ;
using ;
using ;

namespace FuzzyPID
{
  class FuzzyPID
  {
    public const int N = 7;

    double target; //The system's control target    double actual; //The actual value obtained by sampling    double e; //error    double e_pre_1; //The last error    double e_pre_2; //The last error    double de;   //The rate of change of error    double emax;  //The upper limit of error basic theory domain    double demax;  //The upper limit of the basic theory domain of error debate rate    double delta_Kp_max;  //Upper limit of delta_kp output    double delta_Ki_max;  //delta_ki output upper limit    double delta_Kd_max;  //delta_kd output upper limit    double Ke;   //Ke=n/emax, the quantization theory domain is [-3,-2,-1,0,1,2,3]    double Kde;   //Kde=n/demax, the quantization theory domain is [-3,-2,-1,0,1,2,3]    double Ku_p;  //Ku_p=Kpmax/n, the quantization theory domain is [-3,-2,-1,0,1,2,3]    double Ku_i;  //Ku_i=Kimax/n, the quantization theory domain is [-3,-2,-1,0,1,2,3]    double Ku_d;  //Ku_d=Kdmax/n, the quantization theory domain is [-3,-2,-1,0,1,2,3]    int[,] Kp_rule_matrix = new int[N, N];//Kp fuzzy rule matrix    int[,] Ki_rule_matrix = new int[N, N];//Ki fuzzy rule matrix    int[,] Kd_rule_matrix = new int[N, N];//Kd fuzzy rule matrix    string mf_t_e;    //E membership function type    string mf_t_de;   //De membership function type    string mf_t_Kp;   //Kp membership function type    string mf_t_Ki;   //Ki membership function type    string mf_t_Kd;   //Kd membership function type    double[] e_mf_paras; // Parameters of the membership function of error    double[] de_mf_paras;// Parameters of the deviation membership function of error    double[] Kp_mf_paras; //The parameters of the membership function of kp    double[] Ki_mf_paras; //Arguments of ki membership function    double[] Kd_mf_paras; //Arguments of the membership function of kd    double Kp;
    double Ki;
    double Kd;
    double A;
    double B;
    double C;

    public FuzzyPID(double e_max, double de_max, double kp_max, double ki_max, double kd_max, double Kp0, double Ki0, double Kd0)
    {
      emax = e_max;
      demax = de_max;
      delta_Kp_max = kp_max;
      delta_Ki_max = ki_max;
      delta_Kd_max = kd_max;
      e = target - actual;
      de = e - e_pre_1;
      Ke = (N / 2) / emax;
      Kde = (N / 2) / demax;
      Ku_p = delta_Kp_max / (N / 2);
      Ku_i = delta_Ki_max / (N / 2);
      Ku_d = delta_Kd_max / (N / 2);
      Kp = Kp0;
      Ki = Ki0;
      Kd = Kd0;
      A = Kp + Ki + Kd;
      B = -2 * Kd - Kp;
      C = Kd;
    }

    //Triangular membership function    double trimf(double x, double a, double b, double c)
    {
      double u;
      if (x >= a && x <= b)
        u = (x - a) / (b - a);
      else if (x > b && x <= c)
        u = (c - x) / (c - b);
      else
        u = 0;
      return u;
    }

    //Normal membership function    double gaussmf(double x, double ave, double sigma)
    {
      double u;
      if (sigma < 0)
      {
        throw new Exception("In gaussmf, sigma must larger than 0");
      }
      u = (-(((x - ave) / sigma), 2));
      return u;
    }

    //Trainform membership function    double trapmf(double x, double a, double b, double c, double d)
    {
      double u;
      if (x >= a && x < b)
        u = (x - a) / (b - a);
      else if (x >= b && x < c)
        u = 1;
      else if (x >= c && x <= d)
        u = (d - x) / (d - c);
      else
        u = 0;
      return u;
    }


    //Set fuzzy rules Matrix    public void setRuleMatrix(int[,] kp_m, int[,] ki_m, int[,] kd_m)
    {
      for (int i = 0; i < N; i++)
        for (int j = 0; j < N; j++)
        {
          Kp_rule_matrix[i, j] = kp_m[i, j];
          Ki_rule_matrix[i, j] = ki_m[i, j];
          Kd_rule_matrix[i, j] = kd_m[i, j];
        }

    }


    //Set subfunctions of fuzzy membership function    void setMf_sub(string type, double[] paras, int n)
    {
      int N_mf_e = 0, N_mf_de = 0, N_mf_Kp = 0, N_mf_Ki = 0, N_mf_Kd = 0;
      switch (n)
      {
        case 0:
          if (type == "trimf" || type == "gaussmf" || type == "trapmf")
            mf_t_e = type;
          else
            throw new Exception("Type of membership function must be \"trimf\" or \"gaussmf\" or \"trapmf\"");
          if (mf_t_e == "trimf")
            N_mf_e = 3;
          else if (mf_t_e == "gaussmf")
            N_mf_e = 2;
          else if (mf_t_e == "trapmf")
            N_mf_e = 4;

          e_mf_paras = new double[N * N_mf_e];
          for (int i = 0; i < N * N_mf_e; i++)
            e_mf_paras[i] = paras[i];
          break;

        case 1:
          if (type == "trimf" || type == "gaussmf" || type == "trapmf")
            mf_t_de = type;
          else
            throw new Exception("Type of membership function must be \"trimf\" or \"gaussmf\" or \"trapmf\"");
          if (mf_t_de == "trimf")
            N_mf_de = 3;
          else if (mf_t_de == "gaussmf")
            N_mf_de = 2;
          else if (mf_t_de == "trapmf")
            N_mf_de = 4;
          de_mf_paras = new double[N * N_mf_de];
          for (int i = 0; i < N * N_mf_de; i++)
            de_mf_paras[i] = paras[i];
          break;

        case 2:
          if (type == "trimf" || type == "gaussmf" || type == "trapmf")
            mf_t_Kp = type;
          else
            throw new Exception("Type of membership function must be \"trimf\" or \"gaussmf\" or \"trapmf\"");
          if (mf_t_Kp == "trimf")
            N_mf_Kp = 3;
          else if (mf_t_Kp == "gaussmf")
            N_mf_Kp = 2;
          else if (mf_t_Kp == "trapmf")
            N_mf_Kp = 4;
          Kp_mf_paras = new double[N * N_mf_Kp];
          for (int i = 0; i < N * N_mf_Kp; i++)
            Kp_mf_paras[i] = paras[i];
          break;

        case 3:
          if (type == "trimf" || type == "gaussmf" || type == "trapmf")
            mf_t_Ki = type;
          else
            throw new Exception("Type of membership function must be \"trimf\" or \"gaussmf\" or \"trapmf\"");
          if (mf_t_Ki == "trimf")
            N_mf_Ki = 3;
          else if (mf_t_Ki == "gaussmf")
            N_mf_Ki = 2;
          else if (mf_t_Ki == "trapmf")
            N_mf_Ki = 4;
          Ki_mf_paras = new double[N * N_mf_Ki];
          for (int i = 0; i < N * N_mf_Ki; i++)
            Ki_mf_paras[i] = paras[i];
          break;

        case 4:
          if (type == "trimf" || type == "gaussmf" || type == "trapmf")
            mf_t_Kd = type;
          else
            throw new Exception("Type of membership function must be \"trimf\" or \"gaussmf\" or \"trapmf\"");
          if (mf_t_Kd == "trimf")
            N_mf_Kd = 3;
          else if (mf_t_Kd == "gaussmf")
            N_mf_Kd = 2;
          else if (mf_t_Kd == "trapmf")
            N_mf_Kd = 4;
          Kd_mf_paras = new double[N * N_mf_Kd];
          for (int i = 0; i < N * N_mf_Kd; i++)
            Kd_mf_paras[i] = paras[i];
          break;

        default: break;
      }
    }


    //Set the types and parameters of the fuzzy membership function    public void setMf(string mf_type_e, double[] e_mf,
       string mf_type_de, double[] de_mf,
       string mf_type_Kp, double[] Kp_mf,
       string mf_type_Ki, double[] Ki_mf,
       string mf_type_Kd, double[] Kd_mf)
    {
      setMf_sub(mf_type_e, e_mf, 0);
      setMf_sub(mf_type_de, de_mf, 1);
      setMf_sub(mf_type_Kp, Kp_mf, 2);
      setMf_sub(mf_type_Ki, Ki_mf, 3);
      setMf_sub(mf_type_Kd, Kd_mf, 4);
    }

    //Implement fuzzy control    public double realize(double t, double a)
    {
      double[] u_e = new double[N],
        u_de = new double[N],
        u_u = new double[N];
      int[] u_e_index = new int[3], u_de_index = new int[3];//Suppose that one input activates up to 3 fuzzy subsets      double delta_Kp, delta_Ki, delta_Kd;
      double delta_u;
      target = t;
      actual = a;
      e = target - actual;
      de = e - e_pre_1;
      e = Ke * e;
      de = Kde * de;
      /* Fuzzy the error e*/
      int j = 0;
      for (int i = 0; i < N; i++)
      {
        if (mf_t_e == "trimf")
          u_e[i] = trimf(e, e_mf_paras[i * 3], e_mf_paras[i * 3 + 1], e_mf_paras[i * 3 + 2]);//efuzzy, calculate its membership        else if (mf_t_e == "gaussmf")
          u_e[i] = gaussmf(e, e_mf_paras[i * 2], e_mf_paras[i * 2 + 1]);//efuzzy, calculate its membership        else if (mf_t_e == "trapmf")
          u_e[i] = trapmf(e, e_mf_paras[i * 4], e_mf_paras[i * 4 + 1], e_mf_paras[i * 4 + 2], e_mf_paras[i * 4 + 3]);//efuzzy, calculate its membership
        if (u_e[i] != 0)
          u_e_index[j++] = i;        //Storing the subscript of the activated fuzzy subset can reduce the amount of calculation      }
      for (; j < 3; j++) u_e_index[j] = 0;       //Fill in 0 with the excess space
      /*Fuse the error rate de*/
      j = 0;
      for (int i = 0; i < N; i++)
      {
        if (mf_t_de == "trimf")
          u_de[i] = trimf(de, de_mf_paras[i * 3], de_mf_paras[i * 3 + 1], de_mf_paras[i * 3 + 2]);//de fuzzy, calculate its membership        else if (mf_t_de == "gaussmf")
          u_de[i] = gaussmf(de, de_mf_paras[i * 2], de_mf_paras[i * 2 + 1]);//de fuzzy, calculate its membership        else if (mf_t_de == "trapmf")
          u_de[i] = trapmf(de, de_mf_paras[i * 4], de_mf_paras[i * 4 + 1], de_mf_paras[i * 4 + 2], de_mf_paras[i * 4 + 3]);//de fuzzy, calculate its membership
        if (u_de[i] != 0)
          u_de_index[j++] = i;      //Storing the subscript of the activated fuzzy subset can reduce the amount of calculation      }
      for (; j < 3; j++) u_de_index[j] = 0;     //Fill in 0 with the excess space
      double den = 0, num = 0;
      /* Calculate delta_Kp and Kp*/
      for (int m = 0; m < 3; m++)
        for (int n = 0; n < 3; n++)
        {
          num += u_e[u_e_index[m]] * u_de[u_de_index[n]] * Kp_rule_matrix[u_e_index[m], u_de_index[n]];
          den += u_e[u_e_index[m]] * u_de[u_de_index[n]];
        }
      delta_Kp = num / den;
      delta_Kp = Ku_p * delta_Kp;
      if (delta_Kp >= delta_Kp_max) delta_Kp = delta_Kp_max;
      else if (delta_Kp <= -delta_Kp_max) delta_Kp = -delta_Kp_max;
      Kp += delta_Kp;
      if (Kp < 0) Kp = 0;
      /* Calculate delta_Ki and Ki*/
      den = 0; num = 0;
      for (int m = 0; m < 3; m++)
        for (int n = 0; n < 3; n++)
        {
          num += u_e[u_e_index[m]] * u_de[u_de_index[n]] * Ki_rule_matrix[u_e_index[m], u_de_index[n]];
          den += u_e[u_e_index[m]] * u_de[u_de_index[n]];
        }

      delta_Ki = num / den;
      delta_Ki = Ku_i * delta_Ki;
      if (delta_Ki >= delta_Ki_max) delta_Ki = delta_Ki_max;
      else if (delta_Ki <= -delta_Ki_max) delta_Ki = -delta_Ki_max;
      Ki += delta_Ki;
      if (Ki < 0) Ki = 0;
      /* Calculate delta_Kd and Kd*/
      den = 0; num = 0;
      for (int m = 0; m < 3; m++)
        for (int n = 0; n < 3; n++)
        {
          num += u_e[u_e_index[m]] * u_de[u_de_index[n]] * Kd_rule_matrix[u_e_index[m], u_de_index[n]];
          den += u_e[u_e_index[m]] * u_de[u_de_index[n]];
        }
      delta_Kd = num / den;
      delta_Kd = Ku_d * delta_Kd;
      if (delta_Kd >= delta_Kd_max) delta_Kd = delta_Kd_max;
      else if (delta_Kd <= -delta_Kd_max) delta_Kd = -delta_Kd_max;
      Kd += delta_Kd;
      if (Kd < 0) Kd = 0;

      A = Kp + Ki + Kd;
      B = -2 * Kd - Kp;
      C = Kd;
      delta_u = A * e + B * e_pre_1 + C * e_pre_2;

      delta_u = delta_u / Ke;

      if (delta_u >= 0.95 * target) delta_u = 0.95 * target;
      else if (delta_u <= -0.95 * target) delta_u = -0.95 * target;

      e_pre_2 = e_pre_1;
      e_pre_1 = e;

      return delta_u;
    }

    void showMf(string type, double[] mf_paras)
    {
      int tab = 0;
      if (type == "trimf")
        tab = 2;
      else if (type == "gaussmf")
        tab = 1;
      else if (type == "trapmf")
        tab = 3;
      ($"Function Type:{mf_t_e}");
      ("Function parameter list:");
      double[] p = mf_paras;
      for (int i = 0; i < N * (tab + 1); i++)
      {
        (p[i] + " ");
        if (i % (tab + 1) == tab)
          ("\r\n");
      }
    }

    public void showInfo()
    {
      ("Info of this fuzzy controller is as following:");
      ($"Basic Domaine:[{-emax},{emax}]");
      ($"Basic Domainde:[{-demax},{demax}]");
      ($"Basic Domaindelta_Kp:[{-delta_Kp_max},{delta_Kp_max}]");
      ($"Basic Domaindelta_Ki:[{-delta_Ki_max},{delta_Ki_max}]");
      ($"Basic Domaindelta_Kd:[{-delta_Kd_max},{delta_Kd_max}]");
      ("Fuzzy membership function parameters of error e:");
      showMf(mf_t_e, e_mf_paras);
      ("Fuzzy membership function parameters of error rate de:");
      showMf(mf_t_de, de_mf_paras);
      ("Fuzzy membership function parameters of delta_Kp:");
      showMf(mf_t_Kp, Kp_mf_paras);
      ("Fuzzy membership function parameters of delta_Ki:");
      showMf(mf_t_Ki, Ki_mf_paras);
      ("Fuzzy membership function parameters of delta_Kd:");
      showMf(mf_t_Kd, Kd_mf_paras);
      ("Fuzzy Rules Table:");
      ("Fuzzy rule matrix of delta_Kp");
      for (int i = 0; i < N; i++)
      {
        for (int j = 0; j < N; j++)
        {
          (Kp_rule_matrix[i, j]);
        }
        ("\r\n");
      }
      ("The fuzzy rule matrix of delta_Ki"); ;
      for (int i = 0; i < N; i++)
      {
        for (int j = 0; j < N; j++)
        {
          (Ki_rule_matrix[i, j]);
        }
        WriteEnd();
      }
      ("Fuzzy rule matrix of delta_Kd"); ;
      for (int i = 0; i < N; i++)
      {
        for (int j = 0; j < N; j++)
        {
          (Kd_rule_matrix[i, j]);
        }
        WriteEnd();
      }
      ($"Quantitative scale factor of errorKe={Ke}");
      ($"Quantitative proportional factor of error rate changeKde={Kde}");
      ($"Quantitative scale factor of outputKu_p={Ku_p}");
      ($"Quantitative scale factor of outputKu_i={Ku_i}");
      ($"Quantitative scale factor of outputKu_d={Ku_d}");
      ($"Set goalstarget={target}");
      ($"errore={e}");
      ($"Kp={Kp}");
      ($"Ki={Ki}");
      ($"Kd={Kd}");
      WriteEnd();
    }

    public void Write(object str)
    {
      (str);
    }
    public void WriteLine(object str)
    {
      (str);
    }
    public void WriteEnd()
    {
      ("\r\n");
    }


    public static void test()
    {
      int NB = -3;
      int NM = -2;
      int NS = -1;
      int ZO = 0;
      int PS = 1;
      int PM = 2;
      int PB = 3;

      double target = 300;
      double actual = 400;
      double u = 0;

      int[,] deltaKpMatrix = new int[7, 7] {{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}};
      int[,] deltaKiMatrix = new int[7, 7]{{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}};
      int[,] deltaKdMatrix = new int[7, 7]{{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,NS,PS,PS,PS,PS,PB},
               {PB,PM,PM,PM,PS,PS,PB}};
      double[] e_mf_paras = { -3, -3, -2, -3, -2, -1, -2, -1, 0, -1, 0, 1, 0, 1, 2, 1, 2, 3, 2, 3, 3 };
      double[] de_mf_paras = { -3, -3, -2, -3, -2, -1, -2, -1, 0, -1, 0, 1, 0, 1, 2, 1, 2, 3, 2, 3, 3 };
      double[] Kp_mf_paras = { -3, -3, -2, -3, -2, -1, -2, -1, 0, -1, 0, 1, 0, 1, 2, 1, 2, 3, 2, 3, 3 };
      double[] Ki_mf_paras = { -3, -3, -2, -3, -2, -1, -2, -1, 0, -1, 0, 1, 0, 1, 2, 1, 2, 3, 2, 3, 3 };
      double[] Kd_mf_paras = { -3, -3, -2, -3, -2, -1, -2, -1, 0, -1, 0, 1, 0, 1, 2, 1, 2, 3, 2, 3, 3 };

      var fuzzypid = new FuzzyPID(1500, 1000, 0.3, 0.9, 0.6, 0.01, 0.04, 0.01);
      ("trimf", e_mf_paras, "trimf", de_mf_paras, "trimf", Kp_mf_paras, "trimf", Ki_mf_paras, "trimf", Kd_mf_paras);
      (deltaKpMatrix, deltaKiMatrix, deltaKdMatrix);

      for (int i = 0; i < 50; i++)
      {
        u = (target, actual);
        actual += u;
        ($"{i}  {target} {u} {actual}");

        //if (i>19)
        //{
        //  target = 300;
        //}
      }
      //();

    }

  }
}

The above is the detailed content of c# implementing fuzzy PID control algorithm. For more information about c# fuzzy PID control algorithm, please pay attention to my other related articles!