PID

#include "PID.h"

/*
    将偏差的比例(Proportion)、积分(Integral) 和微分(Differential) 通过线性
    组合构成控制量,用这一控制量对被控对象进行控制,这样的控制器称 PID 控制器。
    常规的模拟 PID 控制系统原理框图如图所示:
    *****************************************************************************
    *                         ┌──> 比例 ─────┐                                  *
    *                         │             +↓                                  *                             
    *       +  ┌─┬─┐          │          + ┌─┬─┐                                *     
    * r(t)────>├─┼─┤───e(t)───┼──> 积分 ──>├─┼─┤───u(t)───> 被控对象 ───y(t)───>*                                                    
    *          └─┴─┘          │            └─┴─┘                         │      *
    *            ↑            │             +↑                           │      *                                            
    *            │-           └──> 微分 ─────┘                           │      *      
    *            │                                                       │      *
    *            │                                                       │      *                                                                
    *            └───────────────────────────────────────────────────────┘      *
    *****************************************************************************
    该系统由模拟控制器和被控对象组成。
    图中, r(t) 是给定值, y(t) 是系统的实际输出值,给定值与实际输出值构成控制偏差
    e(t) = r(t) − y(t)                                   (式 1-1)
    e(t) 作为 PID 控制的输入, 作为 PID 控制器的输出和被控对象的输入。 
    所以模拟 PID 控制器的控制规律为:
    
              ┌         1   ╭t             de(t) ┐
    u(t) = Kp*│ e(t) + ───* /  e(t)dt + Td*───── │      (式 1-2)
              └         Ti ╯ 0              dt   ┘
    
    其中:Kp -- 控制器的比例系数
          Ti -- 控制器的积分时间,也称积分系数
          Td -- 控制器的微分时间,也称微分系数
    
    
    *** 位置式 PID 算法 *********************************************************
      由于计算机控制是一种采样控制,它只能根据采样时刻的偏差计算控制量,而不能像
    模拟控制那样连续输出控制量量,进行连续控制。由于这一特点(式 1-2)中的积分项
    和微分项不能直接使用,必须进行离散化处理。离散化处理的方法为:以T作为采样周期,
    k作为采样序号,则离散采样时间kT对应着连续时间t,用矩形法数值积分近似代替积分,
    用一阶后向差分近似代替微分。为表示方便将类似于 e(kT)简化成 e(k) 等。
    
    可作如下近似变换:
    ┌   t ≈ kT  (k = 0,1,2,......)
    │
    │    ╭t           k          k
    │    /  e(t)dt ≈ T*∑e(jT) = T*∑e(j)                  (式 2-1)
    │   ╯ 0          j=0        j=0
    │
    │   de(t)   e(kT)-e[(k-1)T]   e(k)-e(k-1)
    │   ───── ≈ ─────────────── = ───────────
    └    dt           T                T
   
              ┌         T   k           e(k)-e(k-1) ┐
    u(k) = Kp*│ e(k) + ───* ∑e(j) + Td*──────────── │    (式 2-2)
              └         Ti j=0              T       ┘
    或
                        k
    u(k) = Kp*e(k) + Ki*∑e(j) + Kd*[e(k)-e(k-1)]         (式 2-3)
                       j=0  
         
    其中:Ki ――积分系数, Ki=Kp*T/Ti ;
          Kd ――微分系数, Kd=Kp*Td/T ;
          k ―― 采样序号, k =0,1,2,……;
          u(k) ―― 第 k 次采样时刻的计算机输出值;
          e(k) ―― 第 k 次采样时刻输入的偏差值, 
          e(k-1) ―― 第 k -1 次采样时刻输入的偏差值;
          
    如果采样周期足够小,则(式 2-2)或(式 2-3)的近似计算可以获得足够精确的结果,离
散控制过程与连续过程十分接近。
    (式 2-2)或(式 2-3) 表示的控制算法式直接按(式 1-2) 所给出的 PID 控制规律定义进
行计算的,所以它给出了全部控制量的大小,因此被称为全量式或位置式 PID 控制算法。
    这种算法的缺点是: 由于全量输出, 所以每次输出均与过去状态有关, 计算时要对e(k)进行累加,
工作量大; 并且,因为计算机输出的u(k)对应的是执行机构的实际位置, 如果计算机出现故障,输出
的u(k)将大幅度变化,会引起执行机构的大幅度变化,有可能因此造成严重的生产事故,这在实生产
际中是不允许的
    增量式 PID 控制算法可以避免着重现象发生。
    
    *** 增量式 PID 算法 *********************************************************
    所谓增量式 PID 是指数字控制器的输出只是控制量的增量∆u(k) 。 当执行机构需要的控制量是增
量,而不是位置量的绝对数值时,可以使用增量式 PID 控制算法进行控制。
    增量式 PID 控制算法可以通过(式 2-2)推导出。由(式 2-2)可以得到控制器的第 k-1
个采样时刻的输出值为:

                ┌           T  k-1         e(k-1)-e(k-2) ┐
    u(k-1) = Kp*│ e(k-1) + ───* ∑e(j) + Td*───────────── │    (式 2-4)
                └           Ti j=0               T       ┘
                
    将(式 2-2)与(式 2-4)相减并整理,就可以得到增量式 PID 控制算法公式为:
    
                             ┌                 T           e(k)-2e(k-1)+e(k-2) ┐
    ∆u(k) = u(k)-u(k-1) = Kp*│  e(k)-e(k-1) + ───e(k) + Td*─────────────────── │
                             └                 Ti                   T          ┘
                             
                     T    Td                  2Td               Td
          = Kp*(1 + ─── + ───)*e(k) - Kp*(1 + ────)*e(k-1) + Kp*───*e(k-2)    (式 2-5)
                     Ti    T                   T                 T
                     
          =A*e(k) + B*e(k-1) + C*e(k-2)
          
                       T    Td                 2Td            Td
    其中:A = Kp*(1 + ─── + ───);  B = Kp*(1 + ────);  C = Kp*───
                       Ti    T                  T              T
                       
    由(式 2-5)可以看出,如果计算机控制系统采用恒定的采样周期T ,一旦确定 A、 B、 C,
只要使用前后三次测量的偏差值,就可以由(式 2-5)求出控制量。  
    增量式 PID 控制算法与位置式 PID 算法(式 2-2)相比,计算量小的多,因此在实际中得到
广泛的应用。
    而位置式 PID 控制算法也可以通过增量式控制算法推出递推计算公式:
    u(k) = u(k-1) + ∆u(k)                                                     (式 2-6)
(式 2-6)就是目前在计算机控制中广泛应用的数字递推 PID 控制算法。
*/



