TestMethods.SensitivityTest added.

This commit is contained in:
Milan Hanajik 2017-10-16 16:55:10 +02:00
parent 04db65f01f
commit 6cd0be4c17
16 changed files with 1181 additions and 11 deletions

View File

@ -48,7 +48,7 @@ namespace Results.Entities
public virtual int WMPosition { get; set; }
public virtual string EndState { get; set; } /// End state (of the main water meter)
public virtual string EndStateAux { get; set; } /// End state of the auxiliary water meter
public virtual double QRise { get; set; } /// [m3/h] detected Q_rise of a composed meter
public virtual double QRise { get; set; } /// [m3/h] detected Q_rise of a composed meter or 'sensitivity' of a single meter
public virtual double QFall { get; set; } /// [m3/h] detected Q_fall of a composed meter
public virtual int ErrorFlags { get; set; } /// bitfield : bit14=E15, bit15=E16
public virtual bool Passed { get; set; }

View File

@ -83,14 +83,14 @@ namespace Results
Lite_per_pulse_Read, /// 73
Result_code, /// 74
Remark, /// 75
T_Hi_mean, /// 76
T_Hi_start, /// 77
T_Hi_end, /// 78
T_Hi_avg, /// 79
T_Lo_mean, /// 80
T_Lo_start, /// 81
T_Lo_end, /// 82
T_Lo_avg, /// 83
T_Hi_mean, /// 76
T_Hi_start, /// 77
T_Hi_end, /// 78
T_Hi_avg, /// 79
T_Lo_mean, /// 80
T_Lo_start, /// 81
T_Lo_end, /// 82
T_Lo_avg, /// 83
P_delta_mean, /// 84
P_delta_start, /// 85
P_delta_end, /// 86
@ -180,6 +180,7 @@ namespace Results
Diverter_start_time, /// 159
Diverter_end_time, /// 160
Q_sensitivity, /// 161
Count,
}

View File

@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("2.17.695.0")]
[assembly: AssemblyFileVersion("2.17.695.0")]
[assembly: AssemblyVersion("2.17.700.0")]
[assembly: AssemblyFileVersion("2.17.700.0")]

View File

