找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開(kāi)始

搜索
查看: 2293|回復(fù): 1
收起左側(cè)

好用的模糊PID溫度控制算法 C語(yǔ)言源代碼

  [復(fù)制鏈接]
ID:230216 發(fā)表于 2023-4-7 10:16 | 顯示全部樓層 |閱讀模式
  1. #include <string.h>
  2. #include <stdio.h>
  3. #include <math.h>
  4. #include "pid_fuzzy.h"

  5. //注1:自適應(yīng)模糊pid最重要的就是論域的選擇,要和你應(yīng)該控制的對(duì)象相切合
  6. //注2:以下各閥值、限幅值、輸出值均需要根據(jù)具體的使用情況進(jìn)行更改
  7. //注3:因?yàn)槲业目刂茖?duì)象慣性比較大,所以以下各部分取值較小
  8. //論域e:[-5,5]  ec:[-0.5,0.5]

  9. //誤差的閥值,小于這個(gè)數(shù)值的時(shí)候,不做PID調(diào)整,避免誤差較小時(shí)頻繁調(diào)節(jié)引起震蕩
  10. #define Emin 0.0
  11. #define Emid 0.08
  12. #define Emax 0.6
  13. //調(diào)整值限幅,防止積分飽和
  14. #define Umax 5
  15. #define Umin -5

  16. //輸出值限幅
  17. #define Pmax 7200
  18. #define Pmin 0

  19. #define NB 0
  20. #define NM 1
  21. #define NS 2
  22. #define ZO 3
  23. #define PS 4
  24. #define PM 5
  25. #define PB 6

  26. int kp[7][7]= {  {PB,PB,PM,PM,PS,ZO,ZO},
  27.     {PB,PB,PM,PS,PS,ZO,ZO},
  28.     {PM,PM,PM,PS,ZO,NS,NS},
  29.     {PM,PM,PS,ZO,NS,NM,NM},
  30.     {PS,PS,ZO,NS,NS,NM,NM},
  31.     {PS,ZO,NS,NM,NM,NM,NB},
  32.     {ZO,ZO,NM,NM,NM,NB,NB}
  33. };

  34. int kd[7][7]= {  {PS,NS,NB,NB,NB,NM,PS},
  35.     {PS,NS,NB,NM,NM,NS,ZO},
  36.     {ZO,NS,NM,NM,NS,NS,ZO},
  37.     {ZO,NS,NS,NS,NS,NS,ZO},
  38.     {ZO,ZO,ZO,ZO,ZO,ZO,ZO},
  39.     {PB,NS,PS,PS,PS,PS,PB},
  40.     {PB,PM,PM,PM,PS,PS,PB}
  41. };

  42. int ki[7][7]= {  {NB,NB,NM,NM,NS,ZO,ZO},
  43.     {NB,NB,NM,NS,NS,ZO,ZO},
  44.     {NB,NM,NS,NS,ZO,PS,PS},
  45.     {NM,NM,NS,ZO,PS,PM,PM},
  46.     {NM,NS,ZO,PS,PS,PM,PB},
  47.     {ZO,ZO,PS,PS,PM,PB,PB},
  48.     {ZO,ZO,PS,PM,PM,PB,PB}
  49. };

  50. /**************求隸屬度(三角形)***************/
  51. float FTri(float x,float a,float b,float c)//FuzzyTriangle
  52. {
  53.     if(x<=a)
  54.         return 0;
  55.     else if((a<x)&&(x<=b))
  56.         return (x-a)/(b-a);
  57.     else if((b<x)&&(x<=c))
  58.         return (c-x)/(c-b);
  59.     else if(x>c)
  60.         return 0;
  61.     else
  62.         return 0;
  63. }
  64. /*****************求隸屬度(梯形左)*******************/
  65. float FTraL(float x,float a,float b)//FuzzyTrapezoidLeft
  66. {
  67.     if(x<=a)
  68.         return 1;
  69.     else if((a<x)&&(x<=b))
  70.         return (b-x)/(b-a);
  71.     else if(x>b)
  72.         return 0;
  73.     else
  74.         return 0;
  75. }
  76. /*****************求隸屬度(梯形右)*******************/
  77. float FTraR(float x,float a,float b)//FuzzyTrapezoidRight
  78. {
  79.     if(x<=a)
  80.         return 0;
  81.     if((a<x)&&(x<b))
  82.         return (x-a)/(b-a);
  83.     if(x>=b)
  84.         return 1;
  85.     else
  86.         return 1;
  87. }
  88. /****************三角形反模糊化處理**********************/
  89. float uFTri(float x,float a,float b,float c)
  90. {
  91.     float y,z;
  92.     z=(b-a)*x+a;
  93.     y=c-(c-b)*x;
  94.     return (y+z)/2;
  95. }
  96. /*******************梯形(左)反模糊化***********************/
  97. float uFTraL(float x,float a,float b)
  98. {
  99.     return b-(b-a)*x;
  100. }
  101. /*******************梯形(右)反模糊化***********************/
  102. float uFTraR(float x,float a,float b)
  103. {
  104.     return (b-a)*x +a;
  105. }
  106. /**************************求交集****************************/
  107. float fand(float a,float b)
  108. {
  109.     return (a<b)?a:b;
  110. }
  111. /**************************求并集****************************/
  112. float forr(float a,float b)
  113. {
  114.     return (a<b)?b:a;
  115. }
  116. float ec;
  117. /*==========   PID計(jì)算部分   ======================*/
  118. int PID_realize(PID *structpid,uint16_t s,uint16_t in)
  119. {
  120.     float pwm_var;//pwm調(diào)整量
  121.     float iError;//當(dāng)前誤差
  122.     float set,input;

  123.     //計(jì)算隸屬度表
  124.     float es[7],ecs[7],e;
  125.     float form[7][7];
  126.     int i=0,j=0;
  127.     int MaxX=0,MaxY=0;

  128.     //記錄隸屬度最大項(xiàng)及相應(yīng)推理表的p、i、d值
  129.     float lsd;
  130.     int temp_p,temp_d,temp_i;
  131.     float detkp,detkd,detki;//推理后的結(jié)果

  132.     //輸入格式的轉(zhuǎn)化及偏差計(jì)算
  133.     set=(float)s/100.0;
  134.     input=(float)in/100.0;
  135.     iError = set - input; // 偏差

  136.     e=iError;
  137.     ec=iError-structpid->LastError;

  138.     //當(dāng)溫度差的絕對(duì)值小于Emax時(shí),對(duì)pid的參數(shù)進(jìn)行調(diào)整
  139.     if(fabs(iError)<=Emax)
  140.     {
  141.         //計(jì)算iError在es與ecs中各項(xiàng)的隸屬度
  142.         es[NB]=FTraL(e*5,-3,-1);  //e
  143.         es[NM]=FTri(e*5,-3,-2,0);
  144.         es[NS]=FTri(e*5,-3,-1,1);
  145.         es[ZO]=FTri(e*5,-2,0,2);
  146.         es[PS]=FTri(e*5,-1,1,3);
  147.         es[PM]=FTri(e*5,0,2,3);
  148.         es[PB]=FTraR(e*5,1,3);

  149.         ecs[NB]=FTraL(ec*30,-3,-1);//ec
  150.         ecs[NM]=FTri(ec*30,-3,-2,0);
  151.         ecs[NS]=FTri(ec*30,-3,-1,1);
  152.         ecs[ZO]=FTri(ec*30,-2,0,2);
  153.         ecs[PS]=FTri(ec*30,-1,1,3);
  154.         ecs[PM]=FTri(ec*30,0,2,3);
  155.         ecs[PB]=FTraR(ec*30,1,3);

  156.         //計(jì)算隸屬度表,確定e和ec相關(guān)聯(lián)后表格各項(xiàng)隸屬度的值
  157.         for(i=0; i<7; i++)
  158.         {
  159.             for(j=0; j<7; j++)
  160.             {
  161.                 form[i][j]=fand(es[i],ecs[j]);
  162.             }
  163.         }

  164.         //取出具有最大隸屬度的那一項(xiàng)
  165.         for(i=0; i<7; i++)
  166.         {
  167.             for(j=0; j<7; j++)
  168.             {
  169.                 if(form[MaxX][MaxY]<form[i][j])
  170.                 {
  171.                     MaxX=i;
  172.                     MaxY=j;
  173.                 }
  174.             }
  175.         }
  176.         //進(jìn)行模糊推理,并去模糊
  177.         lsd=form[MaxX][MaxY];
  178.         temp_p=kp[MaxX][MaxY];
  179.         temp_d=kd[MaxX][MaxY];
  180.         temp_i=ki[MaxX][MaxY];

  181.         if(temp_p==NB)
  182.             detkp=uFTraL(lsd,-0.3,-0.1);
  183.         else if(temp_p==NM)
  184.             detkp=uFTri(lsd,-0.3,-0.2,0);
  185.         else if(temp_p==NS)
  186.             detkp=uFTri(lsd,-0.3,-0.1,0.1);
  187.         else if(temp_p==ZO)
  188.             detkp=uFTri(lsd,-0.2,0,0.2);
  189.         else if(temp_p==PS)
  190.             detkp=uFTri(lsd,-0.1,0.1,0.3);
  191.         else if(temp_p==PM)
  192.             detkp=uFTri(lsd,0,0.2,0.3);
  193.         else if(temp_p==PB)
  194.             detkp=uFTraR(lsd,0.1,0.3);

  195.         if(temp_d==NB)
  196.             detkd=uFTraL(lsd,-3,-1);
  197.         else if(temp_d==NM)
  198.             detkd=uFTri(lsd,-3,-2,0);
  199.         else if(temp_d==NS)
  200.             detkd=uFTri(lsd,-3,1,1);
  201.         else if(temp_d==ZO)
  202.             detkd=uFTri(lsd,-2,0,2);
  203.         else if(temp_d==PS)
  204.             detkd=uFTri(lsd,-1,1,3);
  205.         else if(temp_d==PM)
  206.             detkd=uFTri(lsd,0,2,3);
  207.         else if(temp_d==PB)
  208.             detkd=uFTraR(lsd,1,3);

  209.         if(temp_i==NB)
  210.             detki=uFTraL(lsd,-0.06,-0.02);
  211.         else if(temp_i==NM)
  212.             detki=uFTri(lsd,-0.06,-0.04,0);
  213.         else if(temp_i==NS)
  214.             detki=uFTri(lsd,-0.06,-0.02,0.02);
  215.         else if(temp_i==ZO)
  216.             detki=uFTri(lsd,-0.04,0,0.04);
  217.         else if(temp_i==PS)
  218.             detki=uFTri(lsd,-0.02,0.02,0.06);
  219.         else if(temp_i==PM)
  220.             detki=uFTri(lsd,0,0.04,0.06);
  221.         else if (temp_i==PB)
  222.             detki=uFTraR(lsd,0.02,0.06);

  223.         //pid三項(xiàng)系數(shù)的修改
  224.         structpid->Kp+=detkp;
  225.         structpid->Ki+=detki;
  226.         //structpid->Kd+=detkd;
  227.         structpid->Kd=0;//取消微分作用

  228.         //對(duì)Kp,Ki進(jìn)行限幅
  229.         if(structpid->Kp<0)
  230.         {
  231.             structpid->Kp=0;
  232.         }
  233.         if(structpid->Ki<0)
  234.         {
  235.             structpid->Ki=0;
  236.         }

  237.         //計(jì)算新的K1,K2,K3
  238.         structpid->K1=structpid->Kp+structpid->Ki+structpid->Kd;
  239.         structpid->K2=-(structpid->Kp+2*structpid->Kd);
  240.         structpid->K3=structpid->Kd;

  241.     }

  242.     if(iError>Emax)
  243.     {
  244.         structpid->pwm_out=7200;
  245.         pwm_var = 0;
  246.         structpid->flag=1;//設(shè)定標(biāo)志位,如果誤差超過(guò)了門(mén)限值,則認(rèn)為當(dāng)控制量第一次到達(dá)給定值時(shí),應(yīng)該采取下面的 抑制超調(diào) 的措施
  247.     }
  248.     else if(iError<-Emax)
  249.     {
  250.         structpid->pwm_out=0;
  251.         pwm_var = 0;
  252.     }
  253.     else if( fabs(iError) < Emin ) //誤差的閥值(死區(qū)控制??)
  254.     {
  255.         pwm_var = 0;
  256.     }
  257.     else
  258.     {
  259.         if( iError<Emid && structpid->flag==1 )//第一次超過(guò)(設(shè)定值-Emid(-0.08)攝氏度),是輸出為零,防止超調(diào),也可以輸出其他值,不至于太小而引起震蕩
  260.         {
  261.             structpid->pwm_out=0;
  262.             structpid->flag=0;
  263.         }
  264.         else if( -iError>Emid)//超過(guò)(設(shè)定+Emid(+0.08)攝氏度)
  265.         {
  266.             pwm_var=-1;
  267.         }
  268.         else
  269.         {
  270.             //增量計(jì)算
  271.             pwm_var=(structpid->K1 * iError  //e[k]
  272.                      + structpid->K2 * structpid->LastError  //e[k-1]
  273.                      + structpid->K3 * structpid->PrevError);    //e[k-2]
  274.         }
  275.         if(pwm_var >= Umax)pwm_var = Umax;      //調(diào)整值限幅,防止積分飽和
  276.         if(pwm_var <= Umin)pwm_var = Umin;      //調(diào)整值限幅,防止積分飽和

  277.     }
  278.     structpid->PrevError=structpid->LastError;
  279.     structpid->LastError=iError;

  280.     structpid->pwm_out += 360*pwm_var;        //調(diào)整PWM輸出

  281.     if(structpid->pwm_out > Pmax)structpid->pwm_out = Pmax;    //輸出值限幅
  282.     if(structpid->pwm_out < Pmin)structpid->pwm_out = Pmin;    //輸出值限幅

  283.     return (int)(structpid->pwm_out); // 微分項(xiàng)
  284. }

  285. void PID_Set(PID *structpid,float Kp,float Ki,float Kd,float T)
  286. {
  287.     (*structpid).Kp=Kp;//Kp*(1+(Td/T));
  288.     (*structpid).Ki=Ki;
  289.     (*structpid).Kd=Kd;
  290.     (*structpid).T=T;

  291.     structpid->K1=structpid->Kp*(1+structpid->Ki+structpid->Kd);
  292.     structpid->K2=-(structpid->Kp+2*structpid->Kp*structpid->Kd);
  293.     structpid->K3=structpid->Kp*structpid->Kd;
  294. }

  295. void PID_Init(PID *structpid)
  296. {
  297.     PID_Set(structpid,8.3,1.2,0,1);
  298.     structpid->flag=0;
  299.     structpid->pwm_out=0;
  300. }
