Sic01/Modules/SicPM/Devices/Base/ErrorDetectableIoDeviceBase.cs

211 lines
6.5 KiB
C#
Raw Permalink 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 System;
using System.Diagnostics;
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 SicPM.Devices
{
/// <summary>
/// 具有SetPoint、FeedBack误差实时检测功能的设备基类。
/// <para>注意在子类中注册FeedbackGetter、SetPointGetter、RampTimerGetter</para>
/// </summary>
public class ErrorDetectableIoDeviceBase : BaseDevice, IDevice
{
#region Variable
private readonly R_TRIG _alarmTrigger;
/// <summary>
/// 是否启用误差检测
/// </summary>
private readonly bool _isEnableErrDetection;
/// <summary>
/// 误差报警超限阈值
/// </summary>
private readonly double _alarmRange;
/// <summary>
/// 误差报警超限持续时间
/// </summary>
private readonly double _alarmTime;
/// <summary>
/// 误差警告超限阈值
/// </summary>
private readonly double _warningRange;
/// <summary>
/// 误差警告超限持续时间
/// </summary>
private readonly double _warningTime;
protected readonly DIAccessor DiAlarm;
protected readonly string AlarmText;
/// <summary>
/// 误差超限警告检查器
/// </summary>
protected readonly ToleranceChecker ErrWarningChecker;
/// <summary>
/// 误差超限报警检查器
/// </summary>
protected readonly ToleranceChecker ErrAlarmChecker;
private readonly AlarmEventItem _alarmEvent;
private readonly AlarmEventItem _warningEvent;
#endregion
#region Constructors
public ErrorDetectableIoDeviceBase(string module, XmlElement node, string ioModule = "")
{
Unit = node.GetAttribute("unit");
var attrModule = node.GetAttribute("module");
Module = string.IsNullOrEmpty(attrModule) ? module : attrModule;
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}.{Display}.AlarmRange")?.DoubleValue ??
double.NaN;
_alarmTime = ParseScNode("scAlarmTime", node, ioModule, $"{scBasePath}.{Display}.AlarmTime")?.IntValue ??
int.MinValue;
_warningRange = SC.GetConfigItem($"{scBasePath}.{Display}.WarningRange")?.DoubleValue ?? double.NaN;
_warningTime = SC.GetConfigItem($"{scBasePath}.{Display}.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;
}
/// <summary>
/// 监测设置值和反馈值误差
/// </summary>
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
}
}