@ -798,6 +798,15 @@ namespace Results.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to sensitivity.
/// </summary>
internal static string sensitivity {
get {
return ResourceManager.GetString("sensitivity", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Single.
/// </summary>

View File

@ -642,4 +642,7 @@
<data name="Passed_meters_count" xml:space="preserve">
<value>Passed meters count</value>
</data>
<data name="sensitivity" xml:space="preserve">
<value>sensitivity</value>
</data>
</root>

View File

@ -184,6 +184,7 @@ namespace Results
AllItems.Add(new WMeterRsltItemSpec(ItemID.Q_ref_mean, string.Format("{0} rim ()", Strings.VName_Flow), Strings.Tooltip_Q_rim, Quantity.Flow, ItemCategory.TestResult, (w, t, u, f, p) => (w.GetTestRslt(t) == null) ? "" : DblFormat(u, f, p, "V3", w.GetTestRslt(t).FlowMean)));
AllItems.Add(new WMeterRsltItemSpec(ItemID.Q_rise, string.Format("{0} {1}", Strings.VName_Flow, Strings.rise), Quantity.Flow, ItemCategory.MeterResult, (w, t, u, f, p) => (string.IsNullOrEmpty(t) || (w.GetTestRslt(t) != null)) ? ((w.QRise == 0) ? "-" : DblFormat(u, f, p, "V3", w.QRise)) : ""));
AllItems.Add(new WMeterRsltItemSpec(ItemID.Q_fall, string.Format("{0} {1}", Strings.VName_Flow, Strings.fall), Quantity.Flow, ItemCategory.MeterResult, (w, t, u, f, p) => (string.IsNullOrEmpty(t) || (w.GetTestRslt(t) != null)) ? ((w.QFall == 0) ? "-" : DblFormat(u, f, p, "V3", w.QFall)) : ""));
AllItems.Add(new WMeterRsltItemSpec(ItemID.Q_sensitivity, string.Format("{0} {1}", Strings.VName_Flow, Strings.sensitivity), Quantity.Flow, ItemCategory.MeterResult, (w, t, u, f, p) => (string.IsNullOrEmpty(t) || (w.GetTestRslt(t) != null)) ? ((w.QRise == 0) ? "-" : DblFormat(u, f, p, "V3", w.QRise)) : ""));
///
/// Temperature

View File

@ -61,6 +61,7 @@ namespace TBF.BenchControl
Factories.Add(new TestMethods.OuterLoop.Start.Factory());
Factories.Add(new TestMethods.OuterLoop.End.Factory());
Factories.Add(new TestMethods.PMaxTest.TestMethodFactory());
Factories.Add(new TestMethods.SensitivityTest.TestMethodFactory());
Factories.Add(new TestMethods.iPerlCommunication.TestMethodFactory()); /// iPerlCommunication
Factories.Add(new TestMethods.RoiDetection.RoiDetectionFactory());
Factories.Add(new TestMethods.ReferenceFlowmeterCalibration.TestMethodFactory());

View File

@ -0,0 +1,143 @@
///
/// Copyright (c) 2017 Sensus Metering Systems
///
using System;
using System.IO;
using System.Text;
using System.Xml.Serialization;
using Config.Entities;
using TBF.BenchControl.Generic;
using TBF.Resources;
namespace TBF.BenchControl.TestMethods.SensitivityTest
{
public class SensitivityTestParams : TestParamsBase, IParamsProvider, ITestParams
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(SensitivityTestParams) })[0];
protected override XmlSerializer GetSerializer() { return Serializer; }
public float TargetQ; /// Target=terminal flow durning detection when increasing or decreasing the flow
public float RateOfChange; /// Each step is calculated as (TargetQfrom - Qfrom) * RateOfChange, text form is displayed in % (*100)
public float DetectionThreshold; /// Drop of frequency for the detection, text form is displayed in % (*100)
public bool SupressTrills; /// Main meter readings are ignored during test (suitable for small flows)
public override void InitializeAll()
{
TargetQ = 3.0f;
RateOfChange = 0.05f;
DetectionThreshold = 0.25f;
SupressTrills = false;
}
string[] paramNames = new string[]
{
Strings.TargetQ,
Strings.RateOfChangePct,
Strings.DetectionThresholdPct,
Strings.SupressWMTrills,
};
public override string ParamName(int i) { return paramNames[i]; }
public override int ParamsCount() { return paramNames.Length; }
public override string ToString(int i)
{
switch (i)
{
case 0: return TargetQ.ToString();
case 1: return (100.0f * RateOfChange).ToString();
case 2: return (100.0f * DetectionThreshold).ToString();
case 3: return (SupressTrills ? Strings.yes : Strings.no);
default: return string.Empty;
}
}
public void UpdateParam(int i, string strValue)
{
switch (i)
{
case 0: TargetQ = Utils.ParseUFloat(strValue); return;
case 1: RateOfChange = Utils.ParseUFloat(strValue) / 100.0f; return;
case 2: DetectionThreshold = Utils.ParseUFloat(strValue) / 100.0f; return;
case 3: SupressTrills = strValue.Equals(Strings.yes); return;
default: return;
}
}
public bool ValidateParam(int i, string strValue, out string message)
{
message = string.Empty;
float dummy;
switch (i)
{
case 0:
case 1:
case 2:
if (Utils.TryParseUFloat(strValue, out dummy)) return true;
break;
case 3:
if (strValue.Equals(Strings.yes) || strValue.Equals(Strings.no)) return true;
break;
default:
message = "Invalid index";
return false;
}
message = ParamName(i) + " is invalid";
return false;
}
void CopyContentTo(SensitivityTestParams prms)
{
prms.TargetQ = this.TargetQ;
prms.RateOfChange = this.RateOfChange;
prms.DetectionThreshold = this.DetectionThreshold;
prms.SupressTrills = this.SupressTrills;
}
public IParamsProvider Clone()
{
SensitivityTestParams pars = new SensitivityTestParams();
CopyContentTo(pars);
return pars;
}
public override void UpdateTestParams(ComponentTest dbEntity)
{
if (dbEntity == null) return;
try
{
SensitivityTestParams tmp = Serializer.Deserialize(new StringReader(dbEntity.Parameters)) as SensitivityTestParams;
testParamsEntity = dbEntity;
componentName = dbEntity.CmpntName;
test = dbEntity.Test;
if (tmp != null) tmp.CopyContentTo(this);
}
catch
{
}
}
/// <summary>
/// Parameterless constructor initializes the parameters
/// </summary>
public SensitivityTestParams()
{
}
public SensitivityTestParams(bool initialize)
{
if (initialize) InitializeAll();
}
public SensitivityTestParams(ComponentTest testParamsEntity, string componentName, Test test)
{
this.testParamsEntity = testParamsEntity;
this.componentName = componentName;
this.test = test;
}
}
}

View File

