using Aitex.Core.Common.DeviceData; using Aitex.Core.RT.DataCenter; using Aitex.Core.RT.Event; using Aitex.Core.RT.IOCore; using Aitex.Core.RT.OperationCenter; using Aitex.Core.RT.SCCore; using Aitex.Core.RT.Tolerance; using Aitex.Core.Util; using MECF.Framework.Common.CommonData; using MECF.Framework.Common.Device.Bases; using MECF.Framework.Common.Event; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Xml; namespace FurnaceRT.Devices { public class IoHeaterBand : HeaterBase { public IoHeaterBand(string module, XmlElement node, string ioModule = "") { base.Module = string.IsNullOrEmpty(node.GetAttribute("module")) ? module : node.GetAttribute("module"); base.Name = node.GetAttribute("id"); base.Display = node.GetAttribute("display"); base.DeviceID = node.GetAttribute("schematicId"); formatString = node.GetAttribute("formatString"); InstallZone = node.GetAttribute("installzone"); _uniqueName = $"{Module}{Name}"; _aiPV = ParseAiNode("aiPV", node, ioModule); _aiMV = ParseAiNode("aiMV", node, ioModule); _aiPID_P = ParseAiNode("aiPID_P", node, ioModule); _aiPID_I = ParseAiNode("aiPID_I", node, ioModule); _aiPID_D = ParseAiNode("aiPID_D", node, ioModule); _aiControlOutput = ParseAiNode("aiControlOutput", node, ioModule); _aiErrorID = ParseAiNode("aiErrorID", node, ioModule); _aiSV = ParseAiNode("aiTemperatureSVFeedback", node, ioModule); _aiAutotuneActivate = ParseAiNode("aiAutotuneActivate", node, ioModule); _aiAlarmHigher = ParseAiNode("aiAlarmHigher", node, ioModule); _aiAlarmLower = ParseAiNode("aiAlarmLower", node, ioModule); _aiEnableIn = ParseAiNode("aiEnableIn", node, ioModule); _aiUpRate = ParseAiNode("aiUpRate", node, ioModule); _aiDownRate = ParseAiNode("aiDownRate", node, ioModule); _aiSBrkOut = ParseAiNode("aiSBrkOut", node, ioModule); _aoSetPoint = ParseAoNode("aoSetPoint", node, ioModule); _aoPID_P = ParseAoNode("aoPID_P", node, ioModule); _aoPID_I = ParseAoNode("aoPID_I", node, ioModule); _aoPID_D = ParseAoNode("aoPID_D", node, ioModule); _aoManualOutput = ParseAoNode("aoManualOutput", node, ioModule); _aoControlPeriodTime = ParseAoNode("aoControlPeriodTime", node, ioModule); _aoAlarmHigher = ParseAoNode("aoAlarmHigher", node, ioModule); _aoAlarmLower = ParseAoNode("aoAlarmLower", node, ioModule); _aoUpRate = ParseAoNode("aoUpRate", node, ioModule); _aoDownRate = ParseAoNode("aoDownRate", node, ioModule); _aoEnableIn = ParseAoNode("aoEnableIn", node, ioModule); _aoAutotuneActivate = ParseAoNode("aoAutotuneActivate", node, ioModule); _diControlDoing = ParseDiNode("diControlDoing", node, ioModule); _diAutoTuningDoing = ParseDiNode("diAutoTuningDoing", node, ioModule); _diAutoTuningDone = ParseDiNode("diAutoTuningDone", node, ioModule); _diPIDControlError = ParseDiNode("diPIDControlError", node, ioModule); _diTimePropControlError = ParseDiNode("diTimePropControlError", node, ioModule); _doEnable = ParseDoNode("doEnable", node, ioModule); _doManualControl = ParseDoNode("doManualControl", node, ioModule); _doAutoTuning = ParseDoNode("doAutoTuning", node, ioModule); _doSelect = ParseDoNode("doMainPVSelect", node, ioModule); _doCascadeMode = ParseDoNode("doCascadeMode", node, ioModule); _scRoot = node.GetAttribute("scRoot"); } #region fields private AIAccessor _aiPV; private AIAccessor _aiMV; private AIAccessor _aiPID_P; private AIAccessor _aiPID_I; private AIAccessor _aiPID_D; private AIAccessor _aiControlOutput; private AIAccessor _aiErrorID; private AIAccessor _aiSV;//gas line heater才有 private AIAccessor _aiAutotuneActivate;//gas line heater才有 private AIAccessor _aiEnableIn;//gas line heater才有 private AIAccessor _aiAlarmHigher; private AIAccessor _aiAlarmLower; private AIAccessor _aiUpRate;//gas line heater才有 private AIAccessor _aiDownRate;//gas line heater才有 private AIAccessor _aiSBrkOut;//gas line heater才有 private AOAccessor _aoUpRate;//gas line heater才有 private AOAccessor _aoDownRate;//gas line heater才有 private AOAccessor _aoEnableIn;//gas line heater才有 private AOAccessor _aoAutotuneActivate;//gas line heater才有 private AOAccessor _aoSetPoint; private AOAccessor _aoPID_P; private AOAccessor _aoPID_I; private AOAccessor _aoPID_D; private AOAccessor _aoManualOutput; private AOAccessor _aoControlPeriodTime; private AOAccessor _aoAlarmHigher; private AOAccessor _aoAlarmLower; private DIAccessor _diControlDoing; private DIAccessor _diAutoTuningDoing; private DIAccessor _diAutoTuningDone; private DIAccessor _diPIDControlError; private DIAccessor _diTimePropControlError; private DOAccessor _doEnable; private DOAccessor _doManualControl; private DOAccessor _doAutoTuning; private DOAccessor _doSelect; private DOAccessor _doCascadeMode; private string formatString; private const int physicalMax = 16000; private ToleranceChecker _toleranceCheckerWarning = new ToleranceChecker(); private ToleranceChecker _toleranceCheckerAlarm = new ToleranceChecker(); //tolerance check private float _alarmJudgmentRange; private float _warningJudgmentRange; private float _alarmJudgmentTime; private float _warningJudgmentTime; private float _toleranceJudgmentDelayTime; private DeviceTimer _toleranceJudgmentDelayTimer = new DeviceTimer(); //stable check private DeviceTimer _stableJudgmentTimer = new DeviceTimer(); private float _stableJudgmentTime; private float _stableMinValue; private float _stableMaxValue; private SCConfigItem _scEnableCalibration; private SCConfigItem _scCalibrationTable; private SCConfigItem _scRange; private SCConfigItem _scRampRate;//°C/min private List _calibrationTable = new List(); private string _previousSetting; private DeviceTimer _rampTimer = new DeviceTimer(); private double _rampTarget; private double _rampInitValue; private int _rampTime; private DeviceTimer _stableTimer = new DeviceTimer(); private bool _isWarned; private string _uniqueName; private float _tempSetpoint; private string _scRoot; private bool _isStartRamp = false; private bool _isFloatAioType = true; #endregion #region properties public string InstallZone { get; set; } public double Range => _scRange.DoubleValue; public AlarmEventItem AlarmToleranceWarning { get; set; } public AlarmEventItem AlarmToleranceAlarm { get; set; } public AlarmEventItem InterlockAlarm { get; set; } public AlarmEventItem HeaterErrorAlarm { get; set; } public AlarmEventItem HeaterErrorRecoveryWarning { get; set; } public AlarmEventItem HeaterStripBreakAlarm { get; set; } public AlarmEventItem HeaterStripBreakWarning { get; set; } public bool IsHeaterStripBreak { get; set; } private RD_TRIG _trigHeaterErrorSignalOn = new RD_TRIG(); public R_TRIG TrigHeaterStripBreakSignalOn = new R_TRIG(); public DeviceTimer HeaterStripBreakTimer = new DeviceTimer(); public string InstallPosition => SC.GetStringValue($"{_scRoot}.Heater.{InstallZone}.{Name}.InstallPosition"); public bool IsError => _diPIDControlError == null || _diTimePropControlError == null ? false : _diPIDControlError.Value || _diTimePropControlError.Value; public override bool IsPowerOn { get; set; } public bool IsStable { get { if (!_stableJudgmentTimer.IsIdle()) { if (DeviceData.FeedBack < (DeviceData.SetPoint - _stableMinValue) || DeviceData.FeedBack > (DeviceData.SetPoint + _stableMaxValue)) { _stableJudgmentTimer.Start(0); } if (_stableJudgmentTimer.GetElapseTime() >= _stableJudgmentTime * 1000) { return true; } } else { _stableJudgmentTimer.Start(0); } return false; } } public override float TempSetPoint { get { if (_aiSV != null) { if (_isFloatAioType) return _aiSV.FloatValue; else return _aiSV.Value; } if (_aoSetPoint != null) { if (_isFloatAioType) return _aoSetPoint.FloatValue; else return _aoSetPoint.Value; } return _tempSetpoint; } set { _tempSetpoint = value; if (_aoSetPoint != null) { if (_isFloatAioType) _aoSetPoint.FloatValue = value; else _aoSetPoint.Value = (short)value; } } } public override float TempFeedback { get { if (_aiPV == null) return 0; float feedback = 0.0f; if (_isFloatAioType) { int temp = (int)(_aiPV.FloatValue * 10); feedback = (float)(temp) / 10; } else { feedback = _aiPV.Value; } return feedback; } } public bool IsEnableMVLimiter { get; set; } = false; public bool IsEnable { get { if (_diControlDoing != null) return _diControlDoing.Value; if (_aiEnableIn != null) return _aiEnableIn.FloatValue > 0; if (_aoEnableIn != null) return _aoEnableIn.FloatValue > 0; if (_doEnable != null) return _doEnable.Value; return false; } } #endregion public override bool Initialize() { DeviceData = new AITHeaterData() { DeviceName = Name, DeviceSchematicId = DeviceID, DisplayName = SC.GetStringValue($"{_scRoot}.Heater.{InstallZone}.{Name}.DisplayName"), Module = Module, //Scale = SC.GetValue($"{_scRoot}.{Name}.Range"), Scale = 1200, Unit = "°C", //SetPoint = TempSetPoint, FeedBack = TempFeedback, }; _scEnableCalibration = SC.GetConfigItem($"{_scRoot}.{Name}.EnableCalibration"); _scCalibrationTable = SC.GetConfigItem($"{_scRoot}.{Name}.CalibrationTable"); //_scRange = SC.GetConfigItem($"{_scRoot}.{Name}.Range"); _scRampRate = SC.GetConfigItem($"{_scRoot}.{Name}.RampRate"); //AlarmToleranceWarning = SubscribeAlarm($"{_scRoot}.{Name}.ToleranceWarning", "", ResetWarningChecker, EventLevel.Warning); //AlarmToleranceAlarm = SubscribeAlarm($"{_scRoot}.{Name}.ToleranceAlarm", "", ResetAlarmChecker); //AlarmToleranceWarning.Id = SC.ContainsItem($"{_scRoot}.{Name}.ToleranceWarningID") ? SC.GetValue($"{_scRoot}.{Name}.ToleranceWarningID") : 0; //AlarmToleranceAlarm.Id = SC.ContainsItem($"{_scRoot}.{Name}.ToleranceAlarmID") ? SC.GetValue($"{_scRoot}.{Name}.ToleranceAlarmID") : 0; //_stableJudgmentTime = (float)SC.GetValue($"{_scRoot}.{Name}.Stabilize.JudgmentTime"); //_stableMinValue = (float)SC.GetValue($"{_scRoot}.{Name}.Stabilize.MinusValue"); //_stableMaxValue = (float)SC.GetValue($"{_scRoot}.{Name}.Stabilize.PlusValue"); //var fb = (float)CalibrationData(_aoTemperature.FloatValue, false); //_tempSetpoint = fb < 0 ? 0 : fb; DATA.Subscribe($"{Module}.{Name}.IsEnable", () => IsEnable); if(_aiMV != null) DATA.Subscribe($"{Module}.{Name}.MV", () => _aiMV.FloatValue); if (_aiControlOutput != null) DATA.Subscribe($"{Module}.{Name}.ControlOutput", () => _aiControlOutput.FloatValue); if (_aiErrorID != null) DATA.Subscribe($"{Module}.{Name}.ErrorID", () => _aiErrorID.FloatValue); if (_doManualControl != null) DATA.Subscribe($"{Module}.{Name}.IsManualControl", () => _doManualControl.Value); if (_diControlDoing != null) DATA.Subscribe($"{Module}.{Name}.IsControlDoing", () => _diControlDoing.Value); if (_diAutoTuningDoing != null) DATA.Subscribe($"{Module}.{Name}.IsAutoTuningDoing", () => _diAutoTuningDoing.Value); if (_diAutoTuningDone != null) DATA.Subscribe($"{Module}.{Name}.IsAutoTuningDone", () => _diAutoTuningDone.Value); OP.Subscribe($"{Module}.{Name}.SetProportioning", SetPID_P); OP.Subscribe($"{Module}.{Name}.SetIntegral", SetPID_I); OP.Subscribe($"{Module}.{Name}.SetDerivative", SetPID_D); OP.Subscribe($"{Module}.{Name}.SetRemoteMode", SetRemoteMode); OP.Subscribe($"{Module}.{Name}.SetAutoTuning", SetAutoTuning); OP.Subscribe($"{Module}.{Name}.SetOnOff", SetOnOff); OP.Subscribe($"{Module}.{Name}.SetAlarmWatchTable", (function, args) => { SetAlarmWatchTable(args[0].ToString()); return true; }); //for recipe OP.Subscribe($"{Module}.{Name}.SetParameters", (out string reason, int time, object[] param) => { reason = string.Empty; SetParameters(param); return true; }); //if (_diRunning.Value) //{ // var temperature = SC.GetValue($"{_scRoot}.{Name}.SetPoint"); // if (temperature != SetpointFeedback) // { // var ramp = SC.GetValue($"{_scRoot}.{Name}.RampRate"); // var _rampTime = ramp != 0 ? (Math.Abs(temperature - TempFeedback) / ramp) * 60 * 1000 : 0; // Ramp(temperature, (int)_rampTime); // } //} return base.Initialize(); } public override void Monitor() { DeviceData.ProportioningSetPoint = _aoPID_P == null ? 0 : _aoPID_P.FloatValue; DeviceData.IntegralSetPoint = _aoPID_I == null ? 0 : _aoPID_I.FloatValue; DeviceData.DerivativeSetPoint = _aoPID_D == null ? 0 : _aoPID_D.FloatValue; DeviceData.FeedBack = TempFeedback; DeviceData.SetPoint = TempSetPoint; DeviceData.ManipulatedVariable = _aiMV == null ? 0 : _aiMV.FloatValue; DeviceData.RampSetPoint = TempSetPoint;//Ramp的过程值 MonitorTolerance(); Ramping(); base.Monitor(); } private void SetAlarmWatchTable(string table) { DeviceData.AlarmWatchTable = table; SC.SetItemValueFromString($"{_scRoot}.{Name}.TempAlarmTableValue", table); if (SC.ContainsItem($"AlarmWatchTable.TempAlarmWatch.{table}.DelayTime")) { var scPath = $"AlarmWatchTable.TempAlarmWatch.{table}"; _toleranceJudgmentDelayTime = (float)SC.GetValue($"{scPath}.DelayTime"); _alarmJudgmentRange = (float)SC.GetValue($"{scPath}.AlarmJudgment"); _warningJudgmentRange = (float)SC.GetValue($"{scPath}.WarningJudgment"); _alarmJudgmentTime = (float)SC.GetValue($"{scPath}.AlarmJudgmentTime"); _warningJudgmentTime = (float)SC.GetValue($"{scPath}.WarningJudgmentTime"); } } public override void SetTemperature(float temperature) { SaveSetPoint(temperature.ToString()); //if (temperature != SetpointFeedback) { var _rampTime = _scRampRate.DoubleValue != 0 ? (Math.Abs(temperature - TempFeedback) / _scRampRate.DoubleValue) * 60 * 1000 : 0; Ramp(temperature, (int)_rampTime); } } public void SetRamping(float ramping) { SaveRampRate(ramping.ToString("F1")); } private void SetParameters(object[] param) { if (param != null && param.Length > 0) { float temperature = 0.0f; float ramp = 0.0f; string alarmWatchTable = ""; string PIDModel = ""; var array = param[0].ToString().Split(';');//tmep;ramp;ControlMode;AlarmTable if (System.Text.RegularExpressions.Regex.Match(array[0].ToString(), @"[a-zA-Z]").Success) { var table = array[0].ToString().Split(':');//AssociateParameterTable if (SC.ContainsItem($"PM1.RecipeEditParameter.TempSetting.{table[0]}.{InstallZone}")) { temperature = (float)SC.GetValue($"PM1.RecipeEditParameter.TempSetting.{table[0]}.{InstallZone}"); } } else { float.TryParse(array[0].ToString(), out temperature); } if (array.Length > 1) { float.TryParse(array[1], out ramp); DeviceData.Ramping = ramp; } if (array.Length > 2) { PIDModel = array[2].ToString(); if (PIDModel.ToLower().Contains("cascade")) { _doSelect.Value = false; _doCascadeMode.Value = false; } else if (PIDModel.ToLower().Contains("spike") && InstallPosition.ToLower().Contains("spike")) { _doSelect.Value = false; _doCascadeMode.Value = true; } else if (PIDModel.ToLower().Contains("paddle") && InstallPosition.ToLower().Contains("paddle")) { _doSelect.Value = true; _doCascadeMode.Value = true; } else { return; } } if (temperature != DeviceData.SetPoint) { } DeviceData.SetPoint = temperature; SetPID(temperature); if (array.Length > 3) { alarmWatchTable = array[4].ToString(); if (string.IsNullOrEmpty(alarmWatchTable) || alarmWatchTable == "0" || alarmWatchTable == "None") { DeviceData.AlarmWatchTable = "None"; _toleranceJudgmentDelayTime = 0; _alarmJudgmentRange = 0; _warningJudgmentRange = 0; _alarmJudgmentTime = 0; _warningJudgmentTime = 0; _toleranceJudgmentDelayTimer.Stop(); } else { DeviceData.AlarmWatchTable = $"Table{alarmWatchTable}"; if (SC.ContainsItem($"PM1.RecipeEditParameter.AlarmWatchTable.TempAlarmWatch.Table{alarmWatchTable}.DelayTime")) { var scPath = $"PM1.RecipeEditParameter.AlarmWatchTable.TempAlarmWatch.Table{alarmWatchTable}"; _toleranceJudgmentDelayTime = (float)SC.GetValue($"{scPath}.DelayTime"); _alarmJudgmentRange = (float)SC.GetValue($"{scPath}.AlarmJudgment"); _warningJudgmentRange = (float)SC.GetValue($"{scPath}.WarningJudgment"); _alarmJudgmentTime = (float)SC.GetValue($"{scPath}.AlarmJudgmentTime"); _warningJudgmentTime = (float)SC.GetValue($"{scPath}.WarningJudgmentTime"); _toleranceJudgmentDelayTimer.Start(0); } else { _toleranceJudgmentDelayTime = 0; _alarmJudgmentRange = 0; _warningJudgmentRange = 0; _alarmJudgmentTime = 0; _warningJudgmentTime = 0; _toleranceJudgmentDelayTimer.Stop(); } } ResetWarningChecker(); ResetAlarmChecker(); AlarmToleranceWarning.Reset(); AlarmToleranceAlarm.Reset(); } //SaveSetPoint(temperature.ToString()); //SaveRampRate(ramp.ToString()); //if (temperature != SetpointFeedback) var _rampTime = ramp != 0 ? (Math.Abs(temperature - TempFeedback) / ramp) * 60 * 1000 : 0; Ramp(temperature, (int)_rampTime); EV.PostInfoLog(Module, $"{Name} temperature set to {DeviceData.SetPoint} ℃"); } } private bool SetPID_P(out string reason, int time, params object[] param) { reason = string.Empty; if (param == null || param.Length == 0) { reason = $"invalid parameter"; return false; } float.TryParse(param[0].ToString(), out float p); _aoPID_P.FloatValue = p; return true; } private bool SetPID_I(out string reason, int time, params object[] param) { reason = string.Empty; if (param == null || param.Length == 0) { reason = $"invalid parameter"; return false; } float.TryParse(param[0].ToString(), out float i); _aoPID_I.FloatValue = i; return true; } private bool SetPID_D(out string reason, int time, params object[] param) { reason = string.Empty; if (param == null || param.Length == 0) { reason = $"invalid parameter"; return false; } float.TryParse(param[0].ToString(), out float d); _aoPID_D.FloatValue = d; return true; } private bool SetRemoteMode(out string reason, int time, params object[] param) { reason = string.Empty; if (param == null || param.Length == 0) { reason = $"invalid parameter"; return false; } bool.TryParse(param[0].ToString(), out bool isRemoteMode); //_doRemoteControl.SetValue(isRemoteMode, out _); return true; } private bool SetOnOff(out string reason, int time, params object[] param) { reason = string.Empty; if (param == null || param.Length == 0) { reason = $"invalid parameter"; return false; } bool.TryParse(param[0].ToString(), out bool isOn); //if (!_doStartHeating.Check(isOn, out reason)) //{ // return false; //} //return _doStartHeating.SetValue(isOn, out reason); return true; } public void SetRun(bool isOn) { //_doStartHeating.SetValue(isOn, out _); EV.PostInfoLog(Name, $"{Name}.SetRun({isOn})"); } public void SetRemote(bool isRemote) { //_doRemoteControl.SetValue(isRemote, out _); } private bool SetAutoTuning(out string reason, int time, params object[] param) { reason = string.Empty; if (param == null || param.Length == 0) { reason = $"invalid parameter"; return false; } bool.TryParse(param[0].ToString(), out bool isAutoSetAutoTuning); if (isAutoSetAutoTuning) { //_doCanWritePara.SetPulseValue(true, 2000); //_doStopAutoTunningMode.SetValue(false, out _); //_doStartAutoTunningMode.SetPulseValue(true, 2000); } else { //_doCanWritePara.SetPulseValue(true, 2000); //_doStartAutoTunningMode.SetValue(false, out _); //_doStopAutoTunningMode.SetPulseValue(true, 2000); } return true; } public override void Terminate() { base.Terminate(); } private void SetPID(float setpoint) { //_aoPID_P.FloatValue = (float)proportioning; //_aoPID_I.FloatValue = (float)integral; //_aoPID_D.FloatValue = (float)derivative; } public void SetStableParameters(string tableId) { if (SC.ContainsItem($"PM1.RecipeEditParameter.TempStabilizeTable.Table{tableId}.{InstallZone}.JudgmentTime")) { var scPath = $"PM1.RecipeEditParameter.TempStabilizeTable.Table{tableId}.{InstallZone}"; _stableJudgmentTime = (float)SC.GetValue($"{scPath}.JudgmentTime"); _stableMinValue = (float)SC.GetValue($"{scPath}.MinValue"); _stableMaxValue = (float)SC.GetValue($"{scPath}.MaxValue"); _stableJudgmentTimer.Start(0); } } public bool ResetWarningChecker() { _toleranceCheckerWarning.Reset(_warningJudgmentTime); return true; } public bool ResetAlarmChecker() { _toleranceCheckerAlarm.Reset(_alarmJudgmentTime); return true; } public override void Reset() { AlarmToleranceWarning?.Reset(); AlarmToleranceAlarm?.Reset(); _toleranceJudgmentDelayTimer?.Stop(); } public void ResetHeaterError() { _trigHeaterErrorSignalOn.RST = true; if (HeaterErrorAlarm != null) HeaterErrorAlarm.IsAcknowledged = true; } public void ResetHeaterStripBreak() { TrigHeaterStripBreakSignalOn.RST = true; if (HeaterStripBreakAlarm != null) HeaterStripBreakAlarm.IsAcknowledged = true; } private void MonitorTolerance() { if (IsHeaterStripBreak || TempSetPoint < 0.001 || _toleranceJudgmentDelayTimer.IsIdle() || _toleranceJudgmentDelayTimer.GetElapseTime() < _toleranceJudgmentDelayTime * 1000) { _toleranceCheckerWarning.RST = true; _toleranceCheckerAlarm.RST = true; return; } if (_alarmJudgmentRange != 0 && _alarmJudgmentTime > 0) { _toleranceCheckerAlarm.Monitor(DeviceData.FeedBack, DeviceData.RampSetPoint - Math.Abs(_alarmJudgmentRange), DeviceData.RampSetPoint + Math.Abs(_alarmJudgmentRange), _alarmJudgmentTime); } if (_warningJudgmentRange != 0 && _warningJudgmentTime > 0) { _toleranceCheckerWarning.Monitor(DeviceData.FeedBack, DeviceData.RampSetPoint - Math.Abs(_warningJudgmentRange), DeviceData.RampSetPoint + Math.Abs(_warningJudgmentRange), _warningJudgmentTime); } } public override bool CheckToleranceAlarm() { return _toleranceCheckerAlarm.Result; } public override bool CheckToleranceWarning() { return _toleranceCheckerWarning.Result; } public void SetToleranceAlarm() { AlarmToleranceAlarm.Description = $"{Display} temperature out of range {_alarmJudgmentRange} °C in {_alarmJudgmentTime:F0} seconds"; AlarmToleranceAlarm.Set(); } public void SetToleranceWarning() { AlarmToleranceWarning.Description = $"{Display} temperature out of range {_warningJudgmentRange} °C in {_warningJudgmentTime:F0} seconds"; AlarmToleranceWarning.Set(); } public void Ramp(double target, int time) { target = Math.Max(0, target); //target = Math.Min(Range, target); _rampInitValue = TempFeedback; //ramp 初始值取当前设定值,而非实际读取值.零漂问题 _rampTime = time; _rampTarget = target; _rampTimer.Start(_rampTime); _isStartRamp = true; } private void Ramping() { //只有修改了温度,才开始ramp,避免一开机温度设定值大于0的问题。 if (!_isStartRamp) return; if (_rampTimer.IsTimeout() || _rampTime == 0) { TempSetPoint = (float)_rampTarget; } else { TempSetPoint = (float)(_rampInitValue + (_rampTarget - _rampInitValue) * _rampTimer.GetElapseTime() / _rampTime); } } public void UpdateCalibrationTable() { if (_scCalibrationTable == null) return; if (_previousSetting == _scCalibrationTable.StringValue) return; _previousSetting = _scCalibrationTable.StringValue; if (string.IsNullOrEmpty(_previousSetting)) { _calibrationTable = new List(); return; } var table = new List>(); string[] items = _previousSetting.Split(';'); for (int i = 0; i < items.Length; i++) { string itemValue = items[i]; if (!string.IsNullOrEmpty(itemValue)) { string[] pairValue = itemValue.Split('#'); if (pairValue.Length == 2) { if (float.TryParse(pairValue[0], out float expectedValue) && float.TryParse(pairValue[1], out float realValue)) { table.Add(Tuple.Create(realValue, expectedValue)); } } } } table = table.OrderBy(x => x.Item1).ToList(); var calibrationTable = new List(); for (int i = 0; i < table.Count; i++) { if (((double)table[0].Item1) > Range) continue; if (i == 0 && table[0].Item1 > 0.001) { calibrationTable.Add(new CalibrationItem() { RawFrom = 0, CalibrationFrom = 0, RawTo = table[0].Item1, CalibrationTo = table[0].Item2, }); } if (i == table.Count - 1) { continue; } calibrationTable.Add(new CalibrationItem() { RawFrom = table[i].Item1, CalibrationFrom = table[i].Item2, RawTo = table[i + 1].Item1, CalibrationTo = table[i + 1].Item2, }); } _calibrationTable = calibrationTable; } private float CalibrationData(float value, bool output) { //default enable if (_scEnableCalibration != null && !_scEnableCalibration.BoolValue) return value; if (_scCalibrationTable == null || !_calibrationTable.Any()) return value; float ret = value > Range ? (float)Range : value; if (output) { var item = _calibrationTable.FirstOrDefault(x => x.RawFrom <= value && x.RawTo >= value); if (item == null) { item = _calibrationTable.Last(); if (!_isWarned) { EV.PostWarningLog(_uniqueName, $"No calibration map for {value}"); _isWarned = true; } } if (Math.Abs(item.RawTo - item.RawFrom) > 0.01) { var slope = Math.Abs((item.CalibrationTo - item.CalibrationFrom) / (item.RawTo - item.RawFrom)); ret = (ret - item.RawFrom) * slope + item.CalibrationFrom; } } else { var item = _calibrationTable.FirstOrDefault(x => x.CalibrationFrom <= value && x.CalibrationTo >= value); if (item == null) { item = _calibrationTable.Last(); if (!_isWarned) { EV.PostWarningLog(_uniqueName, $"No calibration map for {value}"); _isWarned = true; } } if (Math.Abs(item.CalibrationTo - item.CalibrationFrom) > 0.01) { var slope = Math.Abs((item.RawTo - item.RawFrom) / (item.CalibrationTo - item.CalibrationFrom)); ret = (ret - item.CalibrationFrom) * slope + item.RawFrom; } } if (ret < 0) return 0; if (ret >= float.MaxValue || ret > Range) ret = value; return ret; } private void SaveSetPoint(string temperature) { SC.SetItemValueFromString($"{_scRoot}.{Name}.SetPoint", temperature); } private void SaveRampRate(string ramping) { SC.SetItemValueFromString($"{_scRoot}.{Name}.RampRate", ramping); } public override void SetEnable(bool isEnable) { _doEnable?.SetValue(isEnable, out _); if (_aoEnableIn != null) { _aoEnableIn.FloatValue = isEnable ? 1 : 0; } } } }