常见的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
注意:上述代码,在实际应用中,可能需要使用操作系统的定时器或中断来实现。
标签:ek,示例,float,PID,算法,LIMIT,location,out From: https://www.cnblogs.com/zkbklink/p/18343915