Uni.FlowMetersInParallel added, ver. 3.1.1617

This commit is contained in:
Milan Hanajik
2021-03-29 16:23:21 +02:00
parent 79e1fff45e
commit 68ca5c4901
11 changed files with 473 additions and 12 deletions
+2 -2
View File
@@ -31,7 +31,7 @@ namespace TBF.Rig.Uni.FlowMeter
public int Idx1; /// 0 /// 1..7, (DEWA300 : I1+I2=48, I1+I3=80, I2_I3=96, I1+I2+I3=112)
public double NominalFlow; /// 1 /// Nominal flow in m3/h at nominal output frequency (typ. 2000 Hz)
public string MsrdFormat { get; set; } /// 3
public Unit MsrdUnit { get; set; } /// 2
public Unit MsrdUnit { get; set; } /// 2
public double MsrdValLimLo { get; set; } /// 4
public double MsrdValLimHi { get; set; } /// 5
public Unit TempUnit; /// 6
@@ -273,7 +273,7 @@ namespace TBF.Rig.Uni.FlowMeter
Sz = Sz.M;
Factory = factory;
Name = "FlowMeter";
Name = "I";
ParentName = "UniCB";
InitializeAll();
}
+5 -4
View File
@@ -4,6 +4,7 @@
using System;
using log4net;
using TBF.Boxes;
using TBF.Rig.GenericDevices;
namespace TBF.Rig.Uni.FlowMeter
{
@@ -13,7 +14,7 @@ namespace TBF.Rig.Uni.FlowMeter
public override string ToString() { return string.Format("ReadFlowOp({0},.,.,{1})", flowMeter.Idx1, eventDone); }
/// Set by the constructor
readonly FlowMeter flowMeter;
readonly IFlowMeter flowMeter;
readonly DoubleBox flowBox;
readonly Event eventDone;
@@ -23,7 +24,7 @@ namespace TBF.Rig.Uni.FlowMeter
/// <param name="flowMeter">Flow meter reference</param>
/// <param name="flowBox">Reference to the measured flow variable, value is in bar</param>
/// <param name="eventDone">Event to be returned by Run() when completed OK</param>
public ReadFlowOp(FlowMeter flowMeter, ref DoubleBox flowBox, Event eventDone)
public ReadFlowOp(IFlowMeter flowMeter, ref DoubleBox flowBox, Event eventDone)
{
if (flowMeter == null) throw new ArgumentNullException();
@@ -34,7 +35,7 @@ namespace TBF.Rig.Uni.FlowMeter
log.Debug(this.ToString());
}
public ReadFlowOp(FlowMeter flowMeter, ref DoubleBox flowBox)
public ReadFlowOp(IFlowMeter flowMeter, ref DoubleBox flowBox)
: this(flowMeter, ref flowBox, Event.FlowMeasurementDone)
{
}
@@ -50,7 +51,7 @@ namespace TBF.Rig.Uni.FlowMeter
{
if (flowMeter.MsrmntAvailable)
{
flowBox.Val = flowMeter.ReadFlow();
if (flowBox != null) flowBox.Val = flowMeter.ReadFlow();
return eventDone;
}
@@ -0,0 +1,27 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System.Collections.Generic;
using TBF.Rig.Generic;
namespace TBF.Rig.Uni.FlowMetersInParallel
{
public class Factory : IComponentFactory
{
public string ClassName { get { return "FlowMetersInParallel"; } }
public override string ToString() { return ClassName; }
public void ResetStaticProperties() { FlowMeter.ResetStaticProperties(); }
public IComponent DummyComponent() { return new FlowMeter(); }
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new FlowMeter(cfg, components); }
public IComponentCfg DefaultConfig() { return new FlowMeterCfg(this); }
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
{
return ComponentCfgBase.CreateFromDbEntity(FlowMeterCfg.Serializer, component, this);
}
}
}
@@ -0,0 +1,160 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using log4net;
using TBF.Boxes;
using TBF.Rig.ControlBoard.Uni;
using TBF.Rig.GenericDevices;
namespace TBF.Rig.Uni.FlowMetersInParallel
{
public class FlowMeter : ComponentBase, IFlowMeter
{
private static readonly ILog log = LogManager.GetLogger(typeof(FlowMeter));
public override string ToString() { return string.Format("FlowMeter({0})", Cfg.ToString(-1)); }
readonly FlowMeterCfg flowMeterCfg;
readonly UniCB uniCB;
readonly IFlowMeter flowMeter1;
readonly IFlowMeter flowMeter2;
readonly IFlowMeter flowMeter3;
readonly double nominalFlow;
readonly double ltrPerPulse;
readonly int flowMetersCount;
readonly int flowMetersBitfield;
public int Idx1 { get { return flowMetersBitfield; } }
public double NominalFlow { get { return nominalFlow; } }
public double LtrPerPulse { get { return ltrPerPulse; } }
double[] refFreq; /// 0..sum, 1..I11, 2..I12, 3..I13
int[] refPulses;
public double LtrPerPulseCorrected(double flow, int rangeIx)
{
log.DebugFormat("LtrPerPulseCorrected({0}, {1}) started", flow, rangeIx);
refFreq[0] = uniCB.RefFrequency;
refFreq[1] = uniCB.RefFrequency1;
refFreq[2] = uniCB.RefFrequency2;
refFreq[3] = uniCB.RefFrequency3;
log.DebugFormat("refFreq[] = ({0}, {1}, {2}, {3})", refFreq[0], refFreq[1], refFreq[2], refFreq[3]);
refPulses[0] = uniCB.RefPulses;
refPulses[1] = uniCB.RefPulses1;
refPulses[2] = uniCB.RefPulses2;
refPulses[3] = uniCB.RefPulses3;
log.DebugFormat("refPulses[] = ({0}, {1}, {2}, {3})", refPulses[0], refPulses[1], refPulses[2], refPulses[3]);
double flow1, flow2, flow3;
double contribution1, contribution2, contribution3;
if (refPulses[0] != 0)
{
/// Division by zero prevented inside this 'if'
double ltrPerPulseCorrected = 0;
if (flowMeter1 != null)
{
double ratio = (double)refPulses[flowMeter1.Idx1] / (double)refPulses[0];
flow1 = flow * ratio;
contribution1 = flowMeter1.LtrPerPulseCorrected(flow1, rangeIx) * ratio;
ltrPerPulseCorrected += contribution1;
log.DebugFormat("flowmeter1 = {0}, flow1 = {1}, contribution1 = {2}", flowMeter1.Name, flow1, contribution1);
}
if (flowMeter2 != null)
{
double ratio = (double)refPulses[flowMeter2.Idx1] / (double)refPulses[0];
flow2 = flow * ratio;
contribution2 = flowMeter2.LtrPerPulseCorrected(flow2, rangeIx) * ratio;
ltrPerPulseCorrected += contribution2;
log.DebugFormat("flowmeter2 = {0}, flow2 = {1}, contribution2 = {2}", flowMeter2.Name, flow2, contribution2);
}
if (flowMeter3 != null)
{
double ratio = (double)refPulses[flowMeter3.Idx1] / (double)refPulses[0];
flow3 = flow * ratio;
contribution3 = flowMeter3.LtrPerPulseCorrected(flow3, rangeIx) * ratio;
ltrPerPulseCorrected += contribution3;
log.DebugFormat("flowmeter3 = {0}, flow3 = {1}, contribution3 = {2}", flowMeter3.Name, flow3, contribution3);
}
log.DebugFormat("LtrPerPulseCorrected() returns {0}", ltrPerPulseCorrected);
return ltrPerPulseCorrected;
}
else
{
log.DebugFormat("LtrPerPulseCorrected() returns 1");
return 1;
}
}
public bool MsrmntAvailable { get { return true; } }
public double MeasuredVal { get { return ReadFlow(); } }
public string AltString { get { return "Invalid format"; } }
public FlowMeter()
{
refFreq = new double[4];
refPulses = new int[4];
}
public FlowMeter(Generic.IComponentCfg cfg, IList<Generic.IComponent> components)
: base(cfg)
{
flowMeterCfg = cfg as FlowMeterCfg;
uniCB = TbfComponents.FindComponent(cfg.ParentName, components) as UniCB;
if (uniCB == null) throw new Exception("Cannot find " + Name + " parent");
if (!string.IsNullOrEmpty(flowMeterCfg.Flowmeter1)) flowMeter1 = TbfComponents.FindComponent(flowMeterCfg.Flowmeter1, components) as IFlowMeter;
if (!string.IsNullOrEmpty(flowMeterCfg.Flowmeter2)) flowMeter2 = TbfComponents.FindComponent(flowMeterCfg.Flowmeter2, components) as IFlowMeter;
if (!string.IsNullOrEmpty(flowMeterCfg.Flowmeter3)) flowMeter3 = TbfComponents.FindComponent(flowMeterCfg.Flowmeter3, components) as IFlowMeter;
nominalFlow = 0;
flowMetersCount = 0;
flowMetersBitfield = 0;
if (flowMeter1 != null) { nominalFlow += flowMeter1.NominalFlow; flowMetersBitfield |= (8 << flowMeter1.Idx1); flowMetersCount++; }
if (flowMeter2 != null) { nominalFlow += flowMeter2.NominalFlow; flowMetersBitfield |= (8 << flowMeter2.Idx1); flowMetersCount++; }
if (flowMeter3 != null) { nominalFlow += flowMeter3.NominalFlow; flowMetersBitfield |= (8 << flowMeter3.Idx1); flowMetersCount++; }
if (flowMetersCount == 0) throw new Exception("Missing flowmeters");
ltrPerPulse = nominalFlow / (flowMetersCount * 7200.0); /// Nominal freq. is flowMetersCount * 2000 Hz (2000, 4000 or 6000 Hz)
refFreq = new double[4];
refPulses = new int[4];
log.Warn(this.ToString());
}
public double ReadFlow()
{
/// TODO
return 0;
}
public double ReadFrequency() { return uniCB.RefFrequency; }
/// <summary>
/// Events: FlowDone, Error
/// </summary>
/// <param name="flow">Reference to a variable for the flow in Bar</param>
/// <returns>ReadFlowOp instance reference casted to IOperaton</returns>
public IOperation ReadFlowOp(ref DoubleBox flow)
{
return new ReadFlowOp(this, ref flow);
}
/// <summary>
/// Events: flowDone, Error
/// </summary>
/// <param name="flow">Reference to a variable for the flow in Bar</param>
/// <param name="flowDone">Event returned when measurement done</param>
/// <returns>ReadFlowOp instance reference casted to IOperaton</returns>
public IOperation ReadFlowOp(ref DoubleBox flow, Event flowDone)
{
return new ReadFlowOp(this, ref flow, flowDone);
}
}
}
@@ -0,0 +1,200 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Serialization;
using Config;
using Config.Entities;
using SchematicDrawing;
using TBF.Rig.Generic;
namespace TBF.Rig.Uni.FlowMetersInParallel
{
public class FlowMeterCfg : ComponentCfgBase, IChildComponentCfg, Config.Entities.IParamsProvider
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(FlowMeterCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities)
{
flowMeters = cmpntEntities.Where(x => x.ClassName == "FlowMeter");
var parents = cmpntEntities.Where(x => x.ClassName == "ControlBoard.Uni");
return new Configs.ParamsProvider.ComponentCfgCtrl(this, parents);
}
///
/// Serialized parameters
///
public string Flowmeter1; /// 0 Flowmeter component name or string.Empty
public string Flowmeter2; /// 1 - ' ' -
public string Flowmeter3; /// 2 - ' ' -
public string MsrdFormat { get; set; } /// 3
public Unit MsrdUnit { get; set; } /// 4
public double MsrdValLimLo { get; set; } /// 5
public double MsrdValLimHi { get; set; } /// 6
/// Schematic drawing info
public Shape Shape { get; set; }
public int X { get; set; }
public int Y { get; set; }
public Sz Sz { get; set; }
public Orient Orient { get; set; }
public bool Flip { get; set; }
public int LblX { get; set; }
public int LblY { get; set; }
public Orient LblOrient { get; set; }
public int MsrdX { get; set; }
public int MsrdY { get; set; }
public Orient MsrdOrient { get; set; }
[XmlIgnore]
public IList<GNode> GNodes { get; set; }
private IEnumerable<Config.Entities.Component> flowMeters;
/// Private parameterless constructor invoked by all other (public) constructors
FlowMeterCfg()
{
GNodes = new List<GNode>();
}
public FlowMeterCfg(IComponentFactory factory)
: this()
{
Shape = Shape.FlowM;
Sz = Sz.M;
Name = "I11+I12";
Factory = factory;
ParentName = "UniCB";
InitializeAll();
}
public string ComponentName { get { return Name; } }
public void InitializeAll()
{
Flowmeter1 = "I11";
Flowmeter2 = "I12";
Flowmeter3 = string.Empty;
MsrdFormat = "{0:F3} m2/h";
MsrdUnit = Unit.m3ph;
MsrdValLimLo = 0;
MsrdValLimHi = 1000;
}
string[] paramNames = new string[]
{
"Flow meter 1", /// 0
"Flow meter 2", /// 1
"Flow meter 3", /// 2
"Display format", /// 3
"Unit of flow on a display", /// 4
"Flow limit Lo", /// 5
"Flow limit Hi", /// 6
};
public string ParamName(int i) { return paramNames[i]; }
public int ParamsCount() { return paramNames.Length; }
public ICollection<string> ParamValues(int i)
{
switch (i)
{
case 0:
case 1:
case 2:
if (flowMeters == null) return null;
var fmtrs = new List<string>();
foreach (var fmtr in flowMeters) fmtrs.Add(fmtr.Name);
fmtrs.Add("---");
return fmtrs;
case 4:
return new string[] { "m3/h", "l/h" };
default:
return null;
}
}
public string ToString(int i)
{
switch (i)
{
case 0: return Flowmeter1;
case 1: return Flowmeter2;
case 2: return Flowmeter3;
case 3: return MsrdFormat;
case 4: return MsrdUnit.ToDescription();
case 5: return MsrdValLimLo.ToString();
case 6: return MsrdValLimHi.ToString();
default:
return string.Format("Name={0} {1} {2} {3} fmt={4} unit={5} Lo={6} Hi={7}",
Name, Flowmeter1, Flowmeter2, Flowmeter3,
MsrdFormat, MsrdUnit.ToDescription(), MsrdValLimLo, MsrdValLimHi);
}
}
public CfgUpdateFlags UpdateParam(int i, string str)
{
switch (i)
{
case 0: Flowmeter1 = (str != "---") ? str : string.Empty; return CfgUpdateFlags.RestartRqrd;
case 1: Flowmeter2 = (str != "---") ? str : string.Empty; return CfgUpdateFlags.RestartRqrd;
case 2: Flowmeter3 = (str != "---") ? str : string.Empty; return CfgUpdateFlags.RestartRqrd;
case 3: MsrdFormat = str; return CfgUpdateFlags.RestartRqrd;
case 4: MsrdUnit = (str == "l/h") ? Unit.lph : Unit.m3ph; return CfgUpdateFlags.RestartRqrd;
case 5: MsrdValLimLo = TBF.Utils.ParseUDouble(str); return CfgUpdateFlags.RestartRqrd;
case 6: MsrdValLimHi = TBF.Utils.ParseUDouble(str); return CfgUpdateFlags.RestartRqrd;
default:
return CfgUpdateFlags.None;
}
}
public bool ValidateParam(int i, string str, out string message)
{
message = string.Empty;
switch (i)
{
case 0:
case 1:
case 2:
case 4:
if (ParamValues(i).Contains(str)) return true;
break;
default:
message = "Invalid index";
return false;
}
message = ParamName(i) + " is invalid";
return false;
}
void CopyContentTo(FlowMeterCfg prms)
{
prms.Flowmeter1 = this.Flowmeter1;
prms.Flowmeter2 = this.Flowmeter2;
prms.Flowmeter3 = this.Flowmeter3;
prms.MsrdFormat = this.MsrdFormat;
prms.MsrdUnit = this.MsrdUnit;
prms.MsrdValLimLo = this.MsrdValLimLo;
prms.MsrdValLimHi = this.MsrdValLimHi;
}
public Config.Entities.IParamsProvider Clone()
{
FlowMeterCfg pars = new FlowMeterCfg();
CopyContentTo(pars);
return pars;
}
public bool UpdateEmbeddedDbEntity()
{
return true; /// =OK, do nothing
}
}
}
@@ -0,0 +1,64 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
using log4net;
using TBF.Boxes;
using TBF.Rig.GenericDevices;
namespace TBF.Rig.Uni.FlowMetersInParallel
{
public class ReadFlowOp : IOperation
{
private static readonly ILog log = LogManager.GetLogger(typeof(ReadFlowOp));
public override string ToString() { return string.Format("ReadFlowOp({0},.,.,{1})", flowMeter.Idx1, eventDone); }
/// Set by the constructor
readonly IFlowMeter flowMeter;
readonly DoubleBox flowBox;
readonly Event eventDone;
/// <summary>
/// Events: FlowInDone, FlowOutDone or Error
/// </summary>
/// <param name="flowMeter">Flow meter reference</param>
/// <param name="flowBox">Reference to the measured flow variable, value is in bar</param>
/// <param name="eventDone">Event to be returned by Run() when completed OK</param>
public ReadFlowOp(IFlowMeter flowMeter, ref DoubleBox flowBox, Event eventDone)
{
if (flowMeter == null) throw new ArgumentNullException();
this.flowMeter = flowMeter;
this.eventDone = eventDone;
this.flowBox = flowBox;
log.Debug(this.ToString());
}
public ReadFlowOp(IFlowMeter flowMeter, ref DoubleBox flowBox)
: this(flowMeter, ref flowBox, Event.FlowMeasurementDone)
{
}
/// <summary>Start this operation</summary>
public void Start() { }
/// <summary>Run this operation</summary>
/// <returns>
/// Event.FlowInDone or Event.FlowOutDone
/// </returns>
public Event Run()
{
if (flowMeter.MsrmntAvailable)
{
if (flowBox != null) flowBox.Val = flowMeter.ReadFlow();
return eventDone;
}
return Event.Error;
}
/// <summary>Stop this operation</summary>
public void Stop() { }
}
}
+1 -1
View File
@@ -90,7 +90,7 @@ namespace TBF.Rig.Uni.RegValveAnalog
{
this.flowMeterId = (flowMeter as Uni.FlowMeter.FlowMeter).Idx1;
}
else if (flowMeter is Elde.FlowMeterTwins.FlowMeter)
else if (flowMeter is Uni.FlowMetersInParallel.FlowMeter)
{
this.flowMeterId = 0;
}
+1 -1
View File
@@ -95,7 +95,7 @@ namespace TBF.Rig.Uni.RegValveTandem
this.flowMeterNr = (flowMeter as Uni.FlowMeter.FlowMeter).Idx1;
this.nominalFlow = flowMeter.NominalFlow;
}
else if (flowMeter is Elde.FlowMeterTwins.FlowMeter)
else if (flowMeter is Uni.FlowMetersInParallel.FlowMeter)
{
this.flowMeterNr = 0;
this.nominalFlow = flowMeter.NominalFlow;