专家PID
专家控制
专家控制是模拟人类专家控制的方式。它具有大量的专门知识和经验,和专家控制一样不需要知道对象的模型的情况下,对系统进行控制。
 
专家控制的基本结构
和人类专家控制一样,知识库越是丰富,推理机越是精确,控制效果也就越好。不同的知识库和推理机,控制效果也不经相同。这也是专家控制的一个特点,利用这个特点,可以设计属于自己的专家控制系统。
在这里插入图片描述

专家控制的基本实现

直接性专家控制

专家控制器直接对执行机构进行控制。
在这里插入图片描述

间接型专家控制

专家控制通过控制算法,对控制器进行操作,由控制器对执行机构进行控制。
在这里插入图片描述

专家PID
专家PID是专家控制和PID的结合,两者都不需要知道被控对象的模型。
 
简单的专家PID
下面的例子是增量式PID的实现方式,理解了思路,也就是对偏差和偏差增量的判断采取控制。便可以用C语言进行实现。
当前时刻误差
在这里插入图片描述
误差增量
在这里插入图片描述
上次误差增量在这里插入图片描述
通过偏差和偏差的增量来判断应采用的PID控制类型,从而更快更平稳地实现收敛。

K1和K2为增益系数,K1>K2
M1,M2为设定的误差界限,M1>M2>M3

这里的专家控制有5条控制规则:

1:误差超过设定的最大值(M1),输出PID控制器的最大值,进行开环控制,对极限情况进行控制。以迅速达到偏差作用。

在这里插入图片描述

2:误差的绝对值在变大或者维持常值,实施较强的控制作用

在这里插入图片描述
再次对偏差进行判断,选择不同的控制强度。

若误差超过设定的最大值(M2),实行较强控制,减少误差

控制器输出:
在这里插入图片描述

若误差小于设定的最大值(M2),实现一般较弱控制

控制器输出:也可以减少K1的值
在这里插入图片描述
说明此时误差仍然较大,可将 k1增大,反之可以减小。这样可以比分别使用两套参数减少2个待调参数,当然模型的容量也有一定程度下降。

3:误差的绝对值减少后者误差已经达到平衡状态,维持控制器输出不变

在这里插入图片描述
在这里插入图片描述

4:误差处于极值状态

在这里插入图片描述
再次对偏差进行判断,选择不同的控制强度。

若误差超过设定的最大值(M2),实行较强控制,减少误差

控制器输出:
在这里插入图片描述
若误差小于设定的最大值(M2),实现较弱控制

控制器输出:

在这里插入图片描述

5:若误差小于设定的最小值(M3),增加控制精度

在这里插入图片描述
设置控制精度,可能是由系统的静差导致的,用PI控制,减少静差。
在这里插入图片描述

Kp和Ki可以适当减小,以减小控制作用。当偏差小到一定程度后,甚至可以引入死区的概念,是系统稳定下来而不需要去进行调节。

思维导图

在这里插入图片描述

C语言实现:增量式专家PID

//输出限幅
#define OUT_MIN		-1000
#define OUT_MAX		1000

#define DEAD_BAND 10 //死区控制线
#include"math.h"           
//PID结构体
//PID结构体
typedef struct
{
	volatile double    Proportion; // 比例常数 Proportional Const
	volatile double    Integral; // 积分常数 Integral Const
	volatile double    Derivative;// 微分常数 Derivative Const
	volatile double      Error1; // Error[n-1]
	volatile double      Error2; // Error[n-2]
	volatile double      iError;  // Error[n]
	volatile double		 Error_sum;//积分值
	volatile double		 iIncpid;//PID输出值
	volatile double    inc_iError;//Error[n]增量
	volatile double    inc_Error1;//Error[n-1]增量
	volatile double		 Error_abs_Max;//偏差绝对值最大值
	volatile double		 Error_abs_Mid;//偏差绝对值最中值
	volatile double		 Error_abs_Min;//偏差绝对值最小值
} PID;