@ -0,0 +1,608 @@
///
/// Copyright (c) 2017 Sensus Metering Systems
///
using System;
using System.Collections.Generic;
using System.Text;
using log4net;
using TBF.BenchControl;
using TBF.Resources;
using TBF.UiBridge;
namespace TBF.BenchControl.TestMethods.SensitivityTest
{
public class SensitivityTestSeq : Sequences.SequenceBase
{
private static readonly ILog log = LogManager.GetLogger(typeof(SensitivityTestSeq));
const int DetectionBufferSize = 9;
const int DetectionKernelSize = 5;
public IList<Event> Execute(Config.Entities.Test test, bool outerLoopMode, int outerLoopCounter,
SensitivityTestParams testParams,
Config.Entities.DebugMode debugLevel)
{
IList<Event> e = new List<Event>(); /// Events from currently running operations
checkUiOp = new Operations.CheckUIOp(true); /// Runs in more then one state
float switchTimeStart = 0.001f; /// in seconds, original vale is 1 ms
float switchTimeEnd = 0.001f; /// in seconds, original vale is 1 ms
if (test.Part < 1 || test.Part > Config.Data.CompoundWMsCount)
{
UiBridge.Bridge.OnError(this, string.Format("Test 'Part' should be 1 .. {0}", Config.Data.CompoundWMsCount));
IList<Event> retval = new List<Event>(1);
retval.Add(Event.ConfigurationError);
return retval;
}
if (debugLevel == Config.Entities.DebugMode.Simulate)
{
///
/// Test method simulation
///
TestProgressEventArgs.SetEstimatedTimes(new int[] { 0, 0, 0, 30, 0, 30, 0, 0 });
Bridge.OnTestProgress(this, new TestProgressEventArgs(test, Config.Entities.Progress.JustStarted));
Bridge.OnTestProgress(this, new TestProgressEventArgs(test, Config.Entities.Progress.FlowSetting));
if (test.Name.ToLower().Contains("rise") || test.Name.ToLower().Contains("steig"))
{
MakeSimulatedCompound(test.Name, 1, 1, 0, 0.7f, 0.0f);
}
else
{
MakeSimulatedCompound(test.Name, 1, 1, 0, 0.7f, 0.9f);
}
Bridge.OnTestProgress(this, new TestProgressEventArgs(test, Config.Entities.Progress.Completed));
Bridge.OnTestCompleted(this, new TestCompletedEventArgs(test.Name, BatchRslts.GetTestRslt(Results.Utils.GetTestName(test.Name, 1, 1), 0)));
allResults.Info(TestResult2CsvLine(test.Name, 0)); /// Append the results to the CSV-file
for (int i = 0; i < Config.Data.WMsCount; i++)
{
TestMethods.iPerlCommunication.iPerlHead.IperlHead iPerl = ((sensPath.RegisterReaders != null) && (i < sensPath.RegisterReaders.Length))
? (sensPath.RegisterReaders[i] as TestMethods.iPerlCommunication.iPerlHead.IperlHead)
: null;
if (iPerl != null)
{
/// TODO: Reimplement
//iPerl.LastTestResult = meterRslt; /// Save this water meter test result to iPerl WM
iPerl.NominalTestFlowLph = 500.0 * (double)(test.Qfrom + test.Qto); /// Ave. + convert to liter/hour
}
}
//------------------------------------------------
Bridge.OnActivity(this, string.Format("Simulating {0}", test.Name));
//------------------------------------------------
State.Create(string.Format("{0}({1}) : Simulating", test.Method, test.Name))
.AddOperation(checkUiOp)
.EnterState();
e = StateMachine.WaitRunDevsRunOps();
Event retVal = Event.Done;
if (TestAndLogUiCmdStop(test, e)) retVal = Event.UiCmdStop;
/// Create a list with one item 'retVal' (default is Event.Done) and return it
IList<Event> retListSim = new List<Event>(1);
retListSim.Add(retVal);
return retListSim;
}
Elde.ControlBoardDev cBrd = StateMachine.ControlBoard;
/// Specific for combined meters
int[] lastWMPulses = new int[2 * Config.Data.CompoundWMsCount];
//--------------------------------
State.Create(string.Format("{0}({1}) : stopTest diverter gate etc", test.Method, test.Name))
.AddOperation(checkUiOp)
.AddOperation(cBrd.StopPreviousOp())
.EnterState();
do
{
e = StateMachine.WaitRunDevsRunOps();
if (TestAndLogUiCmdStop(test,e)) goto stopTest;
}
while (!e.Contains(Event.PreviousStopped));
LtrPerRefPulse = outPath.FlowMeter.LtrPerPulse; /// [ltr/pulse], nominal flow in [m3/h]
/// Notes:
/// float timeHr = volumeLtr / (1000.0f * targetFlow);
/// float timeSec = 3600.0f * timeHr;
/// int refPulses = (int)(timeSec * (2000.0f * targetFlow / pOut.FlowMeter.NominalFlow));
int totalPulses = (int)(test.Volume / LtrPerRefPulse + 0.5f);
processDataLoggingOp = new TBF.BenchControl.Operations.ProcessDataLoggingOp(processDataLogger, this, false);
/// Meters path is required for the following:
readRegistersOp = new Operations.ReadMoreRegistersOp(sensPath.RegisterReaders);
int repetitionNr = outerLoopMode ? outerLoopCounter : 1; /// First test: repetitionNr=1
//====================================
// Transition or SetRoute - Start
//====================================
switch (Transition(transitionBefore, TransitionContext.BeforeTest))
{
case Event.Error: goto error;
case Event.UiCmdStop: goto stopTest;
}
//====================================
loop:
/// Start the test, initialize test results
Bridge.OnTestSelected(this, new TestSelectedEventArgs(test, repetitionNr, inPath, benchPath, outPath, sensPath, (int)totalPulses));
string testName = Results.Utils.GetTestName(test.Name, test.Repeats, repetitionNr);
TestStartTime = DateTime.Now;
TestProgressEventArgs.SetEstimatedTimes(new int[] { 1, 1, 120, 30, 0, Convert.ToInt32(test.TstTime) + 15, 0, 0 });
Bridge.OnTestProgress(this, new TestProgressEventArgs(test, repetitionNr, Config.Entities.Progress.JustStarted));
Qrise = 0;
if (!test.DoDraining) /// Do not skip emptying if test.Emptying==true
{
//--------------------------------
State.Create(string.Format("{0}({1}) : Mesuring mass of water in the tank", test.Method, test.Name))
.AddOperation(checkUiOp)
.AddOperation(outPath.Scale.ReadMassOp(ref Mass))
.EnterState();
do
{
e = StateMachine.WaitRunDevsRunOps();
if (e.Contains(Event.Error)) goto error;
if (TestAndLogUiCmdStop(test,e)) goto stopTest;
}
while (!e.Contains(Event.BalanceDone));
double estimatedEndMass = Mass.Val + test.Volume;
if (estimatedEndMass < outPath.Scale.Capacity * Constants.TankFullFactor)
{
goto switching_flow_detection; /// Enough room in the tank -> skip emptying
}
}
// Empty the water tank
switch (DrainTheTank(outPath.Scale.DrainValve, outPath.Scale))
{
case Event.Error: goto error;
case Event.UiCmdStop: goto stopTest;
}
switching_flow_detection:
int flowDetectTime0 = StateMachine.Time;
int flowDetectTime = 0;
float estFlowSetTime = 100.0f;
///
/// Prepare cameras, ROI-s and measurementOperations
///
/// Find ROI-s
IList<GenericDevices.IRoi> rois = new List<GenericDevices.IRoi>();
foreach (var rr in sensPath.RegisterReaders)
{
GenericDevices.IRoi roi = rr as GenericDevices.IRoi;
if (roi != null && roi.Detected)
{
rois.Add(roi);
}
}
/// Find cameras
IList<GenericDevices.ICamera> cameras = new List<GenericDevices.ICamera>();
foreach (var roi in rois)
{
if (roi.Camera != null && !cameras.Contains(roi.Camera))
{
roi.Camera.ClearRoiParams();
cameras.Add(roi.Camera);
}
}
/// Register ROI-parameters to cameras
foreach (var roi in rois) roi.RegisterRoiToCamera();
/// Prepare measurementOperations
IList<IOperation> measureOperations = new List<IOperation>();
foreach (var camera in cameras) measureOperations.Add(camera.MeasurementOp());
//------------------------------------------------
Bridge.OnActivity(this, Strings.Switching_flow_detection);
//------------------------------------------------
State.Create(string.Format("{0}({1}) : Starting the pump", test.Method, test.Name))
.AddOperation(checkUiOp)
.AddOperations(measureOperations)
.AddOperation((inPath.Pump is GenericDevices.IPumpFM) ? (inPath.Pump as GenericDevices.IPumpFM).TurnOnOp(test.PumpPower) : null)
.AddOperation(cBrd.SetValvesOp(inPath.Pump, null))
.EnterState();
do
{
e = StateMachine.WaitRunDevsRunOps();
Bridge.OnTestProgress(this, new TestProgressEventArgs(test, repetitionNr, Config.Entities.Progress.SwitchingFlowDetection));
if (TestAndLogUiCmdStop(test,e)) goto stopTest;
}
while (!e.Contains(Event.ValvesSet));
//--------------------------------
State.Create(string.Format("{0}({1}) : Setting the initial flow", test.Method, test.Name))
.AddOperation(checkUiOp)
.AddOperations(measureOperations)
.AddOperation(outPath.RegulValve.SetFlowAndMeasureOp(outPath.FlowMeter, test.Qfrom, test.Qto, outPath.PidCoef, RefFlow, 600, (float)test.TolerRed)) /// timeout = 10 min.
.EnterState();
do
{
e = StateMachine.WaitRunDevsRunOps();
Bridge.OnTestProgress(this, new TestProgressEventArgs(test, repetitionNr, Config.Entities.Progress.SwitchingFlowDetection));
if (TestAndLogUiCmdStop(test,e)) goto stopTest;
if (e.Contains(Event.RegulValveTimeOut))
{
Bridge.OnError(this, Strings.Timeout);
goto error;
}
}
while (!e.Contains(Event.FlowReached));
//--------------------------------
switch (ReadRegistersTempPressAmbient(measureOperations, false))
{
case Event.Error: goto error;
case Event.UiCmdStop: goto stopTest;
}
//====================================
// Find the switching flow
//====================================
int flowSetTime0 = StateMachine.Time;
/// Allocate detection buffers
double[] flowsForDetection = new double[DetectionBufferSize];
double[] pulseFreqsForDetection = new double[DetectionBufferSize];
/// Current values
flowsForDetection[0] = RefFlow.Val;
pulseFreqsForDetection[0] = 0.0f;
int startTime = StateMachine.Time;
int lastTime = StateMachine.Time;
/// Detection parameters
float rvPulse = (testParams.TargetQ > (test.Qfrom + test.Qto) / 2.0f) ? 0.05f : -0.05f; // rise or fall?
rvPulse *= (100.0f * testParams.RateOfChange);
bool detected = false;
bool targetReached = false;
double detectedFlow = 0;
int detectionStartTime = StateMachine.Time;
Bridge.OnTestProgress(this, new TestProgressEventArgs(test, repetitionNr, Config.Entities.Progress.SwitchingFlowDetection));
do
{
//--------------------------------
State.Create(string.Format("{0}({1}) : Changing the RV position", test.Method, test.Name))
.AddOperation(checkUiOp)
.AddOperations(measureOperations)
.AddOperation(outPath.RegulValve.ChangeRegulValvePositionOp(rvPulse))
.EnterState();
do
{
e = StateMachine.WaitRunDevsRunOps();
Bridge.OnTestProgress(this, new TestProgressEventArgs(test, repetitionNr, Config.Entities.Progress.SwitchingFlowDetection));
if (TestAndLogUiCmdStop(test,e)) goto stopTest;
}
while (!e.Contains(Event.PositionReached));
// Last pulses are kept to calculate differences
for (int i = 0; i < 2 * Config.Data.CompoundWMsCount; i++) lastWMPulses[i] = RegisterReaders[i].WMPulses;
// Shift data in the detection buffers
for (int i = DetectionBufferSize - 2; i >= 0; i--)
{
flowsForDetection[i+1] = flowsForDetection[i];
pulseFreqsForDetection[i+1] = pulseFreqsForDetection[i];
}
switch (ReadRegistersTempPressAmbient(measureOperations, false))
{
case Event.Error: goto error;
case Event.UiCmdStop: goto stopTest;
}
int time = StateMachine.Time;
int diff = RegisterReaders[(test.Part - 1) * 2 + 1].WMPulses - lastWMPulses[(test.Part - 1) * 2 + 1];
flowsForDetection[0] = cBrd.ReferenceFreq * outPath.FlowMeter.NominalFlow / 2000.0f;
pulseFreqsForDetection[0] = (float)diff / (float)(time - lastTime);
lastTime = StateMachine.Time;
if (StateMachine.Time - detectionStartTime > 15)
{
if ((flowsForDetection[0] > 0) && (flowsForDetection[DetectionBufferSize - 1] > 0))
{
double[] flowBefore = new double[DetectionKernelSize];
double[] flowAfter = new double[DetectionKernelSize];
double[] freqBefore = new double[DetectionKernelSize];
double[] freqAfter = new double[DetectionKernelSize];
for (int i = 0; i < DetectionKernelSize; i++)
{
flowBefore[i] = flowsForDetection[DetectionBufferSize - DetectionKernelSize + i];
freqBefore[i] = pulseFreqsForDetection[DetectionBufferSize - DetectionKernelSize + i];
flowAfter[i] = flowsForDetection[i];
freqAfter[i] = pulseFreqsForDetection[i];
}
Array.Sort(flowBefore);
Array.Sort(flowAfter);
Array.Sort(freqBefore);
Array.Sort(freqAfter);
flowBefore[0] = 0;
flowAfter[0] = 0;
//freqBefore[0] = 0;
//freqAfter[0] = 0;
flowBefore[DetectionKernelSize - 1] = 0;
flowAfter[DetectionKernelSize - 1] = 0;
//freqBefore[DetectionKernelSize - 1] = 0;
//freqAfter[DetectionKernelSize - 1] = 0;
double aveFlowBefore = 0;
double aveFlowAfter = 0;
double aveFreqBefore = 0;
double aveFreqAfter = 0;
foreach (var f in flowBefore) aveFlowBefore += f;
foreach (var f in flowAfter) aveFlowAfter += f;
foreach (var f in freqBefore) aveFreqBefore += f;
foreach (var f in freqAfter) aveFreqAfter += f;
aveFlowBefore /= (double)(DetectionKernelSize - 2);
aveFlowAfter /= (double)(DetectionKernelSize - 2);
aveFreqBefore /= (double)(DetectionKernelSize);
aveFreqAfter /= (double)(DetectionKernelSize);
UiBridge.Bridge.OnLog(this, string.Format("time={0}, flow{1}, aveFlowB={2}, aveFlowA={3}, pulseFreq={4}, aveFreqB={5}, aveFreqA={6}\r\n",
time - startTime,
flowsForDetection[0].ToString("F2"),
aveFlowBefore.ToString("F2"),
aveFlowAfter.ToString("F2"),
pulseFreqsForDetection[0].ToString("F2"),
aveFreqBefore.ToString("F2"),
aveFreqAfter.ToString("F2")));
//detectedFlow = (aveFlowBefore + aveFlowAfter) / 2.0f;
detectedFlow = aveFlowBefore;
if (rvPulse > 0)
{
detected = (aveFreqAfter < aveFreqBefore * (1.0f - testParams.DetectionThreshold));
targetReached = ((aveFlowAfter + aveFlowBefore) / 2.0f) > testParams.TargetQ;
}
else
{
detected = (aveFreqAfter > aveFreqBefore * (1.0f + testParams.DetectionThreshold));
targetReached = ((aveFlowAfter + aveFlowBefore) / 2.0f) < testParams.TargetQ;
}
}
}
}
while (!detected && !targetReached);
Qrise = detectedFlow;
UiBridge.Bridge.OnLog(this, string.Format("detected flow={0}\r\n", detectedFlow.ToString("F2")));
int flowSetTime1 = StateMachine.Time;
Bridge.OnProcessData(this, new ProcessDataEventArgs(test, repetitionNr, Config.Entities.Progress.FlowSetting));
Bridge.OnTestProgress(this, new TestProgressEventArgs(test, repetitionNr, Config.Entities.Progress.FlowSetting));
//--------------------------------
//State.Create(string.Format("{0}({1}) : Flow sensitivity detected", test.Method, test.Name))
TestEndTime = DateTime.Now;
//------------------------------------------------
Bridge.OnActivity(this, Strings.Test_completed);
//------------------------------------------------
State.Create(string.Format("{0}({1}) : {2}", test.Method, test.Name, Strings.Stop_the_pump))
.AddOperation(checkUiOp)
.AddOperation((inPath != null && inPath.Pump is GenericDevices.IPumpFM) ? (inPath.Pump as GenericDevices.IPumpFM).TurnOffOp() : null)
.AddOperation(cBrd.SetValvesOp(null, inPath.Pump))
.AddOperation(cBrd.UpdateTankWeightOp())
.EnterState();
do
{
e = StateMachine.WaitRunDevsRunOps();
if (TestAndLogUiCmdStop(test,e)) goto stopTest;
}
while (!e.Contains(Event.ValvesSet));
//--------------------------------
State.Create(string.Format("{0}({1}) : Stopping diverter, gate, etc.", test.Method, test.Name))
.AddOperation(checkUiOp)
.AddOperation(cBrd.StopPreviousOp())
.EnterState();
do
{
e = StateMachine.WaitRunDevsRunOps();
if (TestAndLogUiCmdStop(test,e)) goto stopTest;
}
while (!e.Contains(Event.PreviousStopped));
/// Make sure the CycleBeginForm is closed so that water meter data (s/n) can be copied into results
if (UIFlowControl.Stop == WaitBeginFormClosed()) goto stopTest;
///
/// Populate TestResult data entity with data
///
Results.Entities.TestRslt tstRslt = BatchRslts.GetTestRslt(testName, test.Part);
if (tstRslt != null)
{
UpdateTempPressDensAmb(tstRslt);
/// Main results
tstRslt.StartTime = TestStartTime;
tstRslt.EndTime = TestEndTime;
tstRslt.FlowSetTime = flowSetTime1 - flowSetTime0;
tstRslt.TestTime = cBrd.TTime; /// [s] measurement time
tstRslt.PulsesMaster = 0; /// Pulses of the master flow meter (test total)
tstRslt.MassStartRaw = 0;
tstRslt.MassStart = 0;
tstRslt.MassEndRaw = 0;
tstRslt.MassEnd = 0;
tstRslt.FlowMass = 0;
tstRslt.FlowVolume = 0;
tstRslt.Buoyancy = Formulas.Buoyancy();
tstRslt.VolumeCTV = 0;
tstRslt.VolumeMaster = 0;
tstRslt.ConstMaster = 0;
tstRslt.ErrorMaster = 0;
tstRslt.FlowMean = (float)RefFlowStat.Average;
tstRslt.FlowStart = (float)RefFlowStat.First;
tstRslt.FlowEnd = (float)RefFlowStat.Last;
tstRslt.FlowMin = (float)RefFlowStat.Min;
tstRslt.FlowMax = (float)RefFlowStat.Max;
tstRslt.DiverterStart = switchTimeStart;
tstRslt.DiverterEnd = switchTimeEnd;
tstRslt.ErrorFlagsMd = (ErrorFlagsComp != null) ? (sbyte)ErrorFlagsComp.Mode : (sbyte)0;
tstRslt.ErrorFlags = (ErrorFlagsComp != null) ? ErrorFlagsComp.GetErrorFlags(tstRslt, true, false, switchTimeStart, switchTimeEnd) : 0;
for (int i = 0; i < BatchRslts.WMPositionsCount; i++)
{
Results.Entities.MeterTestRslt meterRslt = BatchRslts.GetMeterTestRslt(testName, i, Config.Entities.CompoundMeterId.Single);
GenericDevices.IRegisterReader regReader = sensPath.RegisterReaders[i];
if (meterRslt != null && regReader != null)
{
meterRslt.PulsesPerLiter = regReader.PulsesPerLtr;
meterRslt.Passed = (Qrise <= test.Qto) && (tstRslt.ErrorFlags == 0 || tstRslt.ErrorFlagsMode() != Config.Entities.ErrorFlagsMode.On);
meterRslt.TestDone = true;
tstRslt.TestDone = true;
if (Qrise != 0)
{
BatchRslts.WaterMeters[i].QRise = Qrise;
}
BatchRslts.WaterMeters[i].QFall = 0;
}
}
tstRslt.Components = Results.Entities.Components
.UpdateList(BatchRslts.ComponentsList,
new Results.Entities.Components((BenchInfo != null) ? BenchInfo.TestBenchId : 1,
(BenchInfo != null) ? BenchInfo.TestBenchName : "testbench",
inPath.Pump != null ? inPath.Pump.Name : string.Empty,
outPath.FlowMeter != null ? outPath.FlowMeter.Name : string.Empty,
outPath.Scale != null ? outPath.Scale.Name : string.Empty,
outPath.RegulValve != null ? outPath.RegulValve.Name : string.Empty,
outPath.Diverter != null ? outPath.Diverter.Name : string.Empty));
/// Update water meter error flags
if (ErrorFlagsComp != null)
{
for (int i = 0; i < BatchRslts.WMPositionsCount; i++)
{
if (BatchRslts.WaterMeters[i] != null)
{
BatchRslts.WaterMeters[i].ErrorFlags = ErrorFlagsComp.GetWMtrErrorFlags(BatchRslts.WaterMeters[i].MeterTestRslts);
}
}
}
/// Update results
Bridge.OnTestCompleted(this, new TestCompletedEventArgs(testName, tstRslt));
}
Bridge.OnTestProgress(this, new TestProgressEventArgs(test, repetitionNr, Config.Entities.Progress.TransitionAfter));
/// Append the results to the CSV-file
allResults.Info(TestResult2CsvLine(testName, test.Part));
if (!outerLoopMode && (++repetitionNr <= test.Repeats))
{
goto loop;
}
///----------------------///
/// Quit this sequence ///
///----------------------///
/// Stop the pump
State.Create(string.Format("{0}({1}) : Test(s) completed -> Stopping the pump", test.Method, test.Name))
.AddOperation(checkUiOp)
.AddOperation(cBrd.SetValvesOp(null, inPath.Pump))
.AddOperation((inPath != null && inPath.Pump is GenericDevices.IPumpFM) ? (inPath.Pump as GenericDevices.IPumpFM).TurnOffOp() : null)
.EnterState();
do {
e = StateMachine.WaitRunDevsRunOps();
if (e.Contains(Event.Error)) goto error;
}
while (!e.Contains(Event.ValvesSet) || ((inPath.Pump is GenericDevices.IPumpFM) && !e.Contains(Event.TurnPumpOnOffDone)));
/// Transition or SetRoute - End
switch (Transition(transitionAfter, TransitionContext.AfterTest))
{
case Event.Error: goto error;
case Event.UiCmdStop: goto stopTest;
}
Bridge.OnTestProgress(this, new TestProgressEventArgs(test, repetitionNr, Config.Entities.Progress.Completed));
/// Create the return value - a list with one event Event.Done - and return
IList<Event> retval1 = new List<Event>(1);
retval1.Add(Event.Done);
return retval1;
//====================================
stopTest:
State.Create(string.Format("{0}({1}) : User selected STOP -> Closing the valves", test.Method, test.Name))
.AddOperation(checkUiOp)
.AddOperation((inPath != null && inPath.Pump is GenericDevices.IPumpFM) ? (inPath.Pump as GenericDevices.IPumpFM).TurnOffOp() : null)
.AddOperation(cBrd.SetValvesOp(StateMachine.DefaultValvesOpen, StateMachine.DefaultValvesClose))
.EnterState();
do
{
e = StateMachine.WaitRunDevsRunOps();
if (e.Contains(Event.Error)) goto error;
}
while (!e.Contains(Event.ValvesSet));
Bridge.OnTestProgress(this, new TestProgressEventArgs(test, 1, Config.Entities.Progress.Aborted));
IList<Event> retval2 = new List<Event>(1);
retval2.Add(Event.UiCmdStop);
return retval2;
//====================================
error:
State.Create(string.Format("{0}({1}) : close_before_error", test.Method, test.Name))
.AddOperation(checkUiOp)
.AddOperation((inPath != null && inPath.Pump is GenericDevices.IPumpFM) ? (inPath.Pump as GenericDevices.IPumpFM).TurnOffOp() : null)
.AddOperation(cBrd.SetValvesOp(StateMachine.DefaultValvesOpen, StateMachine.DefaultValvesClose))
.EnterState();
do
{
e = StateMachine.WaitRunDevsRunOps();
if (e.Contains(Event.Error)) goto error;
}
while (!e.Contains(Event.ValvesSet));
Bridge.OnTestProgress(this, new TestProgressEventArgs(test, 1, Config.Entities.Progress.Aborted));
IList<Event> retval3 = new List<Event>(1);
retval3.Add(Event.Error);
return retval3;
}
}
}

