Sic.Framework/MECF.Framework.RT.Equipment.../Devices/IoSensorAnalog.cs

258 lines
9.2 KiB
C#
Raw Normal View History

using System;
using System.Diagnostics;
using System.Xml;
using Aitex.Core.Common.DeviceData;
using Aitex.Core.RT.DataCenter;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.IOCore;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.Tolerance;
using MECF.Framework.Common.Event;
using MECF.Framework.Common.SicMath;
namespace Aitex.Core.RT.Device.Devices
{
public class IoSensorAnalog : BaseDevice, IDevice
{
#region Variables
private readonly AIAccessor _ai;
private readonly AOAccessor _ao;
private readonly DOAccessor _doWarningLow;
private readonly DOAccessor _doWarningHigh;
private readonly DOAccessor _doAlarmLow;
private readonly DOAccessor _doAlarmHigh;
private readonly TimeDomainArithmeticMeanFilter _tdamFilter;
private readonly string _scWarningLow;
private readonly string _scWarningHigh;
private readonly string _scAlarmLow;
private readonly string _scAlarmHigh;
private readonly string _scFilterDuration;
private readonly int _warningDelaySec;
private readonly int _alarmDelaySec;
protected double _warningLow;
protected double _warningHigh;
protected double _alarmLow;
protected double _alarmHigh;
/// <summary>
/// 误差超限警告检查器
/// </summary>
protected readonly ToleranceChecker _warningChecker;
/// <summary>
/// 误差超限报警检查器
/// </summary>
protected readonly ToleranceChecker _alarmChecker;
private readonly AlarmEventItem _alarmEvent;
private readonly AlarmEventItem _warningEvent;
#endregion
/// <summary>
/// 获取Sensor实时反馈值。
/// <para>注意如果绑定的AI或者AO为空返回<see cref="Double.NaN"/></para>
/// </summary>
public double Value
{
get
{
if (_ai != null)
return _ai.FloatValue;
if (_ao != null)
return _ao.FloatValue;
return double.NaN;
}
}
private AITSensorAnalogData DeviceData
{
get
{
var data = new AITSensorAnalogData()
{
DeviceName = Name,
DeviceSchematicId = DeviceID,
DisplayName = Display,
WarningLimitLow = _warningLow,
WarningLimitHigh = _warningHigh,
AlarmLimitLow = _alarmLow,
AlarmLimitHigh = _alarmHigh,
Value = Value,
IsWarning = _warningEvent.IsTriggered,
IsAlarm = _alarmEvent.IsTriggered
};
return data;
}
}
public IoSensorAnalog(string module, XmlElement node, string ioModule = "") : base(module, node, ioModule)
{
_scWarningLow = node.GetAttribute("scWarningLow");
_scWarningHigh = node.GetAttribute("scWarningHigh");
_scAlarmLow = node.GetAttribute("scAlarmLow");
_scAlarmHigh = node.GetAttribute("scAlarmHigh");
_scFilterDuration = node.GetAttribute("scFilterDuration");
_ai = ParseAiNode("ai", node, ioModule);
_ao = ParseAoNode("ao", node, ioModule);
_doWarningLow = ParseDoNode("doWarningLow", node, ioModule);
_doWarningHigh = ParseDoNode("doWarningHigh", node, ioModule);
_doAlarmLow = ParseDoNode("doAlarmLow", node, ioModule);
_doAlarmHigh = ParseDoNode("doAlarmHigh", node, ioModule);
// AI和AO不能同时配置
Debug.Assert((_ai != null && _ao == null) || (_ai == null && _ao != null), "Incorrect configuration.");
_warningLow = ParseScNode("", node, ioModule, $"{ScBasePath}.{_scWarningLow}")?.DoubleValue ??
double.MinValue;
_warningHigh = ParseScNode("", node, ioModule, $"{ScBasePath}.{_scWarningHigh}")?.DoubleValue ??
double.MaxValue;
_alarmLow = ParseScNode("", node, ioModule, $"{ScBasePath}.{_scAlarmLow}")?.DoubleValue ??
double.MinValue;
_alarmHigh = ParseScNode("", node, ioModule, $"{ScBasePath}.{_scAlarmHigh}")?.DoubleValue ??
double.MaxValue;
_warningDelaySec = ParseScNode("", node, ioModule, $"{ScBasePath}.WarningDelay")?.IntValue ??
0;
_alarmDelaySec = ParseScNode("", node, ioModule, $"{ScBasePath}.AlarmDelay")?.IntValue ??
0;
_warningChecker = new ToleranceChecker();
_alarmChecker = new ToleranceChecker();
_warningEvent = SubscribeAlarm($"{Module}.{Display}.ToleranceWarning", "", ResetWarningChecker,
EventLevel.Warning);
_alarmEvent = SubscribeAlarm($"{Module}.{Display}.ToleranceAlarm", "", ResetAlarmChecker);
// 初始化滤波器
var filterDurationSec = ParseScNode("", node, ioModule, $"{ScBasePath}.{_scFilterDuration}")?.IntValue ??
0;
_tdamFilter = new TimeDomainArithmeticMeanFilter(filterDurationSec);
}
public virtual bool Initialize()
{
DATA.Subscribe($"{Module}.{Name}.DeviceData", () => DeviceData);
DATA.Subscribe($"{Module}.{Name}.Value", () => Value);
return true;
}
public virtual void Terminate()
{
}
public virtual void Monitor()
{
try
{
// 对输入量滤波
_tdamFilter.Feed(Value);
var filtered = _tdamFilter.Filter();
_alarmChecker.Monitor(filtered, _alarmLow, _alarmHigh, _alarmDelaySec);
if (_alarmChecker.Trig)
{
// 根据条件设定指定的DO
if (filtered < _alarmLow)
{
_alarmEvent.Description =
$"{Display} feedback ({filtered:F1}{Unit}) is below {_alarmLow:F1} in {_alarmDelaySec:F0} seconds";
_doAlarmLow?.SetValue(true, out _);
_doAlarmHigh?.SetValue(false, out _);
}
else if (filtered > _alarmHigh)
{
_alarmEvent.Description =
$"{Display} feedback ({filtered:F1}{Unit}) is above {_alarmHigh:F1} in {_alarmDelaySec:F0} seconds";
_doAlarmLow?.SetValue(false, out _);
_doAlarmHigh?.SetValue(true, out _);
}
_alarmEvent.Set();
}
// 如果报Alarm不再检查Warning。
if (_alarmEvent.IsTriggered)
return;
// Out-of-rang warning detection
_warningChecker.Monitor(filtered, _warningLow, _warningHigh, _warningDelaySec);
if (_warningChecker.Trig)
{
// 根据条件设定指定的DO
if (filtered < _warningLow)
{
_warningEvent.Description =
$"{Display} feedback ({filtered:F1}{Unit}) is below {_warningLow:F1} in {_warningDelaySec:F0} seconds";
_doWarningLow?.SetValue(true, out _);
_doWarningHigh?.SetValue(false, out _);
}
else if (filtered > _warningHigh)
{
_warningEvent.Description =
$"{Display} feedback ({filtered:F1}{Unit}) is above {_warningHigh:F1} in {_warningDelaySec:F0} seconds";
_doWarningLow?.SetValue(false, out _);
_doWarningHigh?.SetValue(true, out _);
}
_warningEvent.Set();
}
}
catch (Exception ex)
{
LOG.Write(ex);
}
}
public virtual void Reset()
{
_warningChecker.Reset(_warningDelaySec);
_alarmChecker.Reset(_alarmDelaySec);
_warningEvent.Reset();
_alarmEvent.Reset();
_doAlarmLow?.SetValue(false, out _);
_doAlarmHigh?.SetValue(false, out _);
}
#region Private Methods
private bool ResetWarningChecker()
{
_warningChecker.Reset(_warningDelaySec);
_doWarningLow?.SetValue(false, out _);
_doWarningHigh?.SetValue(false, out _);
return true;
}
private bool ResetAlarmChecker()
{
_alarmChecker.Reset(_alarmDelaySec);
_doAlarmLow?.SetValue(false, out _);
_doAlarmHigh?.SetValue(false, out _);
return true;
}
#endregion
}
}