iPerl flow direction detection : Change of flow direction supported, ver. 2.18.1085
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+46
-18
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user