iPerl flow direction detection : Change of flow direction supported, ver. 2.18.1085

This commit is contained in:
Milan Hanajik
2018-12-04 08:58:46 +01:00
parent 5f4cf04edb
commit 0e37e7217d
5 changed files with 109 additions and 72 deletions
@@ -81,6 +81,17 @@ namespace TBF.BenchControl.TestMethods.ChangeFlowDirection
while (!e.Contains(Event.OK));
///
/// Change direction of expected flow in iPerl heads
///
foreach (var rr in sensPath.RegisterReaders)
{
if (rr is TestMethods.iPerlCommunication.iPerlHead.IperlHead)
{
(rr as TestMethods.iPerlCommunication.iPerlHead.IperlHead).ChangeFlowDirection();
}
}
///
/// Fill the line
///
@@ -622,7 +622,6 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication
/// Reset opto-data indication
for (int i = 0; i < iperlHeads.Count; i++)
{
iperlHeads[i].FlushedDataCount = 0;
counters[i].BackColor = OptoNokColor;
}
@@ -8,15 +8,23 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead
{
public class FlowDirectionDetection
{
readonly int fifoSize = 32;
readonly int fifoSize;
Int64[] volumeRawFifo; /// Volume FIFO buffer
Int64[] timestampFifo; /// Timestamp FIFO buffer
///
int fifoCount; /// Number of valid FIFO items
int fifoIx; /// Index of the next FIFO item
DateTime lastFifoWriteTime; /// Time of the last write to FIFO
///
/// Sums for linear regression calculation
///
decimal sumXX;
decimal sumX;
decimal sumXY;
decimal sumY;
decimal N;
public FlowDirectionDetection(int fifoSize)
{
@@ -35,6 +43,12 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead
fifoCount = 0;
fifoIx = 0;
lastFifoWriteTime = DateTime.MinValue;
sumXX = 0;
sumX = 0;
sumXY = 0;
sumY = 0;
N = 0;
}
@@ -45,6 +59,27 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead
/// <param name="timestamp">Time stamp</param>
public void WriteToFifo(Int64 volumeRaw, Int64 timestamp)
{
///
/// Update sums for linear regression calculation
///
if (fifoCount == fifoSize)
{
/// Buffer is already full, the oldest item will be re-written
sumXX -= timestampFifo[fifoIx] * timestampFifo[fifoIx];
sumX -= timestampFifo[fifoIx];
sumXY -= timestampFifo[fifoIx] * volumeRawFifo[fifoIx];
sumY -= volumeRawFifo[fifoIx];
N--;
}
sumXX += timestamp * timestamp;
sumX += timestamp;
sumXY += timestamp * volumeRaw;
sumY += volumeRaw;
N++;
///
/// Save new values to FIFO
///
volumeRawFifo[fifoIx] = volumeRaw;
timestampFifo[fifoIx] = timestamp;
fifoIx = (fifoIx + 1) % fifoSize;
@@ -71,25 +106,18 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead
{
if (!AreFifoDataValid()) return OptoHeadState.OptoNok;
int positiveCount = 0;
int negativeCount = 0;
for (int i = fifoIx; i < fifoIx + fifoSize - 1; i++)
{
if (volumeRawFifo[(i + 1) % fifoSize] - volumeRawFifo[i % fifoSize] > 0)
{
positiveCount++;
}
else if (volumeRawFifo[(i + 1) % fifoSize] - volumeRawFifo[i % fifoSize] < 0)
{
negativeCount++;
}
}
decimal numer = N * sumXY - sumX * sumY;
decimal denom = N * sumXX - sumX * sumX;
if ((positiveCount > negativeCount) && flowDir == FlowDir.R_L)
if (denom == 0) return OptoHeadState.DirNok;
decimal a = numer / denom;
if ((flowDir == FlowDir.R_L) && (a > 0))
{
return OptoHeadState.OptoAndDirOK;
}
else if ((positiveCount < negativeCount) && flowDir == FlowDir.L_R)
else if ((flowDir == FlowDir.L_R) && (a < 0))
{
return OptoHeadState.OptoAndDirOK;
}
@@ -24,6 +24,7 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead
private static readonly ILog log = LogManager.GetLogger(typeof(IperlHead));
public override string ToString() { return string.Format("iPerl({0})", Cfg.ToString(1)); }
const int FifoSize = 32; /// 4s @ 8Hz
readonly IperlHeadCfg iperlHeadCfg;
@@ -38,7 +39,7 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead
public float CalibTarget { get { return iperlHeadCfg.ProcParams.CalibTarget; } }
public ushort FactorLimitLo { get { return (ushort)iperlHeadCfg.ProcParams.FactorLimitLo; } }
public ushort FactorLimitHi { get { return (ushort)iperlHeadCfg.ProcParams.FactorLimitHi; } }
public FlowDir FlowDir { get { return iperlHeadCfg.ProcParams.FlowDir; } }
public FlowDir InitFlowDir { get { return (iperlHeadCfg != null && iperlHeadCfg.ProcParams != null) ? iperlHeadCfg.ProcParams.FlowDir : FlowDir.R_L; } }
public LogType LogType { get { return iperlHeadCfg.ProcParams.LogType; } }
#if ORACLE_DB
public int WMType_ID { get { return iperlHeadCfg.ProcParams.WMType_ID; } } /// Required by Oracle DB
@@ -376,25 +377,8 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead
const int MaxOptoDataCount = 40000;
int optoDataCount;
string optoDataLogFileName;
OptoTelegramRaw toBeFlushed;
int flushedDataCount;
public int FlushedDataCount
{
get { return flushedDataCount; }
set { flushedDataCount = lastFlushedDataCount = lastFlushedDataCount_1 = value; }
}
int lastFlushedDataCount_1;
int lastFlushedDataCount;
public OptoHeadState CheckFlowDirection()
{
return flowDirectionDetection.CheckFlowDirection(FlowDir);
}
///
OptoTelegramRaw toBeFlushed;
///
/// Opto serial port and worker thread related private variables
@@ -404,12 +388,12 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead
public IperlHead()
{
}
}
public IperlHead(Generic.IComponentCfg cfg)
: base(cfg)
{
flowDirectionDetection = new FlowDirectionDetection(32); /// FIFO size = 32, cca 4 sec.
flowDirectionDetection = new FlowDirectionDetection(FifoSize);
ClearData();
@@ -418,7 +402,35 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead
log.Debug(this.ToString());
}
/// <summary>
public void Initialize()
{
ClearData();
if (DebugLevel == DebugMode.Normal)
{
optoSerialPortParsingEnabled = false;
/// Allocate memory for opto-data from iPerl
optoData = new OptoTelegramRaw[MaxOptoDataCount];
for (int i = 0; i < MaxOptoDataCount; i++) optoData[i] = new OptoTelegramRaw();
toBeFlushed = new OptoTelegramRaw();
synchronized = false;
synchronized2 = false;
partOfTelegram = string.Empty;
/// Prepare serial port
optoSerialPort = new SerialPort(string.Format("COM{0}", iperlHeadCfg.OptoComPortNr),
9600, Parity.None, 8, StopBits.One);
optoSerialPort.Handshake = Handshake.None;
optoSerialPort.Open();
}
}
/// <summary>
/// Clear data related to a specific water meter
/// </summary>
public void ClearData()
@@ -445,36 +457,24 @@ namespace TBF.BenchControl.TestMethods.iPerlCommunication.iPerlHead
optoDataCount = 0;
flowDirectionDetection.ClearFifo(); /// Clear FIFO for flow direction detection
currentFlowDir = InitFlowDir;
if (flowDirectionDetection != null) flowDirectionDetection.ClearFifo(); /// Clear FIFO for flow direction detection
}
public void Initialize()
FlowDir currentFlowDir;
///
public OptoHeadState CheckFlowDirection()
{
ClearData();
if (DebugLevel == DebugMode.Normal)
{
optoSerialPortParsingEnabled = false;
/// Allocate memory for opto-data from iPerl
optoData = new OptoTelegramRaw[MaxOptoDataCount];
for (int i = 0; i < MaxOptoDataCount; i++) optoData[i] = new OptoTelegramRaw();
toBeFlushed = new OptoTelegramRaw();
flushedDataCount = 0;
synchronized = false;
synchronized2 = false;
partOfTelegram = string.Empty;
/// Prepare serial port
optoSerialPort = new SerialPort(string.Format("COM{0}", iperlHeadCfg.OptoComPortNr),
9600, Parity.None, 8, StopBits.One);
optoSerialPort.Handshake = Handshake.None;
optoSerialPort.Open();
}
return (flowDirectionDetection != null) ? flowDirectionDetection.CheckFlowDirection(currentFlowDir) : OptoHeadState.DirNok;
}
///
public void ChangeFlowDirection()
{
currentFlowDir = (InitFlowDir == FlowDir.R_L) ? FlowDir.L_R : FlowDir.R_L;
if (flowDirectionDetection != null) flowDirectionDetection.ClearFifo(); /// Clear FIFO for flow direction detection
}
public void RunDeviceBefore()
{
@@ -785,10 +785,9 @@ 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), flushedDataCount, ref volumeRawExtLast, ref timestampExtLast))
else if (toBeFlushed.UpdateFromString(allRcvd.Substring(pos - OptoTelegramRaw.Length + 2), 0, ref volumeRawExtLast, ref timestampExtLast))
{
flowDirectionDetection.WriteToFifo(volumeRawExtLast, timestampExtLast);
flushedDataCount++;
synchronized2 = synchronized;
allRcvd = allRcvd.Substring(pos + 2);
}