diff --git a/Common/Common.csproj b/Common/Common.csproj index 5e254c157..c09591d31 100644 --- a/Common/Common.csproj +++ b/Common/Common.csproj @@ -42,6 +42,7 @@ + UserControl diff --git a/TBF/BenchControl/TestMethods/iPerlCommunication/iPerlHead/OptoTelegramRaw.cs b/Common/Iperl/OptoTelegramRaw.cs similarity index 75% rename from TBF/BenchControl/TestMethods/iPerlCommunication/iPerlHead/OptoTelegramRaw.cs rename to Common/Iperl/OptoTelegramRaw.cs index 6fdaae0c2..d0304abc8 100644 --- a/TBF/BenchControl/TestMethods/iPerlCommunication/iPerlHead/OptoTelegramRaw.cs +++ b/Common/Iperl/OptoTelegramRaw.cs @@ -1,12 +1,21 @@ /// -/// Copyright (c) 2015-2017 Sensus Metering Systems +/// Copyright (c) 2015-2021 Sensus Metering Systems /// using System; using System.Globalization; -namespace TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead +namespace Common.Iperl { - public class OptoTelegramRaw + public enum OptoTelegramFlags : byte + { + OK = 0, + OK_TestStart, + OK_TestEnd, + InvalidTelegram, /// Wrong telegram format of checksum error + SyncError, + } + + public class OptoTelegramRaw { public static readonly int Length = 42; private static CultureInfo culture; @@ -96,11 +105,11 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead /// /// A complete byte array data /// true = telegram OK, false = telegram NOK - public bool UpdateFromString(string telegram, int counter, ref Int64 volumeRawExtLast, ref Int64 timestampExtLast) + public bool UpdateFromString(string telegram, int counter, float refFlow, ref Int64 volumeRawExtLast, ref Int64 timestampExtLast) { DateTime = DateTime.Now; Counter = counter; - RefFlow = (float)Sequences.ProcessData.RefFlow.Val; + RefFlow = refFlow; if ((telegram == null) || (telegram.Length < Length) || (telegram[6] != '\t') || (telegram[11] != '\t') || (telegram[16] != '\t') || @@ -183,7 +192,7 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead public bool UpdateFromStringDummy(string telegram) { DateTime = DateTime.Now; - RefFlow = (float)Sequences.ProcessData.RefFlow.Val; + RefFlow = 0; if ((telegram == null) || (telegram.Length < Length) || (telegram[6] != '\t') || (telegram[11] != '\t') || (telegram[16] != '\t') || @@ -254,79 +263,5 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead Label()); } } - - /// - /// Filter RefFlow data in an array of OptoTelegramRaw objects by a FIR filter: - /// - /// kSize = 5, kSize2 = 2 - /// - /// i k - /// --------------------------------------------------------------------------- - /// 0 -5 filtered[0] = data[0] - /// 1 -4 filtered[1] = data[1] - /// 2 -3 filtered[2] = data[0]*k[0] + ... + data[4]*k[4] - /// 3 -2 filtered[3] = data[1]*k[0] + ... + data[5]*k[4] - /// 4 -1 filtered[4] = data[2]*k[0] + ... + data[6]*k[4] - /// 5 0 data[0] = filtered[0], filtered[0] = data[3]*k[0] + ... + data[7]*k[4] - /// 6 1 data[1] = filtered[1], filtered[1] = data[4]*k[0] + ... + data[8]*k[4] - /// 7 ... - /// - /// array of OptoTelegramRaw objects - /// Index of the first optoData item to process - /// Index of the last optoData item to process - public static void FIRFilterFlow(OptoTelegramRaw[] optoData, int from, int to) - { - float[] kernel = new float[] { 0.1f, 0.2f, 0.4f, 0.2f, 0.1f }; - int kSize = kernel.Length; - int kSize2 = kernel.Length / 2; - - float[] filtered = new float[kSize]; - - for (int i = from; i <= to; i++) - { - if ((i < from + kSize2) || (i > to - kSize2)) - { - /// Beginning or end of optoData buffer => Just copy data (=do not filter) - filtered[i % kSize] = optoData[BufferIdx(i)].RefFlow; - } - else - { - /// Make a convolution of optoData and the kernel - float weightedSum = 0; - for (int j = -kSize2; j <= kSize2; j++) - weightedSum += optoData[BufferIdx(i + j)].RefFlow * kernel[j + kSize2]; - - filtered[i % kSize] = weightedSum; - } - - if (i >= from + kSize) - { - /// filtered[] buffer full => copy filtered data to optoData - optoData[BufferIdx(i - kSize)].RefFlow = filtered[i % kSize]; - } - } - - for (int i = to - kSize + 1; i <= to; i++) - { - if (i >= 0) optoData[BufferIdx(i)].RefFlow = filtered[i % kSize]; - } - } - - /// - /// Get index to optoData buffer - /// - /// Original unwrapped index - /// Index to the buffer - public static int BufferIdx(int index) - { - if (index < IperlHead.MaxOptoDataCount) - { - return index; - } - else - { - return IperlHead.StartOptoDataCount + (index - IperlHead.MaxOptoDataCount) % IperlHead.EndOptoDataCount; - } - } } } diff --git a/Common/Utils.cs b/Common/Utils.cs index 3f9bbaadc..6a78fbcaa 100644 --- a/Common/Utils.cs +++ b/Common/Utils.cs @@ -17,5 +17,46 @@ namespace Common if (repeats == 1) return name; return string.Format("{0} ({1}/{2})", name, repetitionNr, repeats); } + + public static void CalculateFeatureVector(Iperl.OptoTelegramRaw[] optoData, int optoDataCount, int startIx, int endIx, ref float[] x) + { + if (startIx < 0 || endIx >= optoDataCount || startIx >= endIx) return; + + int n = 0; + Int64 sumFlow = 0; + Int64 sumFlow2 = 0; + Int64 sumEmf = 0; + Int64 sumEmf2 = 0; + Int64 sumMagF = 0; + Int64 sumMagF2 = 0; + Int64 sumImp = 0; + Int64 sumImp2 = 0; + + for (int ix = startIx; ix <= endIx; ix++) + { + if (optoData[ix].Flags == Iperl.OptoTelegramFlags.OK || + optoData[ix].Flags == Iperl.OptoTelegramFlags.OK_TestStart || + optoData[ix].Flags == Iperl.OptoTelegramFlags.OK_TestEnd) + { + n++; + sumFlow += optoData[ix].FlowRaw; + sumFlow2 += ((int)optoData[ix].FlowRaw * (int)optoData[ix].FlowRaw); + sumEmf += (int)optoData[ix].EmfRaw; + sumEmf2 += ((Int64)optoData[ix].EmfRaw * (Int64)optoData[ix].EmfRaw); + sumMagF += optoData[ix].MagneticFieldRaw; + sumMagF2 += ((int)optoData[ix].MagneticFieldRaw * (int)optoData[ix].MagneticFieldRaw); + sumImp += optoData[ix].Impedance; + sumImp2 += ((int)optoData[ix].Impedance * (int)optoData[ix].Impedance); + } + } + + if (n >= 2) + { + if (x.Length > 0) x[0] = ((float)sumFlow2 - (float)sumFlow * (float)sumFlow / n) / (n - 1); + if (x.Length > 1) x[1] = ((float)sumEmf2 - (float)sumEmf * (float)sumEmf / n) / (n - 1); + if (x.Length > 2) x[2] = ((float)sumMagF2 - (float)sumMagF * (float)sumMagF / n) / (n - 1); + if (x.Length > 3) x[3] = ((float)sumImp2 - (float)sumImp * (float)sumImp / n) / (n - 1); + } + } } } diff --git a/TBF/BenchControl/TestMethods/iPerlCommunication/iPerlHead/Enums.cs b/TBF/BenchControl/TestMethods/iPerlCommunication/iPerlHead/Enums.cs index 931b02ecc..646076c50 100644 --- a/TBF/BenchControl/TestMethods/iPerlCommunication/iPerlHead/Enums.cs +++ b/TBF/BenchControl/TestMethods/iPerlCommunication/iPerlHead/Enums.cs @@ -99,15 +99,6 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead Count /// Number of flow states } - public enum OptoTelegramFlags : byte - { - OK = 0, - OK_TestStart, - OK_TestEnd, - InvalidTelegram, /// Wrong telegram format of checksum error - SyncError, - } - public enum OptoState { Read, diff --git a/TBF/BenchControl/TestMethods/iPerlCommunication/iPerlHead/IperlHead.cs b/TBF/BenchControl/TestMethods/iPerlCommunication/iPerlHead/IperlHead.cs index 11a89bd77..99908a666 100644 --- a/TBF/BenchControl/TestMethods/iPerlCommunication/iPerlHead/IperlHead.cs +++ b/TBF/BenchControl/TestMethods/iPerlCommunication/iPerlHead/IperlHead.cs @@ -1,10 +1,11 @@ /// -/// Copyright (c) 2015-2020 Sensus Slovensko a.s. +/// Copyright (c) 2015-2021 Sensus Slovensko a.s. /// using System; using System.IO; using System.IO.Ports; using log4net; +using Common.Iperl; using Config.Entities; using TBF.BenchControl.Generic; using TBF.BenchControl.GenericDevices; @@ -617,8 +618,8 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead /// Stop this operation public void Stop() { - int startIx = OptoTelegramRaw.BufferIdx(TestStartTelegramIx); - int endIx = OptoTelegramRaw.BufferIdx(TestEndTelegramIx); + int startIx = BufferIdx(TestStartTelegramIx); + int endIx = BufferIdx(TestEndTelegramIx); log.WarnFormat("IperlHeadd.Stop() startIx={0} endIx={1} optoData.Len={2} filename={3}", startIx, endIx, optoData.Length, !string.IsNullOrEmpty(optoDataLogFileName) ? optoDataLogFileName : ""); @@ -638,17 +639,17 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead StopParsingOptoSerialPort(); if (optoDataCount <= MaxOptoDataCount) { - OptoTelegramRaw.FIRFilterFlow(optoData, 0, optoDataCount - 1); + FIRFilterFlow(optoData, 0, optoDataCount - 1); } else { - OptoTelegramRaw.FIRFilterFlow(optoData, 0, StartOptoDataCount - 1); - OptoTelegramRaw.FIRFilterFlow(optoData, (optoDataCount - EndOptoDataCount), optoDataCount - 1); + FIRFilterFlow(optoData, 0, StartOptoDataCount - 1); + FIRFilterFlow(optoData, (optoDataCount - EndOptoDataCount), optoDataCount - 1); } log.DebugFormat("Flow filtering end, feature vector calculation start: {0:HH:mm:ss.fff}", DateTime.Now); - CalculateFeatureVector(optoData, optoDataCount, startIx, endIx, ref x); + Common.Utils.CalculateFeatureVector(optoData, optoDataCount, startIx, endIx, ref x); log.DebugFormat("Feature vector calculation end, save opto-file start: {0:HH:mm:ss.fff}", DateTime.Now); @@ -666,47 +667,6 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead } } - void CalculateFeatureVector(OptoTelegramRaw[] optoData, int optoDataCount, int startIx, int endIx, ref float[] x) - { - if (startIx < 0 || endIx >= optoDataCount || startIx >= endIx) return; - - int n = 0; - Int64 sumFlow = 0; - Int64 sumFlow2 = 0; - Int64 sumEmf = 0; - Int64 sumEmf2 = 0; - Int64 sumMagF = 0; - Int64 sumMagF2 = 0; - Int64 sumImp = 0; - Int64 sumImp2 = 0; - - for (int ix = startIx; ix <= endIx; ix++) - { - if (optoData[ix].Flags == OptoTelegramFlags.OK || - optoData[ix].Flags == OptoTelegramFlags.OK_TestStart || - optoData[ix].Flags == OptoTelegramFlags.OK_TestEnd) - { - n++; - sumFlow += optoData[ix].FlowRaw; - sumFlow2 += ((int)optoData[ix].FlowRaw * (int)optoData[ix].FlowRaw); - sumEmf += (int)optoData[ix].EmfRaw; - sumEmf2 += ((Int64)optoData[ix].EmfRaw * (Int64)optoData[ix].EmfRaw); - sumMagF += optoData[ix].MagneticFieldRaw; - sumMagF2 += ((int)optoData[ix].MagneticFieldRaw * (int)optoData[ix].MagneticFieldRaw); - sumImp += optoData[ix].Impedance; - sumImp2 += ((int)optoData[ix].Impedance * (int)optoData[ix].Impedance); - } - } - - if (n >= 2) - { - if (x.Length > 0) x[0] = ((float)sumFlow2 - (float)sumFlow * (float)sumFlow / n) / (n - 1); - if (x.Length > 1) x[1] = ((float)sumEmf2 - (float)sumEmf * (float)sumEmf / n) / (n - 1); - if (x.Length > 2) x[2] = ((float)sumMagF2 - (float)sumMagF * (float)sumMagF / n) / (n - 1); - if (x.Length > 3) x[3] = ((float)sumImp2 - (float)sumImp * (float)sumImp / n) / (n - 1); - } - } - /// /// Save opto data to a file. /// @@ -751,11 +711,10 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead optoLogFile.WriteLine(" ..."); /// Second part of the buffer is an overflowed circular buffer - optoLogFile.WriteLine(optoData[OptoTelegramRaw.BufferIdx(optoDataCount)].ToString(scalFact, null)); + optoLogFile.WriteLine(optoData[BufferIdx(optoDataCount)].ToString(scalFact, null)); for (int i = optoDataCount - EndOptoDataCount + 1; i < optoDataCount; i++) { - optoLogFile.WriteLine(optoData[OptoTelegramRaw.BufferIdx(i)] - .ToString(scalFact, optoData[OptoTelegramRaw.BufferIdx(i - 1)])); + optoLogFile.WriteLine(optoData[BufferIdx(i)].ToString(scalFact, optoData[BufferIdx(i - 1)])); } } @@ -848,7 +807,7 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead /// CR+LF found if (optoState == OptoState.Read) { - int bufferIx = OptoTelegramRaw.BufferIdx(optoDataCount); + int bufferIx = BufferIdx(optoDataCount); if (pos < OptoTelegramRaw.Length - 2) { @@ -861,7 +820,10 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead } synchronized = true; } - else if (optoData[bufferIx].UpdateFromString(allRcvd.Substring(pos - OptoTelegramRaw.Length + 2), optoDataCount, ref volumeRawExtLast, ref timestampExtLast)) + else if (optoData[bufferIx].UpdateFromString(allRcvd.Substring(pos - OptoTelegramRaw.Length + 2), + optoDataCount, + Convert.ToSingle(Sequences.ProcessData.RefFlow.Val), + ref volumeRawExtLast, ref timestampExtLast)) { /// CR+LF was found && (pos >= OptoTelegramRaw.Length - 2) && the telegram is OK flowDirectionDetection.WriteToFifo(volumeRawExtLast, timestampExtLast); @@ -888,7 +850,10 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead synchronized = true; } // CR+LF found and (pos >= OptoTelegram.Length - 2) - else if (toBeFlushed.UpdateFromString(allRcvd.Substring(pos - OptoTelegramRaw.Length + 2), 0, ref volumeRawExtLast, ref timestampExtLast)) + else if (toBeFlushed.UpdateFromString(allRcvd.Substring(pos - OptoTelegramRaw.Length + 2), + 0, + Convert.ToSingle(Sequences.ProcessData.RefFlow.Val), + ref volumeRawExtLast, ref timestampExtLast)) { flowDirectionDetection.WriteToFifo(volumeRawExtLast, timestampExtLast); synchronized2 = synchronized; @@ -1036,7 +1001,7 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead Int64 sum = 0; for (int i = unwrappedIx - samplesCount2; i <= unwrappedIx + samplesCount2; i++) { - int wrappedIx = OptoTelegramRaw.BufferIdx(i); + int wrappedIx = BufferIdx(i); if (optoData[wrappedIx].Flags != OptoTelegramFlags.OK && optoData[wrappedIx].Flags != OptoTelegramFlags.OK_TestStart && @@ -1065,7 +1030,7 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead Int64 sum = 0; for (int i = unwrappedIx - samplesCount2; i <= unwrappedIx + samplesCount2; i++) { - int wrappedIx = OptoTelegramRaw.BufferIdx(i); + int wrappedIx = BufferIdx(i); if (optoData[wrappedIx].Flags != OptoTelegramFlags.OK && optoData[wrappedIx].Flags != OptoTelegramFlags.OK_TestStart && @@ -1080,6 +1045,80 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead return sum / (double)(8192 * (2 * samplesCount2 + 1)); } + /// + /// Filter RefFlow data in an array of OptoTelegramRaw objects by a FIR filter: + /// + /// kSize = 5, kSize2 = 2 + /// + /// i k + /// --------------------------------------------------------------------------- + /// 0 -5 filtered[0] = data[0] + /// 1 -4 filtered[1] = data[1] + /// 2 -3 filtered[2] = data[0]*k[0] + ... + data[4]*k[4] + /// 3 -2 filtered[3] = data[1]*k[0] + ... + data[5]*k[4] + /// 4 -1 filtered[4] = data[2]*k[0] + ... + data[6]*k[4] + /// 5 0 data[0] = filtered[0], filtered[0] = data[3]*k[0] + ... + data[7]*k[4] + /// 6 1 data[1] = filtered[1], filtered[1] = data[4]*k[0] + ... + data[8]*k[4] + /// 7 ... + /// + /// array of OptoTelegramRaw objects + /// Index of the first optoData item to process + /// Index of the last optoData item to process + public static void FIRFilterFlow(OptoTelegramRaw[] optoData, int from, int to) + { + float[] kernel = new float[] { 0.1f, 0.2f, 0.4f, 0.2f, 0.1f }; + int kSize = kernel.Length; + int kSize2 = kernel.Length / 2; + + float[] filtered = new float[kSize]; + + for (int i = from; i <= to; i++) + { + if ((i < from + kSize2) || (i > to - kSize2)) + { + /// Beginning or end of optoData buffer => Just copy data (=do not filter) + filtered[i % kSize] = optoData[BufferIdx(i)].RefFlow; + } + else + { + /// Make a convolution of optoData and the kernel + float weightedSum = 0; + for (int j = -kSize2; j <= kSize2; j++) + weightedSum += optoData[BufferIdx(i + j)].RefFlow * kernel[j + kSize2]; + + filtered[i % kSize] = weightedSum; + } + + if (i >= from + kSize) + { + /// filtered[] buffer full => copy filtered data to optoData + optoData[BufferIdx(i - kSize)].RefFlow = filtered[i % kSize]; + } + } + + for (int i = to - kSize + 1; i <= to; i++) + { + if (i >= 0) optoData[BufferIdx(i)].RefFlow = filtered[i % kSize]; + } + } + + /// + /// Get index to optoData buffer + /// + /// Original unwrapped index + /// Index to the buffer + public static int BufferIdx(int index) + { + if (index < IperlHead.MaxOptoDataCount) + { + return index; + } + else + { + return IperlHead.StartOptoDataCount + (index - IperlHead.MaxOptoDataCount) % IperlHead.EndOptoDataCount; + } + } + public void WriteBinary(BinaryWriter writer) { writer.Write(Disabled); diff --git a/TBF/Properties/AssemblyInfo.cs b/TBF/Properties/AssemblyInfo.cs index cfcace450..9f062bfe7 100644 --- a/TBF/Properties/AssemblyInfo.cs +++ b/TBF/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("2.26.1693.0")] -[assembly: AssemblyFileVersion("2.26.1693.0")] +[assembly: AssemblyVersion("2.26.1694.0")] +[assembly: AssemblyFileVersion("2.26.1694.0")] diff --git a/TBF/TBF.csproj b/TBF/TBF.csproj index b1024cb5c..64d7c3ffe 100644 --- a/TBF/TBF.csproj +++ b/TBF/TBF.csproj @@ -1590,7 +1590,6 @@ -