typedef struct PID
{
	int  SetPoint; 			//  设计目标 Desired Value
	long SumError;			//	误差累计 
		
	double  Proportion;     //  比例常数 Proportional Const
	double  Integral;       //  积分常数 Integral Const
	double  Derivative;     //  微分常数 Derivative Const

	int LastError;         	//  Error[-1]
	int PrevError;          //  Error[-2]

} PID;

static PID	 sPID;
static PID	 *sptr = &sPID;

/*
    描述:PID 所用到的 RAM 清零
    输入:无
    输出:无
    注意:请在设置参数前使用。
    例子:PIDInit();
*/
void PIDInit(void)
{
    sptr->LastError  = 0;			//Error[-1]
    sptr->PrevError  = 0;			//Error[-2]
	sptr->Proportion = 0;			//比例常数 Proportional Const
    sptr->Integral   = 0;			//积分常数 Integral Const
    sptr->Derivative = 0;			//微分常数 Derivative Const
    sptr->SetPoint   = 0;
	sptr->SumError   = 0;
}

/*
    描述:设置 PID 调节的目标值
    输入:期望值
    输出:无
    注意:无
    例子:PIDSetPoint(2000); //期望电动机的转速为 2000rpm
*/
void PIDSetPoint(int setpoint)
{	
    sptr->SetPoint = setpoint;	
}

/*
    描述:读取 PID 调节设置的目标值
    输入:无
    输出:所设置的期望值
    注意:得到的期望值将和数值的是同一个数值
    例子:uiSpeed = PIDSetPoint(); //读取所设置的期望电动机转速
*/
int PIDGetSetpoint(void)
{	
    return(sptr->SetPoint);	
}

/*
    描述:设置 PID 的 Kp 值
    输入:Kp 数值
    输出:无
    注意:这个参数在增量 PID 和位置 PID 的计算中代表着不同的意思。
          位置式 PID 中 Kp 就是比例系数
          增量式 PID 中 Kp 相当于 e(k) 的系数Kp(1+T/Ti+Td/T)
    例子:PIDSetKp(0.257); //设置 Kp=0.257
*/
void PIDSetKp(double dKpp)
{	
    sptr->Proportion = dKpp;
}

/*
    描述:读取 PID 中所设置的 Kp 值
    输入:无
    输出:Kp 数值
    注意:这个参数在增量 PID 和位置 PID 的计算中代表着不同的意思。
          位置式 PID 中 Kp 就是比例系数
          增量式 PID 中 Kp 相当于 e(k) 的系数Kp(1+T/Ti+Td/T)
    例子:Kp = PIDSetKp();
*/
double PIDGetKp(void)
{
    return(sptr->Proportion);
}

