参考资料:http://www.51hei.com/bbs/dpj-181096-1.html
/*
功能:用软件模拟PID控制温度
模型一:夏天要求室内的温度为23摄氏度左右,假定房间受室外高温影响,1分钟上升0.1摄氏度(上限为室外温度37摄氏度)。
释放一包制冷剂可降低5摄氏度,一包制热剂,可上升五度,温度变化由传感器采集,但是我用软件模拟温度变化,
假设一切处于理想状态。
*/
#include "SoftSimulation_PID_Header.h"
int main()
{
init_PID();
time_t timep;
struct tm *tp;
while (1)
{
if (pid.ActualTemperature < outdoorTemperature)
{
// 获取时间
time(&timep);
tp = gmtime(&timep);
AcquireTemperature(tp->tm_hour,tp->tm_min,tp->tm_sec);
}
PID_controlTemperature();
/* 当温度处于人体舒适的温度时,则不用制冷或加热 */
while (fabs(pid.SetTemperature - pid.ActualTemperature) < ComfortTemperature)
{
// 获取时间
time(&timep);
tp = gmtime(&timep);
// 获取计算机时间,10秒钟打印一次
printf("%d/%d/%d %d/%d/%d\n",1900+tp->tm_year,(1+tp->tm_mon),tp->tm_mday,tp->tm_hour + 8, tp->tm_min,tp->tm_sec);
printf("Display:设定温度为:%.2f\t室内温度为:%f\t\n\n", pid.SetTemperature, pid.ActualTemperature);
// 获取实时温度
AcquireTemperature(tp->tm_hour, tp->tm_min, tp->tm_sec);
Sleep(500);
}
}
}
/* Acquire indoor Temperature */
void AcquireTemperature(int hour,int minute,int second)
{
static int lastTime[3] = { 0 };
static float Minute = 0;
if (!lastTimeFlag )
{
lastTime[0] = hour;
lastTime[1] = minute;
lastTime[2] = second;
lastTimeFlag = 1;
}
else
{
if (pid.ActualTemperature <= outdoorTemperature)
{
Minute = (hour - lastTime[0]) * 60 + (minute - lastTime[1]) + float(second - lastTime[2]) / 60.0;
pid.ActualTemperature = pid.ActualTemperature + Minute * IncrementTemperature;
lastTime[0] = hour;
lastTime[1] = minute;
lastTime[2] = second;
//printf("Test:设定温度为:%.2f\t室内温度为:%f\t\n\n", pid.SetTemperature, pid.ActualTemperature);
}
else
{
// 温度升高过快,只记录时间,程序会在PID_controlTemperature函数中处理
lastTime[0] = hour;
lastTime[1] = minute;
lastTime[2] = second;
}
}
}
/* release the refrigeration */
void Refrigeration()
{
pid.ActualTemperature = pid.ActualTemperature - 5;
}
/* release the heating */
void Heating()
{
pid.ActualTemperature = pid.ActualTemperature + 5;
}
/* the PID arithmetic control the temperature of indoor */
void PID_controlTemperature()
{
if (pid.SetTemperature >= pid.ActualTemperature + TemperatureErr)
{
// 室内温度偏低,调用制热模块
Heating();
}
// 室内温度处于23度左右,使用PID精调
else if (fabs(pid.SetTemperature - pid.ActualTemperature) < TemperatureErr)
{
IncrementPID_realize(); // 增量式PID控制
//PositionPID_realize(); // 位置式PID控制,两者只要一个就可以了,之所以都贴出来,为了试试两种方式有什么不同
}
else if (pid.SetTemperature + TemperatureErr <= pid.ActualTemperature)
{
// 室内温度偏高,调用制冷模块
Refrigeration();
}
else
{
printf("区间考虑不周全\n");
}
}
/* initialize PID */
void init_PID()
{
pid.Kp = 0.2;
pid.Ki = 0.015;
pid.Kd = 0.2;
pid.SetTemperature = 23.0;
pid.ActualTemperature = outdoorTemperature;
lastTimeFlag = 0;
pid.ErrVal[0] = 0;
pid.ErrVal[1] = 0;
pid.ErrVal[2] = 0;
pid.Integral = 0;
printf("accomplish initialize PID \n");
}
/*
功能:使用增量式PID调节
公式:U(k)+Kp*[E(k)-E(k-1)]+Ki*E(k)+Kd*[E(k)-2E(k-1)+E(k-2)]
备注:网上的公式Kp乘以的东西有两种,第一种是Kp*[E(k)-E(k-1)],第二种是Kp*([E(k)-E(k-1)]+Ki*E(k)+Kd*[E(k)-2E(k-1)+E(k-2)])
这两种我都测试过,都能实现功能,前者更快一些,后者慢,但是我个人喜欢第二种
*/
void IncrementPID_realize()
{
pid.ErrVal[0] = pid.SetTemperature - pid.ActualTemperature; // 计算设定值与实际值直接的误差
float Temp0 = pid.Kp * (pid.ErrVal[0] - pid.ErrVal[1]);
//float Temp0 = (pid.ErrVal[0] - pid.ErrVal[1]);
float Temp1 = pid.Ki * pid.ErrVal[0];
float Temp2 = pid.Kd * (pid.ErrVal[0] - 2 * pid.ErrVal[1] + pid.ErrVal[2]);
float Increment = Temp0 + Temp1 + Temp2; // 通过公式计算增量
// float Increment = pid.Kp * (Temp0 + Temp1 + Temp2); // 通过公式计算增量
pid.ActualTemperature += Increment; // 计算实际温度
pid.ErrVal[1] = pid.ErrVal[0];
pid.ErrVal[2] = pid.ErrVal[1];
//printf("Realize:设定温度为:%.2f\t室内温度为:%.2f\t\n\n", pid.SetTemperature, pid.ActualTemperature);
}
/*
功能:使用位置式PID调节
公式:Kp*(E(k)+Ki*∑E(j)+Kd*[E(k)-E(k-1)])
备注:参考增量式的备注
*/
void PositionPID_realize()
{
pid.ErrVal[0] = pid.SetTemperature - pid.ActualTemperature; // 计算设定值与实际值直接的误差
pid.Integral += pid.ErrVal[0];
pid.ActualTemperature = pid.Kp * pid.ErrVal[0] + pid.Ki * pid.Integral + pid.Kd * (pid.ErrVal[0] - pid.ErrVal[1]);
pid.ErrVal[1] = pid.ErrVal[0];
}
</textarea>
头文件如下:
#include <stdio.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>
#include<windows.h>
typedef struct PID_Value
{
float ErrVal[3]; // 三次误差值
float Kp; // 比例系数
float Ki; // integral 系数
float Kd; // derivative 系数
float Integral; // 积分
float SetTemperature;
float ActualTemperature;
}PID_ValueStr,*PID_ValueT;
PID_Value pid;
#define outdoorTemperature 36.2
#define TemperatureErr 3
#define ComfortTemperature 0.5
#define IncrementTemperature 1 // 每分钟房间上升的温度
int lastTimeFlag = 0;
void AcquireTemperature(int hour, int minute, int second);
void PID_controlTemperature();
void Refrigeration();
void init_PID();
void IncrementPID_realize();
void PositionPID_realize();
————————————————
|