View File

@ -0,0 +1,37 @@
///
/// Copyright (c) 2017 Sensus Metering Systems
///
using System;
using System.Collections.Generic;
using log4net;
using Config.Entities;
using TBF.BenchControl;
namespace TBF.BenchControl.TestMethods.SensitivityTest
{
public class TestMethod : ComponentBase, GenericDevices.ITestMethod
{
private static readonly ILog log = LogManager.GetLogger(typeof(TestMethod));
public override string ToString() { return string.Format("TestMethods.CombinedWithDetection({0})", Cfg.ToString(1)); }
readonly TestMethodCfg testMethodCfg;
public bool CanTest(MetersKind meters) { return meters == MetersKind.Single; }
public TestMethod()
{
}
public TestMethod(Generic.IComponentCfg cfg)
: base(cfg)
{
testMethodCfg = cfg as TestMethodCfg;
log.Debug(this.ToString());
}
public IList<Event> Execute(Test test, bool outerLoopMode, int outerLoopCounter)
{
return (new SensitivityTestSeq()).Execute(test, outerLoopMode, outerLoopCounter, testMethodCfg.TestParams, DebugLevel);
}
}
}

View File

@ -0,0 +1,50 @@
///
/// Copyright (c) 2017 Sensus Metering Systems
///
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
using Config.Entities;
using TBF.BenchControl.Generic;
namespace TBF.BenchControl.TestMethods.SensitivityTest
{
public class TestMethodCfg : ComponentCfgBase, Generic.IComponentCfg
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(TestMethodCfg) })[0];
protected override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl() { return new TestMethodCfgCtrl(); }
/// <summary> Test parameters </summary>
[XmlIgnore]
public SensitivityTestParams TestParams;
public override IParamsProvider GetTestParams() { return TestParams; }
public override IParamsProvider CreateTestParams(Test test)
{
SensitivityTestParams testParams = new SensitivityTestParams(true);
testParams.UpdateTestParams(Name, test);
return testParams;
}
/// Private parameterless constructor invoked by all other (public) constructors
TestMethodCfg()
{
TestParams = new SensitivityTestParams(true);
}
public TestMethodCfg(string name, IComponentFactory factory)
: this()
{
Name = name;
ParentName = string.Empty;
Factory = factory;
}
public string ToString(int i)
{
return string.Format("Name={0}", Name);
}
}
}

