Q2 correction for standard process and MakeQ2CorrectionFrom(...) modified to satisfy MID, Q2 correction done when OoR.

This commit is contained in:
Milan Hanajik 2023-08-04 14:43:30 +02:00
parent e1bfa71310
commit 6fd67cdf08
4 changed files with 127 additions and 105 deletions

View File

@ -174,7 +174,7 @@ namespace Results
return Batch.GetTestRslt(name, part);
}
public MeterTestRslt GetMeterTestRslt(string name, int wmNr0, CompoundMeterId meterId)
public MeterTestRslt GetMeterTestRslt(string name, int wmNr0, CompoundMeterId meterId = CompoundMeterId.Single)
{
if (Batch.WaterMeters != null && Batch.WaterMeters.Count > wmNr0 && !Batch.WaterMeters[wmNr0].Disabled)
{

View File

@ -340,7 +340,7 @@ namespace Results.Entities
return GetMeterTestRslt(testName, CompoundMeterId.SingleOrCompound);
}
public virtual MeterTestRslt GetMeterTestRslt(string testName, CompoundMeterId meterId)
public virtual MeterTestRslt GetMeterTestRslt(string testName, CompoundMeterId meterId = CompoundMeterId.Single)
{
if (string.IsNullOrEmpty(testName)) return null;
if (Disabled) return null;

View File

@ -1954,7 +1954,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
var args = string.IsNullOrEmpty(restOfLine) ? new string[0] : restOfLine.Split(new char[] { ' ' });
Results.Entities.MeterTestRslt q2adjResult; /// The only test or the 1st test (the test in R-L direction)
Results.Entities.TestData q2adjTestData;
Results.Entities.TestData q2adjTestData; /// The 2nd test in L-R direction in case tests in both directions are done
///
if (args.Length == 0)
{
@ -2063,30 +2063,6 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
double errLimitLo = test.ErrLimLo + test.Uncertainty;
double errLimitHi = test.ErrLimHi - test.Uncertainty;
///
if (q2adjResult.Error < errLimitLo || errLimitHi < q2adjResult.Error ||
(q2adjResult2 != null && (q2adjResult2.Error < errLimitLo || errLimitHi < q2adjResult2.Error)))
{
/// At least one of Q2 errors is out of range for Q2 correction
log.WarnFormat("OoR => no Q2 correction: Pos={0}, PCB#={1}, ***Q2_RL err={2}%***, ***Q2_LR err={3}%***, [Lo={4}%, Hi={5}%]",
ihead.Name,
ihead.SerialNr,
q2adjResult.Error.ToString("F2"),
q2adjResult2 != null ? q2adjResult2.Error.ToString("F2") : string.Empty,
errLimitLo.ToString("F2"),
errLimitHi.ToString("F2"));
resultStr = string.Format("Q2 error is out of range => no Q2 correction");
rfidDataLogger.InfoFormat("{0}({1}): Q2 error ({2},{3}) is out of range ({4}..{5}) => Failed",
ihead.Name,
ihead.SerialNr,
q2adjResult.Error.ToString("F2"),
q2adjResult2 != null ? q2adjResult2.Error.ToString("F2") : string.Empty,
errLimitLo.ToString("F2"),
errLimitHi.ToString("F2"));
return CommErr.Q2OutOfRange;
}
///
/// Calculate Q2 correction factor(s) from an error measured at Q2
@ -2113,37 +2089,69 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
///
if (q2CorrType == Q2CorrType.Standard ||
q2CorrType == Q2CorrType.Standard_incl_05 ||
q2CorrType == Q2CorrType.Standard_plus_incl_05 ||
q2CorrType == Q2CorrType.UpdateBothQ2FactorsTestRLDir)
q2CorrType == Q2CorrType.Standard_plus_incl_05)
{
///
/// Standard process
/// Standard process (RL)
/// No 2nd Q2 test, MakeQ2CorrectedFrom(...) is used to calculate Q2 error
/// Do not forget to modify iPerlCommunicationSeq.MakeQ2CorrectedFrom(...)
///
if (q2CorrType == Q2CorrType.Standard && Math.Abs(q2adjResult.Error) <= 0.5)
{
resultStr = string.Format("Q2 correction = 0 (writing bypassed)");
return CommErr.None;
}
q2CorrRL = (q2CorrType == Q2CorrType.Standard_plus_incl_05) ? (int)Math.Round(0.9 * q2Correction) : (int)Math.Round(1.1 * q2Correction);
q2CorrLR = (int)Math.Round(0.5 * q2Correction);
q2CorrRL = (q3error * q2adjResult.Error < 0) ? Convert.ToInt32(0.9 * q2Correction) : Convert.ToInt32(1.1 * q2Correction);
}
else if (q2CorrType == Q2CorrType.Dewa ||
q2CorrType == Q2CorrType.Dewa_incl_05 ||
q2CorrType == Q2CorrType.Dewa_plus_incl_05)
{
///
/// Process for DEWA
/// Standard process for the oposite flow direction (LR)
/// No 2nd Q2 test, MakeQ2CorrectedFrom(...) is used to calculate Q2 error
/// Do not forget to modify iPerlCommunicationSeq.MakeQ2CorrectedFrom(...)
///
if (q2CorrType == Q2CorrType.Dewa && Math.Abs(q2adjResult.Error) <= 0.5)
q2CorrLR = (q3error * q2adjResult.Error < 0) ? Convert.ToInt32(0.9 * q2Correction) : Convert.ToInt32(1.1 * q2Correction);
}
else if (q2CorrType == Q2CorrType.RL ||
q2CorrType == Q2CorrType.RL_incl_05 ||
q2CorrType == Q2CorrType.ConditionalUpdateRL)
{
///
/// RL only
/// Assuming the 2nd Q2 test is done afterwards
/// MakeQ2CorrectedFrom(...) is not used
///
if (q2CorrType == Q2CorrType.RL && Math.Abs(q2adjResult.Error) <= 0.5)
{
resultStr = string.Format("Q2 correction = 0 (writing bypassed)");
return CommErr.None;
}
/// Use the same correction factor in both directions
q2CorrRL = (q2CorrType == Q2CorrType.Dewa_plus_incl_05) ? (int)Math.Round(0.9 * q2Correction2) : (int)Math.Round(1.0 * q2Correction2);
q2CorrLR = (q2CorrType == Q2CorrType.Dewa_plus_incl_05) ? (int)Math.Round(0.9 * q2Correction2) : (int)Math.Round(1.0 * q2Correction2);
q2CorrRL = Convert.ToInt32(q2Correction);
}
else if (q2CorrType == Q2CorrType.LR ||
q2CorrType == Q2CorrType.LR_incl_05 ||
q2CorrType == Q2CorrType.ConditionalUpdateLR)
{
///
/// LR only
/// Assuming the 2nd Q2 test is done afterwards
/// MakeQ2CorrectedFrom(...) is not used
///
if (q2CorrType == Q2CorrType.LR && Math.Abs(q2adjResult.Error) <= 0.5)
{
resultStr = string.Format("Q2 correction = 0 (writing bypassed)");
return CommErr.None;
}
q2CorrLR = Convert.ToInt32(q2Correction2);
}
else if (q2CorrType == Q2CorrType.Update || q2CorrType == Q2CorrType.ConditionalUpdate)
{
///
/// After tests in both directions
/// Assuming the 2nd Q2 tests are done afterwards
/// MakeQ2CorrectedFrom(...) is not used
///
q2CorrRL = Convert.ToInt32(q2Correction);
q2CorrLR = Convert.ToInt32(q2Correction2);
}
else if (q2CorrType == Q2CorrType.Greece || q2CorrType == Q2CorrType.Greece_incl_05 || q2CorrType == Q2CorrType.UpdateBothQ2FactorsTestLRDir)
{
@ -2156,33 +2164,16 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
return CommErr.None;
}
q2CorrRL = (int)Math.Round(2.0 * q2Correction2);
q2CorrLR = (int)Math.Round(1.0 * q2Correction2);
q2CorrRL = Convert.ToInt32(2.0 * q2Correction2);
q2CorrLR = Convert.ToInt32(1.0 * q2Correction2);
}
else if (q2CorrType == Q2CorrType.RL || q2CorrType == Q2CorrType.RL_incl_05 || q2CorrType == Q2CorrType.ConditionalUpdateRL) /// RL only
else if (q2CorrType == Q2CorrType.UpdateBothQ2FactorsTestRLDir)
{
if (q2CorrType == Q2CorrType.RL && Math.Abs(q2adjResult.Error) <= 0.5)
{
resultStr = string.Format("Q2 correction = 0 (writing bypassed)");
return CommErr.None;
}
q2CorrRL = (int)Math.Round(q2Correction);
}
else if (q2CorrType == Q2CorrType.LR || q2CorrType == Q2CorrType.LR_incl_05 || q2CorrType == Q2CorrType.ConditionalUpdateLR) /// LR only
{
if (q2CorrType == Q2CorrType.LR && Math.Abs(q2adjResult.Error) <= 0.5)
{
resultStr = string.Format("Q2 correction = 0 (writing bypassed)");
return CommErr.None;
}
q2CorrLR = (int)Math.Round(q2Correction2);
}
else if ((q2CorrType == Q2CorrType.Update) || (q2CorrType == Q2CorrType.ConditionalUpdate))
{
q2CorrRL = (int)Math.Round(q2Correction);
q2CorrLR = (int)Math.Round(q2Correction2);
///
/// Another strange process
///
q2CorrRL = (q3error * q2adjResult.Error < 0) ? Convert.ToInt32(0.9 * q2Correction) : Convert.ToInt32(1.1 * q2Correction);
q2CorrLR = q2CorrRL;
}
@ -2192,7 +2183,13 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
if (ihead.CommFailed) return CommErr.CommFailed;
CommErr error = CommErr.Write;
if (q2CorrType == Q2CorrType.RL || q2CorrType == Q2CorrType.RL_incl_05 || q2CorrType == Q2CorrType.ConditionalUpdateRL)
if (q2CorrType == Q2CorrType.Standard ||
q2CorrType == Q2CorrType.Standard_incl_05 ||
q2CorrType == Q2CorrType.Standard_plus_incl_05 ||
q2CorrType == Q2CorrType.RL ||
q2CorrType == Q2CorrType.RL_incl_05 ||
q2CorrType == Q2CorrType.ConditionalUpdateRL)
{
///
/// Write R-L Q2 correction factor only
@ -2200,11 +2197,17 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
byte[] wrData = new byte[1] { (byte)q2CorrRL };
if (0 == WriteRequestPort(ihead, MessageID.MetrologyMemory, Q2CorrFactorsAddrRL, wrData.Length, wrData))
{
error = CommErr.None;
wm.Q2CorrRL = ihead.Q2CorrRL = q2CorrRL;
resultStr = string.Format("Q2 correction: RL={0}", q2CorrRL);
error = CommErr.None;
}
}
else if (q2CorrType == Q2CorrType.LR || q2CorrType == Q2CorrType.LR_incl_05 || q2CorrType == Q2CorrType.ConditionalUpdateLR)
else if (q2CorrType == Q2CorrType.Dewa ||
q2CorrType == Q2CorrType.Dewa_incl_05 ||
q2CorrType == Q2CorrType.Dewa_plus_incl_05 ||
q2CorrType == Q2CorrType.LR ||
q2CorrType == Q2CorrType.LR_incl_05 ||
q2CorrType == Q2CorrType.ConditionalUpdateLR)
{
///
/// Write L-R Q2 correction factor only
@ -2212,8 +2215,9 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
byte[] wrData = new byte[1] { (byte)q2CorrLR };
if (0 == WriteRequestPort(ihead, MessageID.MetrologyMemory, Q2CorrFactorsAddrLR, wrData.Length, wrData))
{
error = CommErr.None;
wm.Q2CorrLR = ihead.Q2CorrLR = q2CorrLR;
resultStr = string.Format("Q2 correction: LR={0}", q2CorrLR);
error = CommErr.None;
}
}
else
@ -2224,12 +2228,44 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
byte[] wrData = new byte[2] { (byte)q2CorrLR, (byte)q2CorrRL };
if (0 == WriteRequestPort(ihead, MessageID.MetrologyMemory, Q2CorrFactorsAddr, wrData.Length, wrData))
{
error = CommErr.None;
wm.Q2CorrRL = ihead.Q2CorrRL = q2CorrRL;
wm.Q2CorrLR = ihead.Q2CorrLR = q2CorrLR;
resultStr = string.Format("Q2 correction: RL={0}, LR={1}", q2CorrRL, q2CorrLR);
error = CommErr.None;
}
}
///
/// Q2 correction factor was successfully written to the water meter.
/// Check whether the original error at Q2 was within limits.
///
if (error == CommErr.None &&
(q2adjResult.Error < errLimitLo || errLimitHi < q2adjResult.Error ||
(q2adjResult2 != null && (q2adjResult2.Error < errLimitLo || errLimitHi < q2adjResult2.Error))))
{
resultStr = resultStr + " (OoR)";
/// At least one of Q2 errors is out of range for Q2 correction
log.WarnFormat("OoR => anyhow Q2 correction was done: Pos={0}, PCB#={1}, ***Q2_RL err={2}%***, ***Q2_LR err={3}%***, [Lo={4}%, Hi={5}%]",
ihead.Name,
ihead.SerialNr,
q2adjResult.Error.ToString("F2"),
q2adjResult2 != null ? q2adjResult2.Error.ToString("F2") : string.Empty,
errLimitLo.ToString("F2"),
errLimitHi.ToString("F2"));
rfidDataLogger.InfoFormat("{0}({1}): Q2 error ({2},{3}) is out of range ({4}..{5}) => Failed",
ihead.Name,
ihead.SerialNr,
q2adjResult.Error.ToString("F2"),
q2adjResult2 != null ? q2adjResult2.Error.ToString("F2") : string.Empty,
errLimitLo.ToString("F2"),
errLimitHi.ToString("F2"));
error = CommErr.Q2OutOfRange;
}
///
/// Verification disabled on 16.02.2016
///
@ -2253,30 +2289,18 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
}
}
#else
///
/// Update WaterMeter entity and IperlHead
///
if (error == CommErr.None)
{
if (q2CorrType == Q2CorrType.RL)
{
resultStr = string.Format("Q2 correction: RL={0}", q2CorrRL);
}
else if (q2CorrType == Q2CorrType.LR)
{
resultStr = string.Format("Q2 correction: LR={0}", q2CorrLR);
}
else
{
resultStr = string.Format("Q2 correction: RL={0}, LR={1}", q2CorrRL, q2CorrLR);
}
rfidDataLogger.WarnFormat("{0}: {1}", ihead.Name, resultStr);
if ((q2CorrType != Q2CorrType.Update) && (q2CorrType != Q2CorrType.ConditionalUpdate))
{
wm.Q2ErrWOCorrection = ihead.Q2ErrWOCorrection = q2adjResult.Error;
}
///
/// Update WaterMeter entity and IperlHead
///
if (error == CommErr.None)
{
rfidDataLogger.WarnFormat("{0}({1}): {2}", ihead.Name, ihead.SerialNr, resultStr);
}
#endif

View File

@ -1,5 +1,5 @@
///
/// Copyright (c) 2015-2022 Sensus Slovensko a.s.
/// Copyright (c) 2015-2023 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
@ -572,15 +572,18 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
for (int i = 0; i < ProcessData.BatchRslts.WMPositionsCount; i++)
{
Results.Entities.MeterTestRslt oriMeterRslt = ProcessData.BatchRslts.GetMeterTestRslt(oriTestName, i, CompoundMeterId.Single);
Results.Entities.MeterTestRslt meterRslt = ProcessData.BatchRslts.GetMeterTestRslt(testName, i, CompoundMeterId.Single);
var q3mtr = ProcessData.BatchRslts.GetMeterTestRslt("Q3", i);
double q3error = (q3mtr != null) ? q3mtr.Error : 0;
Results.Entities.MeterTestRslt oriMeterRslt = ProcessData.BatchRslts.GetMeterTestRslt(oriTestName, i);
Results.Entities.MeterTestRslt meterRslt = ProcessData.BatchRslts.GetMeterTestRslt(testName, i);
/// Reference to iPerl water meter or null:
TestMethods.iPerlCommunication.iPerlHead.IperlHead iPerl = ((sensPath != null) && (sensPath.RegisterReaders != null) && (i < sensPath.RegisterReaders.Length))
? (sensPath.RegisterReaders[i] as TestMethods.iPerlCommunication.iPerlHead.IperlHead)
: null;
if (meterRslt != null && oriMeterRslt != null)
if (iPerl != null && meterRslt != null && oriMeterRslt != null)
{
#if ORACLE_DB
meterRslt.ErrorBC = oriMeterRslt.Error;
@ -591,12 +594,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
meterRslt.VolumeRef = oriMeterRslt.VolumeRef;
meterRslt.TestTime = oriMeterRslt.TestTime;
if (iPerl == null || ((iPerl.Q2CorrRL == 0) && (iPerl.Q2CorrLR == 0)))
{
/// Either no iPerl head or no Q2 correction
meterRslt.Error = oriMeterRslt.Error;
}
else if (isPlus)
if (q3error * oriMeterRslt.Error < 0)
{
/// iPerl with Q2 correction => generate an artificial error equal to +1/10 of the original one (relative to Q2 target error)
meterRslt.Error = 0.1 * oriMeterRslt.Error;