OptoTelegramRaw and CalculateFeatureVector() moved to Common project.

This commit is contained in:
Milan Hanajik 2021-07-13 13:08:29 +02:00
parent 3b81f1a143
commit 16de6c5d8b
7 changed files with 180 additions and 173 deletions

View File

@ -67,6 +67,7 @@
<Compile Include="GlobalData.cs" />
<Compile Include="IMeasurementCorrection.cs" />
<Compile Include="IParamsProvider.cs" />
<Compile Include="Iperl\OptoTelegramRaw.cs" />
<Compile Include="IUncertainty.cs" />
<Compile Include="IUser.cs" />
<Compile Include="ProcedureInfo.cs" />

View File

@ -4,9 +4,18 @@
using System;
using System.Globalization;
namespace TBF.Rig.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,16 +105,16 @@ namespace TBF.Rig.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, bool isLog = false)
{
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') ||
(telegram[23] != '\t') || (telegram[28] != '\t') || (telegram[37] != '\t') ||
(telegram[40] != '\r') || (telegram[41] != '\n'))
(!isLog && (telegram[40] != '\r' || telegram[41] != '\n')))
{
Flags = OptoTelegramFlags.InvalidTelegram;
return false;
@ -183,7 +192,7 @@ namespace TBF.Rig.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') ||
@ -229,104 +238,30 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
else /// if (flags == OptoTelegramFlags.OK / OptoTelegramFlags.OK_TestStart / OptoTelegramFlags.OK_TestEnd)
{
return string.Format("{0}:{1}:{2}.{3}\t{4} :\t{5}\t{6}\t{7}\t{8}\t{9}\t{10}\t{11}\t{12}\t{13}\t{14}\t{15}\t{16}\t{17}\t{18}\t{19}\t{20}\t{21}\t{22}",
/* 0 */ DateTime.Hour.ToString("D2"),
/* 1 */ DateTime.Minute.ToString("D2"),
/* 2 */ DateTime.Second.ToString("D2"),
/* 3 */ DateTime.Millisecond.ToString("D4"),
/* 4 */ Counter,
/* 5 */ EmfRaw.ToString("X6"),
/* 6 */ MagneticFieldRaw.ToString("X4"),
/* 7 */ FlowRaw.ToString("X4"),
/* 8 */ VolumeRaw.ToString("X6"),
/* 9 */ Impedance.ToString("X4"),
/* 10 */ Timestamp.ToString("X8"),
/* 11 */ CheckSum.ToString("X2"),
/* 12 */ EMF().ToString("F4", culture),
/* 13 */ MagneticField().ToString("F0", culture),
/* 14 */ Flow(scalingFactor).ToString("F2", culture),
/* 15 */ Volume(scalingFactor).ToString("F4", culture),
/* 16 */ FlipTime().ToString("F0", culture),
/* 17 */ TimestampDec().ToString("F4", culture),
/* 18 */ (RefFlow * 1000).ToString("F2", culture),
/* 19 */ VolumeDelta(scalingFactor, previous).ToString("F4", culture),
/* 20 */ TimeDelta().ToString("F3", culture),
/* 21 */ scalingFactor.ToString("F1", culture),
/* 22 */ Label());
DateTime.Hour.ToString("D2"),
DateTime.Minute.ToString("D2"),
DateTime.Second.ToString("D2"),
DateTime.Millisecond.ToString("D4"),
Counter,
EmfRaw.ToString("X6"),
MagneticFieldRaw.ToString("X4"),
FlowRaw.ToString("X4"),
VolumeRaw.ToString("X6"),
Impedance.ToString("X4"),
Timestamp.ToString("X8"),
CheckSum.ToString("X2"),
EMF().ToString("F4", culture),
MagneticField().ToString("F0", culture),
Flow(scalingFactor).ToString("F2", culture),
Volume(scalingFactor).ToString("F4", culture),
FlipTime().ToString("F0", culture),
TimestampDec().ToString("F4", culture),
(RefFlow * 1000).ToString("F2", culture),
VolumeDelta(scalingFactor, previous).ToString("F4", culture),
TimeDelta().ToString("F3", culture),
scalingFactor.ToString("F1", culture),
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

@ -284,5 +284,46 @@ namespace Common
(userName.Equals("gilles") && password.Equals("alibaba")) ||
(userName.Equals(passwordOfDay) && password.Equals(passwordOfDay));
}
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

@ -3,6 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TBF", "TBF\TBF.csproj", "{8648FD92-CDA1-4C3A-B5F9-FE547CE1FA48}"
ProjectSection(ProjectDependencies) = postProject
{7EBEEA14-91C4-48D7-AF0A-7A4BC3FF9A28} = {7EBEEA14-91C4-48D7-AF0A-7A4BC3FF9A28}
{C8939821-BA5C-4988-A3D0-BF53B74865C7} = {C8939821-BA5C-4988-A3D0-BF53B74865C7}
{211B5E3F-9996-48A7-ABDE-C878DD2D71C2} = {211B5E3F-9996-48A7-ABDE-C878DD2D71C2}
{0C0A1F4D-1363-4544-A7C5-196C76D26CCA} = {0C0A1F4D-1363-4544-A7C5-196C76D26CCA}

View File

@ -99,15 +99,6 @@ namespace TBF.Rig.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,11 +1,12 @@
///
/// 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;
using Common.Iperl;
using Config.Entities;
using TBF.Rig.Generic;
using TBF.Rig.GenericDevices;
@ -613,8 +614,8 @@ namespace TBF.Rig.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>");
@ -634,17 +635,17 @@ namespace TBF.Rig.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);
@ -662,51 +663,10 @@ namespace TBF.Rig.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>
string SaveOptoData()
string SaveOptoData()
{
if (!string.IsNullOrEmpty(optoDataLogFileName))
{
@ -747,11 +707,10 @@ namespace TBF.Rig.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)]));
}
}
@ -844,7 +803,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
/// CR+LF found
if (optoState == OptoState.Read)
{
int bufferIx = OptoTelegramRaw.BufferIdx(optoDataCount);
int bufferIx = BufferIdx(optoDataCount);
if (pos < OptoTelegramRaw.Length - 2)
{
@ -857,7 +816,10 @@ namespace TBF.Rig.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);
@ -884,7 +846,10 @@ namespace TBF.Rig.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;
@ -971,9 +936,9 @@ namespace TBF.Rig.TestMethods.iPerlCommunication.iPerlHead
switch (units)
{
default:
case VolumeUnits.m3: return Common.Units.ConvertFrom(Common.Unit.m3, 1.0); /// liter
case VolumeUnits.UK_gallon: return Common.Units.ConvertFrom(Common.Unit.UKgal, 1.0); /// liter
case VolumeUnits.US_gallon: return Common.Units.ConvertFrom(Common.Unit.USgal, 1.0); /// liter
case VolumeUnits.m3: return Common.Units.ConvertFrom(Common.Unit.m3, 1.0); /// 1 liter
case VolumeUnits.UK_gallon: return Common.Units.ConvertFrom(Common.Unit.UKgal, 1.0); /// 1 imperial gallon
case VolumeUnits.US_gallon: return Common.Units.ConvertFrom(Common.Unit.USgal, 1.0); /// 1 US gallon
}
}
@ -1032,7 +997,7 @@ namespace TBF.Rig.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 &&
@ -1061,7 +1026,7 @@ namespace TBF.Rig.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 &&
@ -1076,6 +1041,80 @@ namespace TBF.Rig.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

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