View File

@ -0,0 +1,71 @@
///
/// Copyright (c) 2017 Sensus Metering Systems
///
using System;
using System.Windows.Forms;
using log4net;
using TBF.BenchControl.Generic;
namespace TBF.BenchControl.TestMethods.SensitivityTest
{
public partial class TestMethodCfgCtrl : UserControl, IComponentCfgCtrl
{
static readonly ILog log = LogManager.GetLogger(typeof(TestMethodCfgCtrl));
public bool ShowMore { get { return false; } }
TestMethodCfg config;
public IComponentCfg Config
{
get { return config as IComponentCfg; }
set
{
config = value as TestMethodCfg;
Redraw();
}
}
public TestMethodCfgCtrl()
{
InitializeComponent();
}
private void EntryFormCfgCtrl_Load(object sender, EventArgs e)
{
Redraw();
}
public void Closing()
{
}
void Redraw()
{
if (config == null) return; /// Control was not loaded, settings were not changed
classNameLabel.Text = config.Factory.ClassName;
nameTextBox.Text = config.Name;
}
public void Unlock()
{
nameTextBox.Enabled = true;
}
public CfgUpdateFlags VerifyCfg(ref string message)
{
CfgUpdateFlags flags = CfgUpdateFlags.None;
return flags;
}
public CfgUpdateFlags UpdateCfg()
{
CfgUpdateFlags flags = CfgUpdateFlags.RestartRqrd;
if (config == null) return CfgUpdateFlags.Error; /// Control was not loaded, settings were not changed
config.Name = nameTextBox.Text;
return flags;
}
}
}

