using System; using System.Xml; using Aitex.Core.RT.Device; using Aitex.Core.RT.Event; using Aitex.Core.RT.IOCore; using Aitex.Core.RT.SCCore; using Aitex.Core.RT.Tolerance; using Aitex.Core.Util; using MECF.Framework.Common.Event; namespace MECF.Framework.Common.Aitex.Core.RT.Device { /// /// 具有SetPoint、FeedBack误差实时检测功能的设备基类。 /// 注意:在子类中注册FeedbackGetter、SetPointGetter、RampTimerGetter /// public class ErrorDetectableBaseDevice : BaseDevice, IDevice { #region Variable private readonly R_TRIG _alarmTrigger; /// /// 是否启用误差检测 /// private readonly bool _isEnableErrDetection; /// /// 误差报警超限阈值 /// private readonly double _alarmRange; /// /// 误差报警超限持续时间 /// private readonly double _alarmTime; /// /// 误差警告超限阈值 /// private readonly double _warningRange; /// /// 误差警告超限持续时间 /// private readonly double _warningTime; protected readonly DIAccessor DiAlarm; protected readonly string AlarmText; /// /// 误差超限警告检查器 /// protected readonly ToleranceChecker ErrWarningChecker; /// /// 误差超限报警检查器 /// protected readonly ToleranceChecker ErrAlarmChecker; private readonly AlarmEventItem _alarmEvent; private readonly AlarmEventItem _warningEvent; #endregion #region Constructors public ErrorDetectableBaseDevice(string module, XmlElement node, string ioModule = "") { var attrModule = node.GetAttribute("module"); Module = string.IsNullOrEmpty(attrModule) ? module : attrModule; Unit = node.GetAttribute("unit"); Name = node.GetAttribute("id"); Display = node.GetAttribute("display"); DeviceID = node.GetAttribute("schematicId"); // 获取diAlarm DiAlarm = ParseDiNode("diAlarm", node, ioModule); // 获取Alarm Text AlarmText = node.GetAttribute("AlarmText"); var scBasePath = node.GetAttribute("scBasePath"); scBasePath = string.IsNullOrEmpty(scBasePath) ? $"{Module}.{Name}" : scBasePath.Replace("{module}", Module); ScBasePath = scBasePath; _isEnableErrDetection = ParseScNode("scEnableAlarm", node, ioModule, $"{scBasePath}.{Display}.EnableAlarm")?.BoolValue ?? false; _alarmRange = ParseScNode("scAlarmRange", node, ioModule, $"{scBasePath}.AlarmRange")?.DoubleValue ?? double.NaN; _alarmTime = ParseScNode("scAlarmTime", node, ioModule, $"{scBasePath}.AlarmTime")?.IntValue ?? int.MinValue; _warningRange = SC.GetConfigItem($"{scBasePath}.WarningRange")?.DoubleValue ?? double.NaN; _warningTime = SC.GetConfigItem($"{scBasePath}.WarningTime")?.IntValue ?? int.MinValue; _alarmTrigger = new R_TRIG(); ErrWarningChecker = new ToleranceChecker(); ErrAlarmChecker = new ToleranceChecker(); _warningEvent = SubscribeAlarm($"{Module}.{Display}.ToleranceWarning", "", ResetWarningChecker, EventLevel.Warning); _alarmEvent = SubscribeAlarm($"{Module}.{Display}.ToleranceAlarm", "", ResetAlarmChecker); } #endregion #region Properties protected string Unit { get; set; } #endregion #region Methods private bool ResetWarningChecker() { ErrWarningChecker.Reset(_warningTime); return true; } private bool ResetAlarmChecker() { ErrAlarmChecker.Reset(_alarmTime); return true; } /// /// 监测设置值和反馈值误差 /// public virtual void MonitorSpFbError(bool allowErrorCheck, double setPoint, double feedback) { _alarmTrigger.CLK = DiAlarm != null && DiAlarm.Value; if (_alarmTrigger.Q) { EV.PostAlarmLog(Module, AlarmText); } if (!_isEnableErrDetection || !allowErrorCheck) { ErrWarningChecker.RST = true; ErrAlarmChecker.RST = true; return; } // Out-of-rang Alarm detection var alarmLow = (setPoint * Math.Abs(100 - _alarmRange) / 100); var alarmHigh = (setPoint * Math.Abs(100 + _alarmRange) / 100); ErrAlarmChecker.Monitor(feedback, alarmLow, alarmHigh, _alarmTime); if (ErrAlarmChecker.Trig) { _alarmEvent.Description = $"{Display} feedback ({feedback:F1}{Unit}) out of range {alarmLow} - {alarmHigh} {Unit} in {_alarmTime:F0} seconds"; _alarmEvent.Set(); } // 如果报Alarm,不再检查Warning。 if (_alarmEvent.IsTriggered) return; // Out-of-rang warning detection var warnLow = (setPoint * Math.Abs(100 - _warningRange) / 100); var warnHigh = (setPoint * Math.Abs(100 + _warningRange) / 100); ErrWarningChecker.Monitor(feedback, warnLow, warnHigh, _warningTime); if (ErrWarningChecker.Trig) { _warningEvent.Description = $"{Display} feedback ({feedback:F1}{Unit}) out of range {warnLow} - {warnHigh} {Unit} in {_warningTime:F0} seconds"; _warningEvent.Set(); } } public virtual bool Initialize() { return true; } public virtual void Monitor() { } public virtual void Terminate() { } public virtual void Reset() { _alarmTrigger.RST = true; ErrAlarmChecker.Reset(_alarmTime); ErrWarningChecker.Reset(_warningTime); _warningEvent.Reset(); _alarmEvent.Reset(); } #endregion } }