/****************************************************************************************/																												//								增量式专家
//										//pwm=Kp*e(k)+Ki*∑e(k)+Kd[e(k)-e(k-1)]	
/****************************************************************************************/
double Exper_Pid_Inc (double iError,PID* sptr) 
{
   double result=0;
   sptr->iError=iError;  //传入当前误差
   sptr->inc_iError=sptr->iError-sptr->Error1;//得到这次增量
   sptr->inc_Error1=sptr->Error1-sptr->Error2;//得到上次增量
   if(abs(sptr->iError)>sptr->Error_abs_Max)//误差超过设定的最大值(M1)
   {
		if(sptr->iError>0)  result=OUT_MAX;
   	 	if(sptr->iError<0)  result=OUT_MIN;
   }

	if(abs(sptr->iError)<=sptr->Error_abs_Min)//若误差小于设定的最小值(M3)
   {
   	if(fabs(sptr->iError)>DEAD_BAND) //死区控制
   	{
	 result=sptr->iIncpid+0.5*sptr->Proportion * sptr->inc_iError  // P
         +0.3*sptr->Integral * sptr->iError;                // I
     }
     else result=0;
   }
     if((sptr->iError*sptr->inc_iError<0)&&(sptr->inc_iError*sptr->inc_Error1>0))||(sptr->iError==0))
    //说明误差正在减小,或者为零,此时维持原输出
  {
    result=sptr->iIncpid;//保持上一次输出
  }
  
	if((sptr->iError*sptr->inc_iError<0)&&(sptr->inc_iError*sptr->inc_Error1<0)))//误差处于极值状态
  {
  	if(abs(sptr->iError)>sptr->Error_abs_Mid)    result=sptr->iIncpid+1.2*sptr->Integral*sptr->iError;
    if(abs(sptr->iError)<sptr->Error_abs_Mid)    result=sptr->iIncpid+0.6*sptr->Integral*sptr->iError;
  }

  	if(((sptr->iError*sptr->inc_iError>0)||(sptr->inc_iError==0))//误差在变大,或维持长值
  {
  	if(abs(sptr->iError)>sptr->Error_abs_Mid)    result=sptr->iIncpid+2*(sptr->Integral*sptr->iError+sptr->Proportion*sptr->inc_iError+sptr->Derivative*(sptr->inc_iError-sptr->inc_Error1));
  	
    if(abs(sptr->iError)<sptr->Error_abs_Mid)    result=sptr->iIncpid+1.2*(sptr->Integral*sptr->iError+sptr->Proportion*sptr->inc_iError+sptr->Derivative*(sptr->inc_iError-sptr->inc_Error1));
  }

  //更新值
  sptr->iIncpid=result;    
  sptr->Error2=sptr->Error1; 
  sptr->Error1=sptr->iError;	
  result=PID_OutputLimit(result);//PID输出限幅								
  return(result);          // 返回计算值
	
}

//PID输出限制,根据PWM的输出值进行增量式PID输出限制
double PID_OutputLimit(double output)  
{
		
    if (output < OUT_MIN)
		{
        output = OUT_MIN;
    }		
		else if (output > OUT_MAX)
		
		{
        output = OUT_MAX;
    }
    return output;
}

C语言实现:位置式专家PID

//输出限幅
#define OUT_MIN		-1000
#define OUT_MAX		1000
//积分限幅
#define INERGRAL_MAX 200
#define INERGRAL_MIX -200

#include"math.h"           
//PID结构体
typedef struct
{
	volatile double    Proportion; // 比例常数 Proportional Const
	volatile double    Integral; // 积分常数 Integral Const
	volatile double    Derivative;// 微分常数 Derivative Const
	volatile double      Error1; // Error[n-1]
	volatile double      Error2; // Error[n-2]
	volatile double      iError;  // Error[n]
	volatile double		 Error_sum;//积分值
	volatile double		 iIncpid;//PID输出值
	volatile double    inc_iError;//Error[n]增量
	volatile double    inc_Error1;//Error[n-1]增量
	volatile double		 Error_abs_Max;//偏差绝对值最大值
	volatile double		 Error_abs_Mid;//偏差绝对值最中值
	volatile double		 Error_abs_Min;//偏差绝对值最小值
} PID;

/****************************************************************************************/																												//								位置式专家PID
//										//pwm=Kp*e(k)+Ki*∑e(k)+Kd[e(k)-e(k-1)]	
/****************************************************************************************/
#include "math.h"
//********************************PID算法部分************************************//
#define OUT_MIN		-500
#define OUT_MAX		500

//积分限幅
#define INERGRAL_MAX 200
#define INERGRAL_MIN -200

//PID初始化
void PID_Init(PID *sptr)
{
	sptr->Derivative = 0;//Kd
	sptr->Proportion = 0;//Kp
	sptr->Integral = 0;//Ki
	sptr->Error2 = 0;
	sptr->Error1 = 0;
	sptr->iError = 0;
	sptr->Error_sum = 0;
	//sptr->index=1;
	sptr->iIncpid = 0;
	sptr->inc_iError = 0;
	sptr->inc_Error1 = 0;
	sptr->Error_abs_Max = 150;
	sptr->Error_abs_Mid = 100;
	sptr->Error_abs_Min = 50;

}