/*
    描述:设置 PID 的 Ki 值
    输入:Ki 数值
    输出:无
    注意:这个参数在增量 PID 和位置 PID 的计算中代表着不同的意思。
          位置式 PID 中 Ki 是积分系数Kp*(T/Ti)
          增量式 PID 中 Ki 是 e(k-1) 的系数Kp*(1+2*Td/T)
    例子:PIDSetKi(0.367); //设置 Ki=0.367
*/
void PIDSetKi(double dKii)
{
    sptr->Integral = dKii;
}

/*
    描述:读取 PID 中所设置的 Ki 值
    输入:无
    输出:Ki 数值
    注意:这个参数在增量 PID 和位置 PID 的计算中代表着不同的意思。
          位置式 PID 中 Ki 是积分系数Kp*(T/Ti)
          增量式 PID 中 Ki 是 e(k-1) 的系数Kp*(1+2*Td/T)
    例子:dKi = PIDSetKi();
*/
double PIDGetKi(void)
{
    return(sptr->Integral);
}

/*
    描述:设置 PID 的 Kd 值
    输入:Kd 数值
    输出:无
    注意:这个参数在增量 PID 和位置 PID 的计算中代表着不同的意思。
          位置式 PID 中 Kd 是积分系数Kp*(Td/T)
          增量式 PID 中 Kd 是 e(k-2) 的系数Kp*(Td/T)
    例子:PIDSetKd(0.157); //设置 Kd=0.157
*/
void PIDSetKd(double dKdd)
{
    sptr->Derivative = dKdd;
}

/*
    描述:读取 PID 中所设置的 Kd 值
    输入:无
    输出:Kd 数值
    注意:这个参数在增量 PID 和位置 PID 的计算中代表着不同的意思。
          位置式 PID 中 Kd 是积分系数Kp*(Td/T)
          增量式 PID 中 Kd 是 e(k-2) 的系数Kp*(Td/T)
    例子:dKd = PIDGetKd();
*/
double PIDGetKd(void)
{
    return(sptr->Derivative);
}

/*
    描述:增量式 PID 计算
    输入:PID 调节当前采样值
    输出:计算增量
    注意:增量式 PID 算法的实现。
    例子:uiGoalvalue += IncPIDCalc (1998); //位置式 PID 控制算法通过增量式控
          制算法递推实现,当前采样得到转速 1998rpm。
*/
int IncPIDCalc(int NextPoint)
{
	register int iError, iIncpid;
    //当前误差
	iError = sptr->SetPoint - NextPoint;
    //增量计算
	iIncpid = sptr->Proportion * iError				//E[k]项
            - sptr->Integral   * sptr->LastError	//E[k-1]项
            + sptr->Derivative * sptr->PrevError;	//E[k-2]项
    //存储误差,用于下次计算
	sptr->PrevError = sptr->LastError;
	sptr->LastError = iError;
    //返回增量值
	return(iIncpid);
}

/*
    描述:位置式 PID 计算
    输入:PID 调节当前采样值
    输出:位置式 PID 计算出的绝对位置值
    注意:位置式式 PID 算法的实现。
    例子:uiGoalvalue = LocPIDCalc (1998); //位置式 PID 控制算法,当前采样得到
          转速 1998rpm。
*/
unsigned int LocPIDCalc(int NextPoint)
{
    register int  iError,dError;
	
	iError = sptr->SetPoint - NextPoint;      	// 偏差
	sptr->SumError += iError;					// 积分
	dError = iError - sptr->LastError; 			// 微分
	sptr->LastError = iError;

	return(sptr->Proportion * iError           	// 比例项
           + sptr->Integral * sptr->SumError 	// 积分项
           + sptr->Derivative * dError);        // 微分项
}

//=============================================//
//	*END*
//=============================================//

#ifndef __PID_H
#define __PID_H
#include "stm32f0xx.h"

extern void PIDInit(void);

extern void PIDSetPoint(int setpoint);
extern int PIDGetSetpoint(void);

extern void PIDSetKp(double dKpp);
extern double PIDGetKp(void);

extern void PIDSetKi(double dKii);
extern double PIDGetKi(void);

extern void PIDSetKd(double dKdd);
extern double PIDGetKd(void);

extern int IncPIDCalc(int NextPoint);
extern unsigned int LocPIDCalc(int NextPoint);

#endif /* __PID_H */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值