/// /// Copyright (c) 2017 Sensus Metering Systems /// using System; using log4net; using TBF.Boxes; namespace TBF.BenchControl.Elde { public class ReadDiverterTransitionOp : IOperation { private static readonly ILog log = LogManager.GetLogger(typeof(ReadDiverterTransitionOp)); public override string ToString() { return string.Format("ReadDiverterTransitionOp(.,{0},{1},{2},...)", div.Name, runsCountWhenSendingCmd, runsCountWhenReadingDiv); } const int SamplesCount = 240; /// Should be less then or equal to 256 float[] samples; /// Set by the constructor readonly ControlBoardDev controlBoard; readonly GenericDevices.IDiverter div; readonly int runsCountWhenSendingCmd; readonly int runsCountWhenReadingDiv; readonly FloatBox transitionTimeSec; readonly Sequences.Statistics plotter; readonly int batchNr; readonly string testName; readonly int repetition; int counter; bool cmdSent = false; bool divRead = false; /// /// Starts the measurement. /// Events: MeasurementStarted /// /// Control board component reference /// Specifies used components /// Test method /// Test duration in number of reference flowmeter pulses /// Specifies filter for watermeter pulses public ReadDiverterTransitionOp(ControlBoardDev controlBoard, GenericDevices.IDiverter div, int runsCountWhenSendingCmd, int runsCountWhenReadingDiv, FloatBox transitionTimeSec, Sequences.Statistics plotter, int batchNr, string testName, int repetition) { if (controlBoard == null) throw new ArgumentNullException("controlBoardDev"); if (runsCountWhenSendingCmd < 0) throw new ArgumentNullException("runsCountWhenSendingCmd"); if (runsCountWhenReadingDiv <= runsCountWhenSendingCmd) throw new ArgumentNullException("runsCountWhenReadingDiv"); if (transitionTimeSec == null) throw new ArgumentNullException("transitionTimeSec"); this.controlBoard = controlBoard; this.div = div; this.runsCountWhenSendingCmd = runsCountWhenSendingCmd; this.runsCountWhenReadingDiv = runsCountWhenReadingDiv; this.transitionTimeSec = transitionTimeSec; this.plotter = plotter; this.batchNr = batchNr; this.testName = testName; this.repetition = repetition; samples = new float[SamplesCount]; log.Debug(this.ToString()); } /// Start this operation public void Start() { counter = 0; if (runsCountWhenSendingCmd == 0 && div.DiverterNr > 0) { SendCommand(); log.DebugFormat("Start() ... Sending a command to read diverter {0}", div.Name); } if (plotter != null) { plotter.Start(batchNr, testName, repetition); log.DebugFormat("Start() ... plotter.Start({0}, {1}, {2})", batchNr, testName, repetition); } } /// Run this operation /// /// Event.FlowInDone or Event.FlowOutDone /// public Event Run() { counter++; if (counter == runsCountWhenSendingCmd && div.DiverterNr > 0) { SendCommand(); log.DebugFormat("Run() ... Sending a command to read diverter {0}", div.Name); } else if (counter == runsCountWhenReadingDiv && div.DiverterNr > 0) { if (plotter == null) { ReadDiverterTransitionTimes(); log.DebugFormat("Run() ... Reading diverter {0} transition times: {1}s", div.Name, transitionTimeSec.Val); } else { log.DebugFormat("Run() ... Reading diverter {0} samples", div.Name); for (int i = 0; i < SamplesCount; i++) { float oneSample = controlBoard.DivSamples(i, div.DiverterNr - 1); samples[i] = oneSample; plotter.Update(oneSample); } plotter.Stop(); log.DebugFormat("Run() ... Calculating diverter {0} transition times: {1}s", div.Name, transitionTimeSec.Val); CalculateDiverterTransitionTimes(); } } return Event.None; } /// Stop this operation public void Stop() { log.DebugFormat("Stop()"); } void SendCommand() { controlBoard.SyncRoute(); controlBoard.SendCommand(Command.ReadDivTransition, 0, controlBoard.Route, 0, 0, 0, 0, 0, 0, StopDevs.None); cmdSent = true; } /// /// Diverter transition time is read from the control board /// /// true (always) bool ReadDiverterTransitionTimes() { transitionTimeSec.Val = (float)controlBoard.DivTime(2) - (float)controlBoard.DivTime(1); return true; } /// /// Diverter transition time is calculated from ADC samples and threshold levels /// /// true when transition time calculated OK bool CalculateDiverterTransitionTimes() { bool startedRising = false; bool startedFalling = false; bool stopped = false; int transitionStartIdx = 0; int transitionEndIdx = 0; float level = samples[0]; for (int i = 1; i < SamplesCount; i++) { if (!startedRising && !startedFalling) { if (level <= div.ThresholdLo && samples[i] > div.ThresholdLo) { transitionStartIdx = i; startedRising = true; } else if (level >= div.ThresholdHi && samples[i] < div.ThresholdHi) { transitionStartIdx = i; startedFalling = true; } } else if (startedRising && !stopped && level < div.ThresholdHi && samples[i] >= div.ThresholdHi) { transitionEndIdx = i; stopped = true; break; } else if (startedFalling && !stopped && level > div.ThresholdLo && samples[i] <= div.ThresholdLo) { transitionEndIdx = i; stopped = true; break; } } if ((startedRising || startedFalling) && stopped) { transitionTimeSec.Val = 0.002f * (float)(transitionEndIdx - transitionStartIdx); /// 2 ms per sample return true; } else { return false; } } } }