Sic10/Modules/SicModules/TMs/TMPressureBalancePidRoutine.cs

678 lines
22 KiB
C#
Raw Normal View History

2023-05-10 10:26:01 +08:00
using Aitex.Core.RT.Device;
using Aitex.Core.RT.Device.Devices;
using Aitex.Core.RT.Device.Unit;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.Routine;
using Aitex.Core.RT.SCCore;
using Aitex.Core.Util;
using MECF.Framework.Common.Equipment;
using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.TMs;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Mainframe.TMs
{
public class TMPressureBalancePidRoutine : TMBaseRoutine
{
enum RoutineStep
{
OpenValve,
RunPid,
SetM40,
CloseValve,
OpenSlowVent,
CloseSlowVent,
OpenSlowPump,
CloseSlowPump,
Delay1,
}
private bool _pidAlways = false;
private SicTM _tm;
private IoMFC _m40;
private IoValve _TMTOLLVent;
private ModuleName _paramTarget;
private double _pidP;
private double _pidI;
private double _pidD;
//private bool _needMfcVent; //是否需要Vent操作
//private double _ventMfcFlow; //MFC在Vent时设置的值
private double _balancePressure; //目标压力值
private int _ventTimeout; //MFC 超时
private double _pidMaxDiffPressure; //PID与目标压力的差
//private int _waitPressureTimeout; //不需要Vent操作时等待压力平衡时间
private bool _isPidSucceed = false;
private bool _isPidRunning = true;
private int _pidSuccessCount; //压力到达范围内比较多少次就认为PID成功
private int _pidSleepTime;
private bool _pressureAboveTarget = false;
private bool _needVentOrPump = false;
List<double> lstPressure = new List<double>();
public TMPressureBalancePidRoutine()
{
Module = ModuleName.TM.ToString();
Name = "Pressure Balance PID";
_tm = DEVICE.GetDevice<SicTM>($"{ ModuleName.System.ToString()}.{ Module}");
_m40 = DEVICE.GetDevice<IoMFC>($"TM.Mfc40");
}
public void Init(ModuleName target)
{
Name = "Pressure Balance PID with " + target;
_paramTarget = target;
_pidAlways = false;
}
public void Init(ModuleName target, bool alwaysPID)
{
Name = "Pressure Balance PID with " + target;
_paramTarget = target;
_pidAlways = alwaysPID;
}
public override Result Start(params object[] objs)
{
if (ModuleHelper.IsPm(_paramTarget))
{
if (!SC.ContainsItem($"TM.PressureBalance.BalancePressure"))
{
EV.PostAlarmLog(Module, $"did not define balance pressure for {_paramTarget}");
return Result.FAIL;
}
_balancePressure = SC.GetValue<double>($"TM.PressureBalance.BalancePressure") + SC.GetValue<double>("TM.TMPressureBigThanPM"); //TM的压力需要大于PM数值
}
else
{
_balancePressure = SC.GetValue<double>("TM.PressureBalance.BalancePressure");
}
_ventTimeout = SC.GetValue<int>("TM.PressureBalance.VentTimeout");
_pidP = SC.GetValue<double>("TM.PressureBalance.PidP");
_pidI = SC.GetValue<double>("TM.PressureBalance.PidI");
_pidD = SC.GetValue<double>("TM.PressureBalance.PidD");
_pidMaxDiffPressure = SC.GetValue<double>("TM.PressureBalance.BalanceMaxDiffPressure");
_pidSuccessCount = SC.GetValue<int>("TM.PressureBalance.SuccessCount");
_pidSleepTime = SC.GetValue<int>("TM.PressureBalance.SleepTime");
if (_balancePressure <= 1)
{
return Result.DONE;
}
_isPidSucceed = false;
_needVentOrPump = true;
if (Math.Abs(_tm.ChamberPressure - _balancePressure) < 10)
{
_needVentOrPump = false;
}
else
{
if (_tm.ChamberPressure > _balancePressure)
{
_pressureAboveTarget = true;
}
else
{
_pressureAboveTarget = false;
}
}
_tm.SetVentMfc(10, out string reasonxx);
Notify("Start");
return Result.RUN;
}
public override Result Monitor()
{
try
{
if (SC.GetValue<bool>("System.IsATMMode"))
{
return Result.DONE;
}
if (_needVentOrPump)
{
if (_pressureAboveTarget)
{
OpenSlowPumpToTarget((int)RoutineStep.OpenSlowPump, _tm, _balancePressure, 200);
CloseSlowPump((int)RoutineStep.CloseSlowPump, _tm);
TimeDelay((int)RoutineStep.Delay1, 1);
}
else
{
OpenSlowVentToTarget((int)RoutineStep.OpenSlowVent,_tm, _balancePressure,200);
}
}
SetPIDValve((int)RoutineStep.OpenValve, _tm, true, 2);
RunPid((int)RoutineStep.RunPid, _ventTimeout);
//不需要关闭阀门
if (!_pidAlways)
{
SetPIDValve((int)RoutineStep.CloseValve, _tm, false, 2);
}
}
catch (RoutineBreakException)
{
return Result.RUN;
}
catch (RoutineFaildException)
{
return Result.FAIL;
}
return Result.DONE;
}
public override void Abort()
{
_isPidRunning = false;
_tm.SetPIDValve(false, out string reason);
_tm.SetSlowVentValve(false, out reason);
_tm.SetFastVentValve(false, out reason);
_tm.SetSlowPumpValve(false, out reason);
_tm.SetFastPumpValve(false, out reason);
}
private bool PidPressureReach()
{
if (lstPressure.Count >= _pidSuccessCount)
{
for (int i = 0; i < _pidSuccessCount; i++)
{
if (Math.Abs(lstPressure[i]) > _pidMaxDiffPressure)
{
return false;
}
}
return true;
}
else
{
return false;
}
}
public void RunPid(int id, int timeout)
{
Tuple<bool, Result> ret = ExecuteAndWait(id, () =>
{
Notify($"Run PID for {_paramTarget}");
Task.Factory.StartNew(() => TMPressureBalancePid(timeout));
return true;
}, () =>
{
return _isPidSucceed;
}, timeout * 1000);
if (ret.Item1)
{
if (ret.Item2 == Result.TIMEOUT) //timeout
{
Stop($"Run PID for {_paramTarget} timeout, over {timeout} seconds");
throw (new RoutineFaildException());
}
else
throw (new RoutineBreakException());
}
}
public void TMPressureBalancePid(int timeOut)
{
bool firstReachTarget = false;
bool isLowThanTarget = _tm.ChamberPressure <_balancePressure;
DeviceTimer timer = new DeviceTimer();
timer.Start(timeOut * 1000);
double MP = 0;
double MI = 0;
double MD = 0;
double M = 0;
double LE = 0;
double E = _balancePressure - _tm.ChamberPressure;
while (_isPidRunning)
{
//第一次穿过目标值时,重新开始PID,以节省调节时间
if (firstReachTarget == false)
{
if (isLowThanTarget && _tm.ChamberPressure > _balancePressure)
{
MP = 0;
MI = 0;
MD = 0;
M = 0;
LE = 0;
E = _balancePressure - _tm.ChamberPressure;
lstPressure = new List<double>();
firstReachTarget = true;
}
else if(!isLowThanTarget && _tm.ChamberPressure < _balancePressure)
{
MP = 0;
MI = 0;
MD = 0;
M = 0;
LE = 0;
E = _balancePressure - _tm.ChamberPressure;
lstPressure = new List<double>();
firstReachTarget = true;
}
}
if (lstPressure.Count > _pidSuccessCount)
{
lstPressure.RemoveAt(0);
}
LE = E;
E = _balancePressure - _tm.ChamberPressure;
lstPressure.Add(E);
MP = _pidP * E;
MI += _pidI * E;
MD = _pidD * (E - LE);
M = MP + MI + MD;
_tm.SetVentMfc(M, out string reason);
_isPidRunning = !PidPressureReach();
if (timer.IsTimeout())
{
_isPidSucceed = false;
_isPidRunning = false;
}
Thread.Sleep(_pidSleepTime);
}
_isPidSucceed = true;
}
public void SetM40(int id, IoMFC m40)
{
Tuple<bool, Result> ret = Execute(id, () =>
{
Notify($"Set M40 flow default value");
m40.Terminate();
return true;
});
if (ret.Item1)
{
if (ret.Item2 == Result.FAIL)
{
throw (new RoutineFaildException());
}
else
throw (new RoutineBreakException());
}
}
public void SetPIDValve(int id, SicTM tm, bool isOpen, int timeout)
{
Tuple<bool, Result> ret = ExecuteAndWait(id, () =>
{
Notify($"Open Slow Vent Valve and V121 for PID");
if (!tm.SetPIDValve(isOpen, out string reason))
{
Stop(reason);
return false;
}
return true;
}, () =>
{
return tm.CheckPIDValve(isOpen);
}, timeout * 1000);
if (ret.Item1)
{
if (ret.Item2 == Result.TIMEOUT) //timeout
{
Stop($"Set PID valve timeout, over {timeout} seconds");
throw (new RoutineFaildException());
}
else
throw (new RoutineBreakException());
}
}
//public void RunPid(int id, int timeout)
//{
// Tuple<bool, Result> ret = ExecuteAndWait(id, () =>
// {
// Notify($"Run PID for {_paramTarget}");
// Task.Factory.StartNew(() => TMPressureBalancePid(timeout));
// return true;
// }, () =>
// {
// return _isPidSucceed;
// }, timeout * 1000);
// if (ret.Item1)
// {
// if (ret.Item2 == Result.TIMEOUT) //timeout
// {
// Stop($"Run PID for {_paramTarget} timeout, over {timeout} seconds");
// throw (new RoutineFaildException());
// }
// else
// throw (new RoutineBreakException());
// }
//}
//private void TMPressureBalancePid(int timeout)
//{
// string reason = string.Empty;
// try
// {
// _isPidRunning = true;
// double tolerance = _maxPressureDiffOpenSlitValve;
// double lowLimit = _balancePressure - 0.5;
// double upLimit = _balancePressure + tolerance - 1;
// double FP, FD;
// double FI = _tm.ChamberPressure;
// double Pn = FI;
// double Fn;
// int step = 0;
// double mfcFlow = 0;
// List<double> lstPressure = new List<double>();
// DeviceTimer timer = new DeviceTimer();
// timer.Start(timeout * 1000);
// while (_isPidRunning)
// {
// if (_tm.ChamberPressure >= lowLimit && _tm.ChamberPressure < upLimit)
// {
// lstPressure.Add(_tm.ChamberPressure);
// if (lstPressure.Count >= 100)
// {
// double avg = lstPressure.Average();
// lstPressure.RemoveAt(0);
// if (avg >= lowLimit && avg < upLimit)
// {
// if (!_isPidSucceed)
// {
// _isPidSucceed = true;
// break;
// }
// }
// }
// }
// switch (step)
// {
// case 0:
// if (_tm.ChamberPressure >= _balancePressure + 2)
// {
// _tm.SetVentMfc(0, out reason);
// _tm.SetMfcVentValve(false, out reason);
// if (!_tm.SetFastPumpValve(true, out reason))
// {
// Stop(reason);
// step = 10;
// }
// else
// {
// step = 2; // 1 为了防止气流不稳不能关闭Pump阀门
// }
// }
// else
// {
// step = 2; // 1 为了防止气流不稳不能关闭Pump阀门
// }
// break;
// case 2:
// if (_tm.ChamberPressure < _balancePressure - 1)
// {
// if (mfcFlow < _ventMfcFlow)
// {
// mfcFlow += _ventMfcStepFlow;
// }
// else
// {
// mfcFlow = 0;
// }
// _tm.SetVentMfc(mfcFlow, out reason);
// _tm.SetMfcVentValve(true, out reason);
// }
// else
// {
// step = 4; // 3case 3 没用了
// }
// break;
// case 4:
// FP = _pidP * (_balancePressure - _tm.ChamberPressure);
// if (Math.Abs(Pn - _tm.ChamberPressure) < 3.0 * tolerance)
// {
// FI = FI + _pidI * (_balancePressure - _tm.ChamberPressure);
// }
// FD = _pidD * (Pn - _tm.ChamberPressure);
// Fn = FP + FI + FD;
// Fn = Math.Min(Fn, 7000.0);
// Fn = Math.Max(Fn, 5000.0);
// if (Fn < 0)
// {
// Fn = 0;
// }
// else if (Fn > _ventMfcFlow)
// {
// Fn = _ventMfcFlow;
// }
// _tm.SetVentMfc(Fn, out reason);
// _tm.SetMfcVentValve(true, out reason);
// Pn = _tm.ChamberPressure;
// step = _tm.ChamberPressure > (_balancePressure + 3) ? 0 : 2; // 0 : 1 为了防止气流不稳不能关闭Pump阀门
// if (timer.IsTimeout())
// {
// step = 10;
// }
// break;
// case 10:
// _isPidRunning = false;
// _isPidSucceed = false;
// break;
// }
// Thread.Sleep(100);
// }
// }
// catch (Exception ex)
// {
// _isPidRunning = false;
// _isPidSucceed = false;
// LOG.Write(ex, $"Run PID for {_paramTarget} failed");
// }
// _tm.SetVentMfc(0, out reason);
// _tm.SetMfcVentValve(false, out reason);
// _tm.SetFastPumpValve(false, out reason);
// if (_isPidSucceed)
// {
// Notify($"Succeed");
// }
// else
// {
// Notify($"Failed");
// }
//}
public void OpenSlowPumpToTarget(int id, TM tm, double basePressure, int timeout)
{
Tuple<bool, Result> ret = ExecuteAndWait(id, () =>
{
Notify($"Open {tm.Name} slow pump valve");
if (!tm.SetSlowPumpValve(true, out string reason))
{
Stop(reason);
return false;
}
return true;
}, () =>
{
return Math.Abs(tm.ChamberPressure - basePressure) < 10;
}, timeout * 1000);
if (ret.Item1)
{
if (ret.Item2 == Result.FAIL)
{
throw (new RoutineFaildException());
}
else if (ret.Item2 == Result.TIMEOUT) //timeout
{
tm.SetFastPumpValve(false, out string _);
Stop($"{tm.Name} pressure can not pump to {basePressure} in {timeout} seconds");
throw (new RoutineFaildException());
}
else
throw (new RoutineBreakException());
}
}
public void CloseSlowPump(int id, TM tm)
{
Tuple<bool, Result> ret = Execute(id, () =>
{
Notify($"Close {tm.Name} pump valves");
if (!_tm.SetSlowPumpValve(false, out string reason))
{
Stop(reason);
return false;
}
return true;
});
if (ret.Item1)
{
if (ret.Item2 == Result.FAIL)
{
throw (new RoutineFaildException());
}
else
throw (new RoutineBreakException());
}
}
public void OpenSlowVentToTarget(int id, TM tm, double basePressure, int timeout)
{
Tuple<bool, Result> ret = ExecuteAndWait(id, () =>
{
Notify($"Open {tm.Name} slow vent valve");
if (!tm.SetSlowVentValve(true, out string reason))
{
Stop(reason);
return false;
}
return true;
}, () =>
{
return Math.Abs(tm.ChamberPressure - basePressure) < 10;
}, timeout * 1000);
if (ret.Item1)
{
if (ret.Item2 == Result.FAIL)
{
throw (new RoutineFaildException());
}
else if (ret.Item2 == Result.TIMEOUT) //timeout
{
tm.SetFastPumpValve(false, out string _);
Stop($"{tm.Name} pressure can not vent to {basePressure} in {timeout} seconds");
throw (new RoutineFaildException());
}
else
throw (new RoutineBreakException());
}
}
public void CloseSlowVent(int id, TM tm)
{
Tuple<bool, Result> ret = Execute(id, () =>
{
Notify($"Close {tm.Name} vent valves");
if (!_tm.SetSlowVentValve(false, out string reason))
{
Stop(reason);
return false;
}
return true;
});
if (ret.Item1)
{
if (ret.Item2 == Result.FAIL)
{
throw (new RoutineFaildException());
}
else
throw (new RoutineBreakException());
}
}
}
}