OptoTelegramRaw class omved to Common.Iperl namespace, ver. 2.26.1694

This commit is contained in:
Milan Hanajik 2021-07-06 13:11:42 +02:00
parent 7b780d72a0
commit 4a33339c63
7 changed files with 154 additions and 148 deletions

View File

@ -42,6 +42,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="BackgroundBeep.cs" />
<Compile Include="Iperl\OptoTelegramRaw.cs" />
<Compile Include="SerializableDictionary.cs" />
<Compile Include="UIControls\CoolButtonCtrl.cs">
<SubType>UserControl</SubType>

View File

@ -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
/// </description>
/// <param name="data">A complete byte array data</param>
/// <returns>true = telegram OK, false = telegram NOK</returns>
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());
}
}
/// <summary>
/// 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 ...
/// </summary>
/// <param name="optoData">array of OptoTelegramRaw objects</param>
/// <param name="from">Index of the first optoData item to process</param>
/// <param name="to">Index of the last optoData item to process</param>
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];
}
}
/// <summary>
/// Get index to optoData buffer
/// </summary>
/// <param name="index">Original unwrapped index</param>
/// <returns>Index to the buffer</returns>
public static int BufferIdx(int index)
{
if (index < IperlHead.MaxOptoDataCount)
{
return index;
}
else
{
return IperlHead.StartOptoDataCount + (index - IperlHead.MaxOptoDataCount) % IperlHead.EndOptoDataCount;
}
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -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,

View File

@ -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
/// <summary>Stop this operation</summary>
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 : "<null>");
@ -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);
}
}
/// <summary>
/// Save opto data to a file.
/// </summary>
@ -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));
}
/// <summary>
/// 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 ...
/// </summary>
/// <param name="optoData">array of OptoTelegramRaw objects</param>
/// <param name="from">Index of the first optoData item to process</param>
/// <param name="to">Index of the last optoData item to process</param>
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];
}
}
/// <summary>
/// Get index to optoData buffer
/// </summary>
/// <param name="index">Original unwrapped index</param>
/// <returns>Index to the buffer</returns>
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);

View File

@ -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")]

View File

@ -1590,7 +1590,6 @@
</Compile>
<Compile Include="BenchControl\TestMethods\iPerlCommunication\iPerlHead\FlowDirectionDetection.cs" />
<Compile Include="BenchControl\TestMethods\iPerlCommunication\iPerlHead\OptoReceivedEventArgs.cs" />
<Compile Include="BenchControl\TestMethods\iPerlCommunication\iPerlHead\OptoTelegramRaw.cs" />
<Compile Include="BenchControl\TestMethods\iPerlCommunication\iPerlHead\ProcParams.cs" />
<Compile Include="BenchControl\TestMethods\iPerlCommunication\iPerlHead\StatusStruct.cs" />
<Compile Include="BenchControl\TestMethods\iPerlCommunication\TestMethod.cs" />