位制式PID算法
PID计算公式:
K:比例系数
E:为当前的偏差
T :PID的计算周期
T:积分周期
T:微分周期
E:前一次的偏差
OUT:常数
#ifndef _PID_
#define _PID_
#include "stm32f10x_conf.h"
void PID_Calc(void);
// 使用结构体定义PID所需的类型
typedef struct
{
float Sv; // 用户设定值
float Pv; // 当前的值
float Kp; // 比例系数
float T; // 计算周期or采样周期
float Ti; // 积分时间常数
float Td; // 微分系数
float Ek; // 本次的偏差
float Ek_1; // 上次的偏差
float SEk; // 前面n次历史偏差之和
float OUT0; // 当计算值为0时,维持一个稳定的输出
float OUT; // 输出的值
unsigned int C10ms;
unsigned int pwmcycle; // pwm周期
}PID;
// pid.c
#include "pid.h"
PID pid; // 存放PID算法所需的数据
void PID_Calc(void) // pid计算
{
float DelEk;
float ti, ki, td, kd;
float Pout,Iout,Dout, temp;
if(/*判断计算周期是否到了*/)
return;
pid.Ek = pid.Sv-pid.Pv; // 得到当前的偏差值
pid.SEK += pid.Ek; // 历史偏差总和
DelEk = pid.Ek - pid.Ek_1; // 最近两次偏差之差
ti = pid.T/pid.Ti; // 积分项
ki = ti*pid.Kp;
td = pid.Td/pid.T; // 微分项
kd = td*pid.Kp;
Pout = pid.Kp*pid.Ek; // 比例输出
Iout = ki*pid.SEK; // 积分输出
Dout = kd*(pid.Ek - pid.Ek_1); // 微分输出
temp = Pout + Iout + Dout + pid.OUT0; // 本次计算结果
// pid归并到有效值内
if(out>pid.pwmcycle)
{
pid.OUT = pid.pwmcycle;
}else if
{
pid.OUT = 0;
}else
{
pid.OUT = temp;
}
pid.Ek_1 = pid.Ek; // 本次输出后,将本次的值赋值到上一次的
pid.C10ms = 0;
}
// main.c
// 初始化PID所需的参数值(一般这些参数都是存储在可记忆存储位置)
void PID_Init()
{
pid.Sv = 100; // 用户设定温度 从存储器获取的值
pid.Kp = 20; // 从传感器获取的值
pid.T = 1000; // PID计算周期 1000ms
pid.Ti = 5000; // 积分时间5000ms
pid.Td = 1200; // 微分时间1200ms
pid.pwmcycle = 1000; // pwm周期1000;
}
int main()
{
//....
PID_Init();
while(1)
{
}
}
增量式PID算法
公式:
参数介绍:
Ek:本次的偏差
Ek_1:上次的偏差
Ek_2:上上次的偏差
Kp:算法增益调节
Ti:积分时间
Td:微分时间常数
结论:
增量式PID的计算只需要最近3次的偏差(本次偏差,上次偏差,上上次偏差),不需要处理器存储大量的历史偏差值,计算量也相对较少,容易实现。