復(fù)制代碼

pid_fuzzy.h
  1. #ifndef PID_H_
  2. #define PID_H_
  3. #include "stm32f10x.h"

  4. typedef struct PID
  5. {
  6.         float Kp; // 增量式積分系數(shù)
  7.         float Ki;
  8.         float Kd;
  9.         float T;
  10.        
  11.         float K1; // 增量式積分系數(shù)
  12.         float K2;
  13.         float K3;
  14.         float LastError; //Error[-1]
  15.         float PrevError; // Error[-2]
  16.         float pwm_out;
  17.        
  18.         uint16_t flag;//溫度狀態(tài)標(biāo)志位
  19. }PID;

  20. //void PID_init(PID *structpid);
  21. void PID_Set(PID *structpid,float Kp,float Ki,float Kd,float T);
  22. int PID_realize(PID *structpid,uint16_t s,uint16_t in);
  23. void PID_Init(PID *structpid);
  24. #endif /* PID_H_ */
復(fù)制代碼


評(píng)分

參與人數(shù) 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎(jiǎng)勵(lì)!

查看全部評(píng)分

回復(fù)

使用道具 舉報(bào)

ID:115126 發(fā)表于 2023-4-11 09:56 | 顯示全部樓層
代碼簡(jiǎn)潔,學(xué)習(xí)一下看看
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表