常見的PID的演算法及程式碼示例
PID(比例-積分-微分)演算法是控制系統中常用的一種反饋控制演算法,它透過計算誤差的比例、積分和微分來調整控制輸入,以達到預定的控制目標。以下是一些常見的PID演算法及程式碼示例:
一、常見的PID演算法
- 位置式PID演算法
- 位置式PID演算法直接計算控制量的絕對值,每次輸出都與過去的狀態有關,因此計算量相對較大。其計算公式為:u(k)=Kpe(k)+K**i∑j=0k**e(j)+K**d[e(k)−e(k−1)]
- 其中,u(k) 是第 k 次的控制量,e(k) 是第 k 次的誤差,K**p、K**i、K**d 分別是比例、積分、微分系數。
- 增量式PID演算法
- 增量式PID演算法只計算控制量的增量,即本次控制量與上一次控制量之差,因此計算量相對較小,且更易於實現無擾動切換。其計算公式為:Δu(k)=K**p[e(k)−e(k−1)]+Kie(k)+K**d[e(k)−2e(k−1)+e(k−2)]
- 實際應用中,控制量 u(k) 可透過累加增量 Δu(k) 來獲得。
二、程式碼示例
pid.c
#include "stm32f10x.h"
#include <math.h>
#include "sys.h"
#include "pid.h"
#define PID_LIMIT_MIN -10000 //PID輸出最低值
#define PID_LIMIT_MAX 10000 //PID輸出最大值
//注意:PID結構體必須定義為全域性變數或靜態變數,然後在函式中給KP,KI,KD賦值
/************************取樣週期未知且不變************************************/
//位置式PID
//pwm=Kp*e(k)+Ki*∑e(k)+Kd[e(k)-e(k-1)]
//setvalue : 設定值(期望值)
//actualvalue: 實際值
//由於全量輸出,每次輸出均與過去狀態有關,計算時要對ek累加,計算量大
float PID_location(float setvalue, float actualvalue, PID_LocTypeDef *PID)
{
PID->ek =setvalue-actualvalue;
PID->location_sum += PID->ek; //計算累計誤差值
if((PID->ki!=0)&&(PID->location_sum>(PID_LIMIT_MAX/PID->ki))) PID->location_sum=PID_LIMIT_MAX/PID->ki;
if((PID->ki!=0)&&(PID->location_sum<(PID_LIMIT_MIN/PID->ki))) PID->location_sum=PID_LIMIT_MIN/PID->ki;//積分限幅
PID->out=PID->kp*PID->ek+(PID->ki*PID->location_sum)+PID->kd*(PID->ek-PID->ek1);
PID->ek1 = PID->ek;
if(PID->out<PID_LIMIT_MIN) PID->out=PID_LIMIT_MIN;
if(PID->out>PID_LIMIT_MAX) PID->out=PID_LIMIT_MAX;//PID->out限幅
return PID->out;
}
//增量式PID
//pidout+=Kp[e(k)-e(k-1)]+Ki*e(k)+Kd[e(k)-2e(k-1)+e(k-2)]
//setvalue : 設定值(期望值)
//actualvalue: 實際值
float PID_increment(float setvalue, float actualvalue, PID_LocTypeDef *PID)
{
PID->ek =setvalue-actualvalue;
PID->out+=PID->kp*(PID->ek-PID->ek1)+PID->ki*PID->ek+PID->kd*(PID->ek-2*PID->ek1+PID->ek2);
// PID->out+=PID->kp*PID->ek-PID->ki*PID->ek1+PID->kd*PID->ek2;
PID->ek2 = PID->ek1;
PID->ek1 = PID->ek;
if(PID->out<PID_LIMIT_MIN) PID->out=PID_LIMIT_MIN;
if(PID->out>PID_LIMIT_MAX) PID->out=PID_LIMIT_MAX;//限幅
return PID->out;
}
pid.h
#ifndef __PID_H
#define __PID_H
#include "stm32f10x.h"
#include <math.h>
#include "sys.h"
typedef struct
{
float kp; //比例係數Proportional
float ki; //積分系數Integral
float kd; //微分系數Derivative
// float ti; //積分時間常數
// float td; //微分時間常數
// float period; //取樣週期
float ek; //當前誤差
float ek1; //前一次誤差e(k-1)
float ek2; //再前一次誤差e(k-2)
float location_sum; //累計積分位置
float out; //PID輸出值
}PID_LocTypeDef;
float PID_location(float setvalue, float actualvalue, PID_LocTypeDef *PID);
float PID_increment(float setvalue, float actualvalue, PID_LocTypeDef *PID);
#endif
注意:上述程式碼,在實際應用中,可能需要使用作業系統的定時器或中斷來實現。