- #include <string.h>
- #include <stdio.h>
- #include <math.h>
- #include "pid_fuzzy.h"
- //注1:自適應(yīng)模糊pid最重要的就是論域的選擇,要和你應(yīng)該控制的對(duì)象相切合
- //注2:以下各閥值、限幅值、輸出值均需要根據(jù)具體的使用情況進(jìn)行更改
- //注3:因?yàn)槲业目刂茖?duì)象慣性比較大,所以以下各部分取值較小
- //論域e:[-5,5] ec:[-0.5,0.5]
- //誤差的閥值,小于這個(gè)數(shù)值的時(shí)候,不做PID調(diào)整,避免誤差較小時(shí)頻繁調(diào)節(jié)引起震蕩
- #define Emin 0.0
- #define Emid 0.08
- #define Emax 0.6
- //調(diào)整值限幅,防止積分飽和
- #define Umax 5
- #define Umin -5
- //輸出值限幅
- #define Pmax 7200
- #define Pmin 0
- #define NB 0
- #define NM 1
- #define NS 2
- #define ZO 3
- #define PS 4
- #define PM 5
- #define PB 6
- int kp[7][7]= { {PB,PB,PM,PM,PS,ZO,ZO},
- {PB,PB,PM,PS,PS,ZO,ZO},
- {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 kd[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}
- };
- int ki[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}
- };
- /**************求隸屬度(三角形)***************/
- float FTri(float x,float a,float b,float c)//FuzzyTriangle
- {
- if(x<=a)
- return 0;
- else if((a<x)&&(x<=b))
- return (x-a)/(b-a);
- else if((b<x)&&(x<=c))
- return (c-x)/(c-b);
- else if(x>c)
- return 0;
- else
- return 0;
- }
- /*****************求隸屬度(梯形左)*******************/
- float FTraL(float x,float a,float b)//FuzzyTrapezoidLeft
- {
- if(x<=a)
- return 1;
- else if((a<x)&&(x<=b))
- return (b-x)/(b-a);
- else if(x>b)
- return 0;
- else
- return 0;
- }
- /*****************求隸屬度(梯形右)*******************/
- float FTraR(float x,float a,float b)//FuzzyTrapezoidRight
- {
- if(x<=a)
- return 0;
- if((a<x)&&(x<b))
- return (x-a)/(b-a);
- if(x>=b)
- return 1;
- else
- return 1;
- }
- /****************三角形反模糊化處理**********************/
- float uFTri(float x,float a,float b,float c)
- {
- float y,z;
- z=(b-a)*x+a;
- y=c-(c-b)*x;
- return (y+z)/2;
- }
- /*******************梯形(左)反模糊化***********************/
- float uFTraL(float x,float a,float b)
- {
- return b-(b-a)*x;
- }
- /*******************梯形(右)反模糊化***********************/
- float uFTraR(float x,float a,float b)
- {
- return (b-a)*x +a;
- }
- /**************************求交集****************************/
- float fand(float a,float b)
- {
- return (a<b)?a:b;
- }
- /**************************求并集****************************/
- float forr(float a,float b)
- {
- return (a<b)?b:a;
- }
- float ec;
- /*========== PID計(jì)算部分 ======================*/
- int PID_realize(PID *structpid,uint16_t s,uint16_t in)
- {
- float pwm_var;//pwm調(diào)整量
- float iError;//當(dāng)前誤差
- float set,input;
- //計(jì)算隸屬度表
- float es[7],ecs[7],e;
- float form[7][7];
- int i=0,j=0;
- int MaxX=0,MaxY=0;
- //記錄隸屬度最大項(xiàng)及相應(yīng)推理表的p、i、d值
- float lsd;
- int temp_p,temp_d,temp_i;
- float detkp,detkd,detki;//推理后的結(jié)果
- //輸入格式的轉(zhuǎn)化及偏差計(jì)算
- set=(float)s/100.0;
- input=(float)in/100.0;
- iError = set - input; // 偏差
- e=iError;
- ec=iError-structpid->LastError;
- //當(dāng)溫度差的絕對(duì)值小于Emax時(shí),對(duì)pid的參數(shù)進(jìn)行調(diào)整
- if(fabs(iError)<=Emax)
- {
- //計(jì)算iError在es與ecs中各項(xiàng)的隸屬度
- es[NB]=FTraL(e*5,-3,-1); //e
- es[NM]=FTri(e*5,-3,-2,0);
- es[NS]=FTri(e*5,-3,-1,1);
- es[ZO]=FTri(e*5,-2,0,2);
- es[PS]=FTri(e*5,-1,1,3);
- es[PM]=FTri(e*5,0,2,3);
- es[PB]=FTraR(e*5,1,3);
- ecs[NB]=FTraL(ec*30,-3,-1);//ec
- ecs[NM]=FTri(ec*30,-3,-2,0);
- ecs[NS]=FTri(ec*30,-3,-1,1);
- ecs[ZO]=FTri(ec*30,-2,0,2);
- ecs[PS]=FTri(ec*30,-1,1,3);
- ecs[PM]=FTri(ec*30,0,2,3);
- ecs[PB]=FTraR(ec*30,1,3);
- //計(jì)算隸屬度表,確定e和ec相關(guān)聯(lián)后表格各項(xiàng)隸屬度的值
- for(i=0; i<7; i++)
- {
- for(j=0; j<7; j++)
- {
- form[i][j]=fand(es[i],ecs[j]);
- }
- }
- //取出具有最大隸屬度的那一項(xiàng)
- for(i=0; i<7; i++)
- {
- for(j=0; j<7; j++)
- {
- if(form[MaxX][MaxY]<form[i][j])
- {
- MaxX=i;
- MaxY=j;
- }
- }
- }
- //進(jìn)行模糊推理,并去模糊
- lsd=form[MaxX][MaxY];
- temp_p=kp[MaxX][MaxY];
- temp_d=kd[MaxX][MaxY];
- temp_i=ki[MaxX][MaxY];
- if(temp_p==NB)
- detkp=uFTraL(lsd,-0.3,-0.1);
- else if(temp_p==NM)
- detkp=uFTri(lsd,-0.3,-0.2,0);
- else if(temp_p==NS)
- detkp=uFTri(lsd,-0.3,-0.1,0.1);
- else if(temp_p==ZO)
- detkp=uFTri(lsd,-0.2,0,0.2);
- else if(temp_p==PS)
- detkp=uFTri(lsd,-0.1,0.1,0.3);
- else if(temp_p==PM)
- detkp=uFTri(lsd,0,0.2,0.3);
- else if(temp_p==PB)
- detkp=uFTraR(lsd,0.1,0.3);
- if(temp_d==NB)
- detkd=uFTraL(lsd,-3,-1);
- else if(temp_d==NM)
- detkd=uFTri(lsd,-3,-2,0);
- else if(temp_d==NS)
- detkd=uFTri(lsd,-3,1,1);
- else if(temp_d==ZO)
- detkd=uFTri(lsd,-2,0,2);
- else if(temp_d==PS)
- detkd=uFTri(lsd,-1,1,3);
- else if(temp_d==PM)
- detkd=uFTri(lsd,0,2,3);
- else if(temp_d==PB)
- detkd=uFTraR(lsd,1,3);
- if(temp_i==NB)
- detki=uFTraL(lsd,-0.06,-0.02);
- else if(temp_i==NM)
- detki=uFTri(lsd,-0.06,-0.04,0);
- else if(temp_i==NS)
- detki=uFTri(lsd,-0.06,-0.02,0.02);
- else if(temp_i==ZO)
- detki=uFTri(lsd,-0.04,0,0.04);
- else if(temp_i==PS)
- detki=uFTri(lsd,-0.02,0.02,0.06);
- else if(temp_i==PM)
- detki=uFTri(lsd,0,0.04,0.06);
- else if (temp_i==PB)
- detki=uFTraR(lsd,0.02,0.06);
- //pid三項(xiàng)系數(shù)的修改
- structpid->Kp+=detkp;
- structpid->Ki+=detki;
- //structpid->Kd+=detkd;
- structpid->Kd=0;//取消微分作用
- //對(duì)Kp,Ki進(jìn)行限幅
- if(structpid->Kp<0)
- {
- structpid->Kp=0;
- }
- if(structpid->Ki<0)
- {
- structpid->Ki=0;
- }
- //計(jì)算新的K1,K2,K3
- structpid->K1=structpid->Kp+structpid->Ki+structpid->Kd;
- structpid->K2=-(structpid->Kp+2*structpid->Kd);
- structpid->K3=structpid->Kd;
- }
- if(iError>Emax)
- {
- structpid->pwm_out=7200;
- pwm_var = 0;
- structpid->flag=1;//設(shè)定標(biāo)志位,如果誤差超過(guò)了門(mén)限值,則認(rèn)為當(dāng)控制量第一次到達(dá)給定值時(shí),應(yīng)該采取下面的 抑制超調(diào) 的措施
- }
- else if(iError<-Emax)
- {
- structpid->pwm_out=0;
- pwm_var = 0;
- }
- else if( fabs(iError) < Emin ) //誤差的閥值(死區(qū)控制??)
- {
- pwm_var = 0;
- }
- else
- {
- if( iError<Emid && structpid->flag==1 )//第一次超過(guò)(設(shè)定值-Emid(-0.08)攝氏度),是輸出為零,防止超調(diào),也可以輸出其他值,不至于太小而引起震蕩
- {
- structpid->pwm_out=0;
- structpid->flag=0;
- }
- else if( -iError>Emid)//超過(guò)(設(shè)定+Emid(+0.08)攝氏度)
- {
- pwm_var=-1;
- }
- else
- {
- //增量計(jì)算
- pwm_var=(structpid->K1 * iError //e[k]
- + structpid->K2 * structpid->LastError //e[k-1]
- + structpid->K3 * structpid->PrevError); //e[k-2]
- }
- if(pwm_var >= Umax)pwm_var = Umax; //調(diào)整值限幅,防止積分飽和
- if(pwm_var <= Umin)pwm_var = Umin; //調(diào)整值限幅,防止積分飽和
- }
- structpid->PrevError=structpid->LastError;
- structpid->LastError=iError;
- structpid->pwm_out += 360*pwm_var; //調(diào)整PWM輸出
- if(structpid->pwm_out > Pmax)structpid->pwm_out = Pmax; //輸出值限幅
- if(structpid->pwm_out < Pmin)structpid->pwm_out = Pmin; //輸出值限幅
- return (int)(structpid->pwm_out); // 微分項(xiàng)
- }
- void PID_Set(PID *structpid,float Kp,float Ki,float Kd,float T)
- {
- (*structpid).Kp=Kp;//Kp*(1+(Td/T));
- (*structpid).Ki=Ki;
- (*structpid).Kd=Kd;
- (*structpid).T=T;
- structpid->K1=structpid->Kp*(1+structpid->Ki+structpid->Kd);
- structpid->K2=-(structpid->Kp+2*structpid->Kp*structpid->Kd);
- structpid->K3=structpid->Kp*structpid->Kd;
- }
- void PID_Init(PID *structpid)
- {
- PID_Set(structpid,8.3,1.2,0,1);
- structpid->flag=0;
- structpid->pwm_out=0;
- }
復(fù)制代碼
pid_fuzzy.h
- #ifndef PID_H_
- #define PID_H_
- #include "stm32f10x.h"
- typedef struct PID
- {
- float Kp; // 增量式積分系數(shù)
- float Ki;
- float Kd;
- float T;
-
- float K1; // 增量式積分系數(shù)
- float K2;
- float K3;
- float LastError; //Error[-1]
- float PrevError; // Error[-2]
- float pwm_out;
-
- uint16_t flag;//溫度狀態(tài)標(biāo)志位
- }PID;
- //void PID_init(PID *structpid);
- void PID_Set(PID *structpid,float Kp,float Ki,float Kd,float T);
- int PID_realize(PID *structpid,uint16_t s,uint16_t in);
- void PID_Init(PID *structpid);
- #endif /* PID_H_ */
復(fù)制代碼
|