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 lstPressure = new List(); public TMPressureBalancePidRoutine() { Module = ModuleName.TM.ToString(); Name = "Pressure Balance PID"; _tm = DEVICE.GetDevice($"{ ModuleName.System.ToString()}.{ Module}"); _m40 = DEVICE.GetDevice($"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($"TM.PressureBalance.BalancePressure") + SC.GetValue("TM.TMPressureBigThanPM"); //TM的压力需要大于PM数值 } else { _balancePressure = SC.GetValue("TM.PressureBalance.BalancePressure"); } _ventTimeout = SC.GetValue("TM.PressureBalance.VentTimeout"); _pidP = SC.GetValue("TM.PressureBalance.PidP"); _pidI = SC.GetValue("TM.PressureBalance.PidI"); _pidD = SC.GetValue("TM.PressureBalance.PidD"); _pidMaxDiffPressure = SC.GetValue("TM.PressureBalance.BalanceMaxDiffPressure"); _pidSuccessCount = SC.GetValue("TM.PressureBalance.SuccessCount"); _pidSleepTime = SC.GetValue("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("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 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(); 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(); 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 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 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 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 lstPressure = new List(); // 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; // 3,case 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 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 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 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 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()); } } } }