//PID输出限幅处理
double PID_OutputLimit(double output)
{
	double x;
	x = output;
	if (x <= OUT_MIN)
	{
		x = (double)OUT_MIN;
	}
	else if (x >= OUT_MAX)

	{
		x = (double)OUT_MAX;
	}
	return x;
}

/****************************************************************************************/																												//								增量式专家
//										//pwm=Kp*e(k)+Ki*∑e(k)+Kd[e(k)-e(k-1)]	
/****************************************************************************************/
double Exper_Pid_Pos(double iError, PID* sptr)
{
	double result = 0;
	sptr->iError = iError;  //传入当前误差
	sptr->inc_iError = sptr->iError - sptr->Error1;//得到这次增量
	sptr->inc_Error1 = sptr->Error1 - sptr->Error2;//得到上次增量
	  sptr->iError=iError;                                    // 计算当前误差
  
	sptr->Error_sum+=sptr->iError;//积分项	
		///当输出限幅的时候,积分累加部分也应同时进行限幅,以防输出不变而积分项继续累加,也即所谓的积分饱和过深。
	//积分量限幅
	if(sptr->Error_sum >=INERGRAL_MAX)
	{
		sptr->Error_sum = INERGRAL_MAX ;
	}
	if(sptr->Error_sum < INERGRAL_MIN)
	{
		sptr->Error_sum =INERGRAL_MIN ;
	}

	if (fabs(sptr->iError) > sptr->Error_abs_Max)//误差超过设定的最大值(M1)
	{
		if (sptr->iError > 0)  result = OUT_MAX;
		if (sptr->iError < 0)  result = OUT_MIN;
	}

	if (fabs(sptr->iError) <= sptr->Error_abs_Min)//若误差小于设定的最小值(M3)
	{
		if (fabs(sptr->iError) > DEAD_BAND) //死区控制
		{
			result = 0.5*sptr->Proportion * sptr->iError// P
				+ 0.3*sptr->Integral * sptr->Error_sum ;                // I
		}
		else result = 0;
	}
	if (((sptr->iError*sptr->inc_iError < 0) && (sptr->inc_iError*sptr->inc_Error1 > 0)) || (sptr->iError == 0))
		//说明误差正在减小,或者为零,此时维持原输出
	{
		result = sptr->iIncpid;//保持上一次输出
	}

	if (((sptr->iError*sptr->inc_iError < 0) && (sptr->inc_iError*sptr->inc_Error1 < 0)))//误差处于极值状态
	{
		if(fabs(sptr->iError)>sptr->Error_abs_Mid)    result=1.8*sptr->Integral*sptr->Error_sum;
   	    if(fabs(sptr->iError)<sptr->Error_abs_Mid)    result=1.2*sptr->Integral*sptr->Error_sum;
	}

	if ((sptr->iError*sptr->inc_iError > 0) || (sptr->inc_iError == 0))//误差在变大,或维持长值
	{
  	if(abs(sptr->iError)>sptr->Error_abs_Mid)    result=2*(sptr->Integral*sptr->Error_sum+sptr->Proportion*sptr->iError+sptr->Derivative*sptr->inc_iError);
  	
    if(abs(sptr->iError)<sptr->Error_abs_Mid)    result=1.1*(sptr->Integral*sptr->Error_sum+sptr->Proportion*sptr->iError+sptr->Derivative*sptr->inc_iError);
	}

	//更新值
	sptr->iIncpid = result;
	sptr->Error2 = sptr->Error1;
	sptr->Error1 = sptr->iError;
	result = PID_OutputLimit(result);//PID输出限幅								
	return(result);          // 返回计算值

}


//PID输出限制,根据PWM的输出值进行增量式PID输出限制
double PID_OutputLimit(double output)  
{
		
    if (output < OUT_MIN)
		{
        output = OUT_MIN;
    }		
		else if (output > OUT_MAX)
		
		{
        output = OUT_MAX;
    }
    return output;
}

 
总结
通过这个简单的例子,大概了解直接性专家控制。最明显的优势,控制决策的灵活性,可以根据不同的系统,选择不同和设计不同的控制策略,通过修改、增加控制规则,可不断积累知识,改进控制性能。能够满足任意动态过程的控制需要,尤其适用于带有时变、非线性和强干扰的控制;但问题是,调试比普通PID复杂,设计的控制规则需要经验。