From 6fd67cdf08a51dac405f9e43b4805a8422deba90 Mon Sep 17 00:00:00 2001 From: Milan Hanajik Date: Fri, 4 Aug 2023 14:43:30 +0200 Subject: [PATCH] Q2 correction for standard process and MakeQ2CorrectionFrom(...) modified to satisfy MID, Q2 correction done when OoR. --- Results/BatchResults.cs | 2 +- Results/Entities/WaterMeter.cs | 2 +- .../iPerlCommunicationForm.cs | 210 ++++++++++-------- .../iPerlCommunicationSeq.cs | 18 +- 4 files changed, 127 insertions(+), 105 deletions(-) diff --git a/Results/BatchResults.cs b/Results/BatchResults.cs index 74fdc2464..3b48bede9 100644 --- a/Results/BatchResults.cs +++ b/Results/BatchResults.cs @@ -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) { diff --git a/Results/Entities/WaterMeter.cs b/Results/Entities/WaterMeter.cs index e5bf0eb96..cc58eefdd 100644 --- a/Results/Entities/WaterMeter.cs +++ b/Results/Entities/WaterMeter.cs @@ -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; diff --git a/TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationForm.cs b/TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationForm.cs index 6d3555224..d2859aa31 100644 --- a/TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationForm.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationForm.cs @@ -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,15 +2228,47 @@ 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; } } - /// - /// Verification disabled on 16.02.2016 - /// + + /// + /// 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 + /// #if false if (error == CommErr.None) { @@ -2253,30 +2289,18 @@ namespace TBF.Rig.TestMethods.iPerlCommunication } } #else + + if ((q2CorrType != Q2CorrType.Update) && (q2CorrType != Q2CorrType.ConditionalUpdate)) + { + wm.Q2ErrWOCorrection = ihead.Q2ErrWOCorrection = q2adjResult.Error; + } + /// /// 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; - } + rfidDataLogger.WarnFormat("{0}({1}): {2}", ihead.Name, ihead.SerialNr, resultStr); } #endif diff --git a/TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationSeq.cs b/TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationSeq.cs index ef8777621..133069612 100644 --- a/TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationSeq.cs +++ b/TBF/Rig/TestMethods/iPerlCommunication/iPerlCommunicationSeq.cs @@ -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;