參考資料:http://www.zg4o1577.cn/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();
————————————————
|