SicMultiplate/Modules/Mainframe/TMs/TMPressureBalancePidRoutine.cs

678 lines
22 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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());
}
}
}
}