263 lines
14 KiB
C#
263 lines
14 KiB
C#
///
|
|
/// Copyright (c) 2017-2021 Sensus Slovensko a.s.
|
|
///
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using log4net;
|
|
using Config.Entities;
|
|
using Results.Entities;
|
|
using TBF.BenchControl.Sequences;
|
|
|
|
namespace TBF.BenchControl.Various.ErrorFlags
|
|
{
|
|
public class Errors : ComponentBase, GenericDevices.IErrorFlags
|
|
{
|
|
private static readonly ILog log = LogManager.GetLogger(typeof(Errors));
|
|
public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); }
|
|
|
|
readonly ErrorsCfg errorsCfg;
|
|
|
|
/// <summary>
|
|
/// Ger error flags for a test
|
|
/// </summary>
|
|
/// <param name="testRslt">A valid test result</param>
|
|
/// <param name="diverter">true = diverter was used (times apply)</param>
|
|
/// <param name="startStopValve">true = start/stop valve was used (times apply)</param>
|
|
/// <param name="switchTimeStart">Diverter or valve switch time in s on test start</param>
|
|
/// <param name="switchTimeEnd">Diverter or valve switch time in s on test end</param>
|
|
/// <returns>Error flags</returns>
|
|
public long GetErrorFlags(TestRslt testRslt, bool diverter, bool startStopValve, float switchTimeStart, float switchTimeEnd, out long infoFlags, out bool stopCycle)
|
|
{
|
|
/// Any E# is 'true' on error, 'false' when OK
|
|
|
|
/// Average flow
|
|
bool E1 = (testRslt.FlowVolume < testRslt.Qfrom()) || (testRslt.FlowVolume > testRslt.Qto());
|
|
|
|
/// Max. and min. up and down water temperature
|
|
bool E2 = ProcessData.TempUpStat.Min < testRslt.TempLimLo()
|
|
|| ProcessData.TempUpStat.Max > testRslt.TempLimHi()
|
|
|| ProcessData.TempDownStat.Min < testRslt.TempLimLo()
|
|
|| ProcessData.TempDownStat.Max > testRslt.TempLimHi();
|
|
|
|
/// Max. flow deviation
|
|
bool E3 = ProcessData.RefFlowStat.Min < ProcessData.RefFlowStat.Average * (1.0f - errorsCfg.TestParams.Delta_Q_pct / 100.0f)
|
|
|| ProcessData.RefFlowStat.Max > ProcessData.RefFlowStat.Average * (1.0f + errorsCfg.TestParams.Delta_Q_pct / 100.0f);
|
|
|
|
/// Max. up and down water temperature deviation
|
|
bool E4 = ProcessData.TempUpStat.Min < ProcessData.TempUpStat.Average - errorsCfg.TestParams.Delta_T
|
|
|| ProcessData.TempUpStat.Max > ProcessData.TempUpStat.Average + errorsCfg.TestParams.Delta_T
|
|
|| ProcessData.TempDownStat.Min < ProcessData.TempDownStat.Average - errorsCfg.TestParams.Delta_T
|
|
|| ProcessData.TempDownStat.Max > ProcessData.TempDownStat.Average + errorsCfg.TestParams.Delta_T;
|
|
|
|
/// Max. absolute value of up and down water temperature difference
|
|
bool E5 = Math.Abs(ProcessData.TempUpStat.Average - ProcessData.TempDownStat.Average) > errorsCfg.TestParams.Delta_Tup_Tdn;
|
|
|
|
bool E6 = false;
|
|
|
|
/// Test time (min)
|
|
bool E7 = testRslt.TestTime < errorsCfg.TestParams.TestTime_min;
|
|
|
|
/// Test time (max)
|
|
bool E8 = testRslt.TestTime > errorsCfg.TestParams.TestTime_max;
|
|
|
|
bool E9 = false;
|
|
bool E10 = false;
|
|
if (diverter)
|
|
{
|
|
E9 = (Math.Abs(switchTimeStart - switchTimeEnd) > errorsCfg.TestParams.Coef_E9 * (switchTimeStart + switchTimeEnd) + errorsCfg.TestParams.Offset_E9);
|
|
E10 = ((switchTimeStart + switchTimeEnd) > errorsCfg.TestParams.Coef_E10 * testRslt.TestTime);
|
|
}
|
|
|
|
bool E11 = false;
|
|
bool E12 = false;
|
|
if (startStopValve)
|
|
{
|
|
E11 = ((switchTimeStart + switchTimeEnd) > errorsCfg.TestParams.Coef_E11 * testRslt.TestTime);
|
|
E12 = (Math.Abs(switchTimeStart - switchTimeEnd) > errorsCfg.TestParams.Coef_E12 * (switchTimeStart + switchTimeEnd) + errorsCfg.TestParams.Offset_E12);
|
|
}
|
|
|
|
/// Ambient temperature
|
|
bool E13 = ProcessData.AmbTempStat.Min < errorsCfg.TestParams.AmbTemp_min
|
|
|| ProcessData.AmbTempStat.Max > errorsCfg.TestParams.AmbTemp_max;
|
|
|
|
/// Water pressure
|
|
bool E14 = ProcessData.PressUpStat.Min < errorsCfg.TestParams.Pressure_min
|
|
|| ProcessData.PressUpStat.Max > errorsCfg.TestParams.Pressure_max
|
|
|| ProcessData.PressDownStat.Min < errorsCfg.TestParams.Pressure_min
|
|
|| ProcessData.PressDownStat.Max > errorsCfg.TestParams.Pressure_max;
|
|
|
|
/// Max. and min. flow
|
|
double rectifiedFlowMin = (testRslt.FlowMean == 0) ? testRslt.FlowMin : testRslt.FlowMin * testRslt.FlowVolume / testRslt.FlowMean;
|
|
double rectifiedFlowMax = (testRslt.FlowMean == 0) ? testRslt.FlowMax : testRslt.FlowMax * testRslt.FlowVolume / testRslt.FlowMean;
|
|
bool E21 = rectifiedFlowMin < testRslt.Qfrom() || rectifiedFlowMax > testRslt.Qto();
|
|
|
|
/// Electrical conductivity of water
|
|
bool E36 = ProcessData.ConductStat.Min < errorsCfg.TestParams.Conductivity_min
|
|
|| ProcessData.ConductStat.Max > errorsCfg.TestParams.Conductivity_max;
|
|
|
|
const sbyte INFO = (sbyte)ErrorFlagsMode.Info;
|
|
const sbyte ON = (sbyte)ErrorFlagsMode.On;
|
|
const sbyte STOP = (sbyte)ErrorFlagsMode.Stop;
|
|
|
|
long errorFlags = 0;
|
|
if (E1 && (errorsCfg.TestParams.E1 == ON || errorsCfg.TestParams.E1 == STOP)) errorFlags |= (long)ErrorFlagMask.E1;
|
|
if (E2 && (errorsCfg.TestParams.E2 == ON || errorsCfg.TestParams.E2 == STOP)) errorFlags |= (long)ErrorFlagMask.E2;
|
|
if (E3 && (errorsCfg.TestParams.E3 == ON || errorsCfg.TestParams.E3 == STOP)) errorFlags |= (long)ErrorFlagMask.E3;
|
|
if (E4 && (errorsCfg.TestParams.E4 == ON || errorsCfg.TestParams.E4 == STOP)) errorFlags |= (long)ErrorFlagMask.E4;
|
|
if (E5 && (errorsCfg.TestParams.E5 == ON || errorsCfg.TestParams.E5 == STOP)) errorFlags |= (long)ErrorFlagMask.E5;
|
|
if (E6 && (errorsCfg.TestParams.E6 == ON || errorsCfg.TestParams.E6 == STOP)) errorFlags |= (long)ErrorFlagMask.E6;
|
|
if (E7 && (errorsCfg.TestParams.E7 == ON || errorsCfg.TestParams.E7 == STOP)) errorFlags |= (long)ErrorFlagMask.E7;
|
|
if (E8 && (errorsCfg.TestParams.E8 == ON || errorsCfg.TestParams.E8 == STOP)) errorFlags |= (long)ErrorFlagMask.E8;
|
|
if (E9 && (errorsCfg.TestParams.E9 == ON || errorsCfg.TestParams.E9 == STOP)) errorFlags |= (long)ErrorFlagMask.E9;
|
|
if (E10 && (errorsCfg.TestParams.E10 == ON || errorsCfg.TestParams.E10 == STOP)) errorFlags |= (long)ErrorFlagMask.E10;
|
|
if (E11 && (errorsCfg.TestParams.E11 == ON || errorsCfg.TestParams.E11 == STOP)) errorFlags |= (long)ErrorFlagMask.E11;
|
|
if (E12 && (errorsCfg.TestParams.E12 == ON || errorsCfg.TestParams.E12 == STOP)) errorFlags |= (long)ErrorFlagMask.E12;
|
|
if (E13 && (errorsCfg.TestParams.E13 == ON || errorsCfg.TestParams.E13 == STOP)) errorFlags |= (long)ErrorFlagMask.E13;
|
|
if (E14 && (errorsCfg.TestParams.E14 == ON || errorsCfg.TestParams.E14 == STOP)) errorFlags |= (long)ErrorFlagMask.E14;
|
|
/// E15, E16, E17, E18, E19, E20 skipped
|
|
if (E21 && (errorsCfg.TestParams.E21 == ON || errorsCfg.TestParams.E21 == STOP)) errorFlags |= (long)ErrorFlagMask.E21;
|
|
if (E36 && (errorsCfg.TestParams.E36 == ON || errorsCfg.TestParams.E36 == STOP)) errorFlags |= (long)ErrorFlagMask.E36;
|
|
|
|
long _infoFlags = 0;
|
|
if (E1 && (errorsCfg.TestParams.E1 == INFO)) _infoFlags |= (long)ErrorFlagMask.E1;
|
|
if (E2 && (errorsCfg.TestParams.E2 == INFO)) _infoFlags |= (long)ErrorFlagMask.E2;
|
|
if (E3 && (errorsCfg.TestParams.E3 == INFO)) _infoFlags |= (long)ErrorFlagMask.E3;
|
|
if (E4 && (errorsCfg.TestParams.E4 == INFO)) _infoFlags |= (long)ErrorFlagMask.E4;
|
|
if (E5 && (errorsCfg.TestParams.E5 == INFO)) _infoFlags |= (long)ErrorFlagMask.E5;
|
|
if (E6 && (errorsCfg.TestParams.E6 == INFO)) _infoFlags |= (long)ErrorFlagMask.E6;
|
|
if (E7 && (errorsCfg.TestParams.E7 == INFO)) _infoFlags |= (long)ErrorFlagMask.E7;
|
|
if (E8 && (errorsCfg.TestParams.E8 == INFO)) _infoFlags |= (long)ErrorFlagMask.E8;
|
|
if (E9 && (errorsCfg.TestParams.E9 == INFO)) _infoFlags |= (long)ErrorFlagMask.E9;
|
|
if (E10 && (errorsCfg.TestParams.E10 == INFO)) _infoFlags |= (long)ErrorFlagMask.E10;
|
|
if (E11 && (errorsCfg.TestParams.E11 == INFO)) _infoFlags |= (long)ErrorFlagMask.E11;
|
|
if (E12 && (errorsCfg.TestParams.E12 == INFO)) _infoFlags |= (long)ErrorFlagMask.E12;
|
|
if (E13 && (errorsCfg.TestParams.E13 == INFO)) _infoFlags |= (long)ErrorFlagMask.E13;
|
|
if (E14 && (errorsCfg.TestParams.E14 == INFO)) _infoFlags |= (long)ErrorFlagMask.E14;
|
|
/// E15, E16, E17, E18, E19, E20 skipped
|
|
if (E21 && (errorsCfg.TestParams.E21 == INFO)) _infoFlags |= (long)ErrorFlagMask.E21;
|
|
if (E36 && (errorsCfg.TestParams.E36 == INFO)) _infoFlags |= (long)ErrorFlagMask.E36;
|
|
|
|
/// E15, E16, E17, E18, E19, E20 skipped
|
|
stopCycle = testRslt.TestData.Evaluate && ((E1 && errorsCfg.TestParams.E1 == STOP) ||
|
|
(E2 && errorsCfg.TestParams.E2 == STOP) ||
|
|
(E3 && errorsCfg.TestParams.E3 == STOP) ||
|
|
(E4 && errorsCfg.TestParams.E4 == STOP) ||
|
|
(E5 && errorsCfg.TestParams.E5 == STOP) ||
|
|
(E6 && errorsCfg.TestParams.E6 == STOP) ||
|
|
(E7 && errorsCfg.TestParams.E7 == STOP) ||
|
|
(E8 && errorsCfg.TestParams.E8 == STOP) ||
|
|
(E9 && errorsCfg.TestParams.E9 == STOP) ||
|
|
(E10 && errorsCfg.TestParams.E10 == STOP) ||
|
|
(E11 && errorsCfg.TestParams.E11 == STOP) ||
|
|
(E12 && errorsCfg.TestParams.E12 == STOP) ||
|
|
(E13 && errorsCfg.TestParams.E13 == STOP) ||
|
|
(E14 && errorsCfg.TestParams.E14 == STOP) ||
|
|
(E21 && errorsCfg.TestParams.E21 == STOP) ||
|
|
(E36 && errorsCfg.TestParams.E36 == STOP));
|
|
|
|
infoFlags = _infoFlags;
|
|
return errorFlags;
|
|
}
|
|
|
|
|
|
MeterTestRslt GetMtrTstRsltFromNames(IList<MeterTestRslt> meterTestRslts, string testNames)
|
|
{
|
|
if (string.IsNullOrEmpty(testNames)) return null;
|
|
|
|
string[] names = testNames.Split(new char[] { ';' });
|
|
|
|
foreach (var nm in names)
|
|
{
|
|
foreach (var mtr in meterTestRslts) if (mtr.Name() == nm) return mtr;
|
|
}
|
|
|
|
return null; /// No matching MeterTestRslt found
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get water meter error flags E15 and E16 (evaluated from three meter test results)
|
|
/// </summary>
|
|
/// <param name="meterTestRslts">Meter test results</param>
|
|
/// <returns>Error flags</returns>
|
|
public long GetWMtrErrorFlags(IList<MeterTestRslt> meterTestRslts, out long infoIndicators)
|
|
{
|
|
long _infoIndicators = 0;
|
|
long errorIndicators = 0;
|
|
|
|
MeterTestRslt mtrQ3 = GetMtrTstRsltFromNames(meterTestRslts, errorsCfg.Q3Names);
|
|
MeterTestRslt mtrQ2 = GetMtrTstRsltFromNames(meterTestRslts, errorsCfg.Q2Names);
|
|
MeterTestRslt mtrQ1 = GetMtrTstRsltFromNames(meterTestRslts, errorsCfg.Q1Names);
|
|
|
|
if (mtrQ3 == null || !mtrQ3.TestDone || mtrQ2 == null || !mtrQ2.TestDone || mtrQ1 == null || !mtrQ1.TestDone)
|
|
{
|
|
/// No error indicator;
|
|
}
|
|
else if (((mtrQ3.Error > mtrQ3.ErrLimHi() / 2) && (mtrQ2.Error > mtrQ2.ErrLimHi() / 2) && (mtrQ1.Error > mtrQ1.ErrLimHi() / 2)) ||
|
|
((mtrQ3.Error < mtrQ3.ErrLimLo() / 2) && (mtrQ2.Error < mtrQ2.ErrLimLo() / 2) && (mtrQ1.Error < mtrQ1.ErrLimLo() / 2)))
|
|
{
|
|
if (errorsCfg.TestParams.E15 == (sbyte)ErrorFlagsMode.Info)
|
|
{
|
|
_infoIndicators |= (long)ErrorFlagMask.E15; /// Set E15
|
|
}
|
|
if (errorsCfg.TestParams.E15 == (sbyte)ErrorFlagsMode.On || errorsCfg.TestParams.E15 == (sbyte)ErrorFlagsMode.Stop)
|
|
{
|
|
errorIndicators |= (long)ErrorFlagMask.E15; /// Set E15
|
|
}
|
|
}
|
|
|
|
foreach (var mtr in meterTestRslts)
|
|
{
|
|
errorIndicators |= mtr.ErrorIndicators; /// Set any error flag from mtr.ErrorIndicators (iPerl)
|
|
}
|
|
|
|
infoIndicators = _infoIndicators;
|
|
return errorIndicators;
|
|
}
|
|
|
|
|
|
public Errors() { }
|
|
|
|
public Errors(Generic.IComponentCfg cfg, IList<Generic.IComponent> components)
|
|
: base(cfg)
|
|
{
|
|
errorsCfg = cfg as ErrorsCfg;
|
|
}
|
|
|
|
public override void Initialize()
|
|
{
|
|
log.FatalFormat("{0} initialized: {1}", Name, this);
|
|
}
|
|
|
|
|
|
#region Configuration Change Handling
|
|
|
|
public static void OnCfgChange(object sender, CfgChangeArgs args)
|
|
{
|
|
if (CfgChangeHandler == null) return;
|
|
try { CfgChangeHandler(sender, args); }
|
|
catch (Exception e) { log.Error("CfgChangeHandler(...) failed", e); }
|
|
}
|
|
|
|
public static event EventHandler<CfgChangeArgs> CfgChangeHandler;
|
|
|
|
public override void StartChangeHandler()
|
|
{
|
|
CfgChangeHandler += delegate(object sender, CfgChangeArgs args)
|
|
{
|
|
ErrorsCfg tmpcfg = args.Cfg as ErrorsCfg;
|
|
if (tmpcfg != null && tmpcfg.Name.Equals(Name))
|
|
{
|
|
if (args.Command == CfgChangeCmd.CfgChange)
|
|
{
|
|
errorsCfg.Q3Names = tmpcfg.Q3Names;
|
|
errorsCfg.Q2Names = tmpcfg.Q2Names;
|
|
errorsCfg.Q1Names = tmpcfg.Q1Names;
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
#endregion Configuration Change Handling
|
|
}
|
|
}
|