View File

@ -0,0 +1,86 @@
///
/// Copyright (c) 2017 Sensus Metering Systems
///
namespace TBF.BenchControl.TestMethods.SensitivityTest
{
partial class TestMethodCfgCtrl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.nameTextBox = new System.Windows.Forms.TextBox();
this.nameLabel = new System.Windows.Forms.Label();
this.classNameLabel = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// nameTextBox
//
this.nameTextBox.Enabled = false;
this.nameTextBox.Location = new System.Drawing.Point(137, 57);
this.nameTextBox.Name = "nameTextBox";
this.nameTextBox.Size = new System.Drawing.Size(130, 20);
this.nameTextBox.TabIndex = 5;
//
// nameLabel
//
this.nameLabel.AutoSize = true;
this.nameLabel.Location = new System.Drawing.Point(27, 60);
this.nameLabel.Name = "nameLabel";
this.nameLabel.Size = new System.Drawing.Size(35, 13);
this.nameLabel.TabIndex = 4;
this.nameLabel.Text = "Name";
//
// classNameLabel
//
this.classNameLabel.AutoSize = true;
this.classNameLabel.Location = new System.Drawing.Point(134, 33);
this.classNameLabel.Name = "classNameLabel";
this.classNameLabel.Size = new System.Drawing.Size(83, 13);
this.classNameLabel.TabIndex = 3;
this.classNameLabel.Text = "ComonentName";
//
// BasicPrinterCfgCtrl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.nameTextBox);
this.Controls.Add(this.nameLabel);
this.Controls.Add(this.classNameLabel);
this.Name = "BasicPrinterCfgCtrl";
this.Size = new System.Drawing.Size(300, 200);
this.Load += new System.EventHandler(this.EntryFormCfgCtrl_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox nameTextBox;
private System.Windows.Forms.Label nameLabel;
private System.Windows.Forms.Label classNameLabel;
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,26 @@
///
/// Copyright (c) 2017 Sensus Metering Systems
///
using System.Collections.Generic;
using TBF.BenchControl.Generic;
namespace TBF.BenchControl.TestMethods.SensitivityTest
{
public class TestMethodFactory : IComponentFactory
{
public string ClassName { get { return this.GetType().Namespace.Substring(17) + ".Single"; } }
public void ResetStaticProperties() { TestMethod.ResetStaticProperties(); }
public IComponent DummyComponent() { return new TestMethod(); }
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new TestMethod(cfg); }
public IComponentCfg DefaultConfig() { return new TestMethodCfg(this.GetType().Namespace.Substring(29), this); }
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
{
return ComponentCfgBase.CreateFromDbEntity(TestMethodCfg.Serializer, component, this);
}
}
}

View File

@ -982,6 +982,17 @@
<Compile Include="BenchControl\TestMethods\OuterLoop\End\Factory.cs" />
<Compile Include="BenchControl\TestMethods\OuterLoop\Start\Component.cs" />
<Compile Include="BenchControl\TestMethods\OuterLoop\Start\Factory.cs" />
<Compile Include="BenchControl\TestMethods\SensitivityTest\SensitivityTestSeq.cs" />
<Compile Include="BenchControl\TestMethods\SensitivityTest\SensitivityTestParams.cs" />
<Compile Include="BenchControl\TestMethods\SensitivityTest\TestMethod.cs" />
<Compile Include="BenchControl\TestMethods\SensitivityTest\TestMethodCfg.cs" />
<Compile Include="BenchControl\TestMethods\SensitivityTest\TestMethodCfgCtrl.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="BenchControl\TestMethods\SensitivityTest\TestMethodCfgCtrl.designer.cs">
<DependentUpon>TestMethodCfgCtrl.cs</DependentUpon>
</Compile>
<Compile Include="BenchControl\TestMethods\SensitivityTest\TestMethodFactory.cs" />
<Compile Include="BenchControl\Various\ErrorFlags\Factory.cs" />
<Compile Include="BenchControl\Various\ErrorFlags\TestParams.cs" />
<Compile Include="BenchControl\Various\ErrorFlags\Errors.cs" />
@ -2261,6 +2272,9 @@
<EmbeddedResource Include="BenchControl\TestMethods\PMaxTest\TestMethodCfgCtrl.resx">
<DependentUpon>TestMethodCfgCtrl.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="BenchControl\TestMethods\SensitivityTest\TestMethodCfgCtrl.resx">
<DependentUpon>TestMethodCfgCtrl.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="BenchControl\Various\ErrorFlags\ErrorsCfgCtrl.resx">
<DependentUpon>ErrorsCfgCtrl.cs</DependentUpon>
</EmbeddedResource>