Uni.RegValveAnalog : Initial implementation for UNI, ver. 3.5.2015

This commit is contained in:
Milan Hanajik
2023-02-13 09:54:05 +01:00
parent d29a425880
commit ed21db65c3
16 changed files with 283 additions and 436 deletions
+37 -15
View File
@@ -1,5 +1,5 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
/// Copyright (c) 2023 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
@@ -15,15 +15,18 @@ namespace TBF.Rig.Uni.RegValveAnalog
private static readonly ILog log = LogManager.GetLogger(typeof(RegValve));
public override string ToString() { return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); }
readonly RegValveCfg regValveCfg;
public ValveCategory Category { get { return regValveCfg.Category; } }
public int Idx1 { get { return regValveCfg.Idx1; } } /// 1..7
public int StableTime { get { return regValveCfg.StableTime; } } /// 0=200ms, step=50ms, max. 1500ms (max.26)
public int FlowStableSec { get { return regValveCfg.FlowStableSec; } } /// 0..60 sec
public bool StoredPositionReuse { get { return regValveCfg.StoredPositionReuse; } }
public const int RVAnalogIdx = 9; /// Reg. valve ID used in communication with UniCB
public const double CalibDA = 550.0;
readonly RegValveCfg regValveCfg;
public IDrawingItem DrawingItem { get { return regValveCfg as IDrawingItem; } }
public ValveCategory Category { get { return regValveCfg.Category; } }
public int Idx1 { get { return RVAnalogIdx; } } /// Always 9
public int StableTime { get { return regValveCfg.StableTime; } } /// 0=200ms, step=50ms, max. 1500ms (max.26)
public int FlowStableSec { get { return regValveCfg.FlowStableSec; } } /// 0..60 sec
public bool StoredPositionReuse { get { return regValveCfg.StoredPositionReuse; } }
IDictionary<double, double> dict;
public IDictionary<double, double> Dict { get { return dict; } }
@@ -34,25 +37,35 @@ namespace TBF.Rig.Uni.RegValveAnalog
///
public double Position
{
get {
return 50.0; // TODO: was return uniCB.RValvePosition(Idx1);
get
{
/// Converts int value (0 .. 55000) to double value (0.0 .. 100.0)
return (1 / CalibDA) * uniCB.Data.StavDA[0];
}
}
///
public double SetpointVal
{
get { return Position; }
set { } // TODO
set
{
/// Converts double value (0.0 .. 100.0) to int value (0 .. 65535)
(StateMachine.ControlBoard as TBF.Rig.ControlBoard.Uni.UniCB).RegVlvMoveToPos(true, RVAnalogIdx, Convert.ToInt32(CalibDA * value));
}
}
///
public void IncreaseSetpoint()
{
/// TODO
int currentVal = uniCB.Data.StavDA[0];
int newValue = Math.Min(currentVal + 1500, (int)(100 * CalibDA));
(StateMachine.ControlBoard as TBF.Rig.ControlBoard.Uni.UniCB).RegVlvMoveToPos(true, RVAnalogIdx, newValue);
}
///
public void DecreaseSetpoint()
{
/// TODO
int currentVal = uniCB.Data.StavDA[0];
int newValue = Math.Max(0, currentVal - 1500);
(StateMachine.ControlBoard as TBF.Rig.ControlBoard.Uni.UniCB).RegVlvMoveToPos(true, RVAnalogIdx, newValue);
}
/// <summary>
@@ -64,7 +77,8 @@ namespace TBF.Rig.Uni.RegValveAnalog
{
/// Converison assuming: 0..100 % ~ 4..20 mA , 0..20 mA ~ 0..1023
int targetAdcVal = Math.Max(0, Math.Min(1023, Convert.ToInt32(Math.Round(8.19 * posPct + 204.0))));
uniCB.RegVlvMoveToPos(isFromUI, Idx1, targetAdcVal);
//uniCB.RegVlvMoveToPos(isFromUI, Idx1, targetAdcVal);
uniCB.RegVlvMoveToPos(isFromUI, Idx1, targetAdcVal, targetAdcVal);
}
@@ -83,6 +97,14 @@ namespace TBF.Rig.Uni.RegValveAnalog
{
this.dict = new Dictionary<double, double>();
TBF.UiBridge.Bridge.SetpointChangeHandler += delegate(object sndr, TBF.UiBridge.SetpointChangeArgs args)
{
if (args.Name == Name)
{
if (args.Increase) IncreaseSetpoint(); else DecreaseSetpoint();
}
};
log.FatalFormat("{0} initialized: {1}", Name, this);
}
@@ -100,7 +122,7 @@ namespace TBF.Rig.Uni.RegValveAnalog
/// <returns>SetFlowOp instance</returns>
public IOperation SetFlowOp(GenericDevices.IFlowMeter flowMeter, double qFrom, double qTo, DoubleBox measuredFlow, int timeout, int delay)
{
return new SetFlowOp(uniCB, this, flowMeter, qFrom, qTo, measuredFlow, regValveCfg.ReTryCommands, timeout, delay);
return new SetFlowOp(uniCB, this, flowMeter, qFrom, qTo, measuredFlow, timeout, delay);
}
/// <summary>
@@ -116,7 +138,7 @@ namespace TBF.Rig.Uni.RegValveAnalog
public IOperation SetFlowAndMeasureOp(GenericDevices.IFlowMeter flowMeter, double qFrom, double qTo,
DoubleBox measuredFlow, int timeout, float filterConstant)
{
return new SetFlowOp(uniCB, this, flowMeter, qFrom, qTo, measuredFlow, regValveCfg.ReTryCommands, timeout, 0, true);
return new SetFlowOp(uniCB, this, flowMeter, qFrom, qTo, measuredFlow, timeout, 0, true);
}
/// <summary>
+7 -10
View File
@@ -1,5 +1,5 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
/// Copyright (c) 2023 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
@@ -16,17 +16,18 @@ namespace TBF.Rig.Uni.RegValveAnalog
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(RegValveCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities) { return new RegValveCfgCtrl(); }
public IComponentCfgCtrl GetControl(IList<Component> cmpntEntities)
{
return new RegValveCfgCtrl();
}
///
/// Serialized parameters
///
public int Idx1; /// 1..8
public ValveCategory Category; /// Feeding, Output or All
public int StableTimeMs; /// 200..1500 ms
public int FlowStableSec; /// 0..60 sec
public bool StoredPositionReuse; /// true = store and re-use previous regulation valve positions
public bool ReTryCommands;
/// Schematic drawing info
public Shape Shape { get; set; }
@@ -70,26 +71,22 @@ namespace TBF.Rig.Uni.RegValveAnalog
Factory = factory;
ParentName = "CB";
Category = ValveCategory.Output;
Idx1 = 1;
StableTimeMs = 500;
FlowStableSec = 5;
StoredPositionReuse = false;
ReTryCommands = false;
}
public string ToString(int i)
{
return string.Format("Name={0} ({1}), Idx1={2}, Cat.={3}, StabTm={4}ms, FlowStable={5}s, PosReuse={6}, ReTryCmds={7}",
return string.Format("Name={0} ({1}), Cat.={2}, StabTm={3}ms, FlowStable={4}s, PosReuse={5}",
Name,
(string.IsNullOrEmpty(ParentName) ? "-" : ParentName),
Idx1,
Category,
StableTimeMs,
FlowStableSec,
StoredPositionReuse,
ReTryCommands);
StoredPositionReuse);
}
}
}
+2 -24
View File
@@ -1,5 +1,5 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
/// Copyright (c) 2023 Sensus Slovensko a.s.
///
using System;
using System.Windows.Forms;
@@ -74,11 +74,9 @@ namespace TBF.Rig.Uni.RegValveAnalog
nameTextBox.Text = config.Name;
parentNameComboBox.Text = string.IsNullOrEmpty(config.ParentName) ? "---" : config.ParentName;
categoryComboBox.Text = config.Category.ToString();
positionTextBox.Text = config.Idx1.ToString();
stableTimeTextBox.Text = config.StableTimeMs.ToString();
flowStableSecTextBox.Text = config.FlowStableSec.ToString();
storedPosReuseCheckBox.Checked = config.StoredPositionReuse;
reTryCommandsCheckBox.Checked = config.ReTryCommands;
formatTextBox.Text = config.SetpFormat;
unitsComboBox.Text = config.SetpUnit.ToString();
}
@@ -88,11 +86,9 @@ namespace TBF.Rig.Uni.RegValveAnalog
nameTextBox.Enabled = true;
parentNameComboBox.Enabled = true;
categoryComboBox.Enabled = true;
positionTextBox.Enabled = true;
stableTimeTextBox.Enabled = true;
flowStableSecTextBox.Enabled = true;
storedPosReuseCheckBox.Enabled = true;
reTryCommandsCheckBox.Enabled = true;
formatTextBox.Enabled = true;
unitsComboBox.Enabled = true;
}
@@ -113,11 +109,6 @@ namespace TBF.Rig.Uni.RegValveAnalog
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "Invalid 'Category'";
}
if (!int.TryParse(positionTextBox.Text, out dummy) || dummy < 1 || dummy > 8)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + "'Position' should be between 1 and 8";
}
if (!int.TryParse(stableTimeTextBox.Text, out dummy) || dummy < 200 || dummy > 1500 || (dummy % 50) != 0)
{
flags |= CfgUpdateFlags.Error;
@@ -166,14 +157,7 @@ namespace TBF.Rig.Uni.RegValveAnalog
flags |= CfgUpdateFlags.RestartRqrd;
}
int tmp = int.Parse(positionTextBox.Text);
if (config.Idx1 != tmp)
{
config.Idx1 = tmp;
flags |= CfgUpdateFlags.RestartRqrd;
}
tmp = int.Parse(stableTimeTextBox.Text);
int tmp = int.Parse(stableTimeTextBox.Text);
if (config.StableTimeMs != tmp)
{
config.StableTimeMs = tmp;
@@ -194,12 +178,6 @@ namespace TBF.Rig.Uni.RegValveAnalog
flags |= CfgUpdateFlags.RestartRqrd;
}
btmp = reTryCommandsCheckBox.Checked;
if (config.ReTryCommands != btmp)
{
config.ReTryCommands = btmp;
flags |= CfgUpdateFlags.RestartRqrd;
}
config.SetpUnit = global::Common.Unit.None;
for (Common.Unit units = 0; units < global::Common.Unit.Count; units++)
{
+12 -49
View File
@@ -31,8 +31,6 @@ namespace TBF.Rig.Uni.RegValveAnalog
/// </summary>
private void InitializeComponent()
{
this.positionTextBox = new System.Windows.Forms.TextBox();
this.positionLabel = new System.Windows.Forms.Label();
this.parentNameLabel = new System.Windows.Forms.Label();
this.nameTextBox = new System.Windows.Forms.TextBox();
this.nameLabel = new System.Windows.Forms.Label();
@@ -48,7 +46,6 @@ namespace TBF.Rig.Uni.RegValveAnalog
this.openButton = new System.Windows.Forms.Button();
this.categoryComboBox = new System.Windows.Forms.ComboBox();
this.categoryLabel = new System.Windows.Forms.Label();
this.reTryCommandsCheckBox = new System.Windows.Forms.CheckBox();
this.unitsComboBox = new System.Windows.Forms.ComboBox();
this.unitsLabel = new System.Windows.Forms.Label();
this.formatTextBox = new System.Windows.Forms.TextBox();
@@ -56,23 +53,6 @@ namespace TBF.Rig.Uni.RegValveAnalog
this.groupBox3.SuspendLayout();
this.SuspendLayout();
//
// positionTextBox
//
this.positionTextBox.Enabled = false;
this.positionTextBox.Location = new System.Drawing.Point(138, 115);
this.positionTextBox.Name = "positionTextBox";
this.positionTextBox.Size = new System.Drawing.Size(46, 20);
this.positionTextBox.TabIndex = 8;
//
// positionLabel
//
this.positionLabel.AutoSize = true;
this.positionLabel.Location = new System.Drawing.Point(28, 118);
this.positionLabel.Name = "positionLabel";
this.positionLabel.Size = new System.Drawing.Size(18, 13);
this.positionLabel.TabIndex = 7;
this.positionLabel.Text = "ID";
//
// parentNameLabel
//
this.parentNameLabel.AutoSize = true;
@@ -121,7 +101,7 @@ namespace TBF.Rig.Uni.RegValveAnalog
//
this.storedPosReuseCheckBox.AutoSize = true;
this.storedPosReuseCheckBox.Enabled = false;
this.storedPosReuseCheckBox.Location = new System.Drawing.Point(31, 192);
this.storedPosReuseCheckBox.Location = new System.Drawing.Point(31, 168);
this.storedPosReuseCheckBox.Name = "storedPosReuseCheckBox";
this.storedPosReuseCheckBox.Size = new System.Drawing.Size(162, 17);
this.storedPosReuseCheckBox.TabIndex = 17;
@@ -131,7 +111,7 @@ namespace TBF.Rig.Uni.RegValveAnalog
// stableTimeTextBox
//
this.stableTimeTextBox.Enabled = false;
this.stableTimeTextBox.Location = new System.Drawing.Point(138, 139);
this.stableTimeTextBox.Location = new System.Drawing.Point(138, 115);
this.stableTimeTextBox.Name = "stableTimeTextBox";
this.stableTimeTextBox.Size = new System.Drawing.Size(46, 20);
this.stableTimeTextBox.TabIndex = 14;
@@ -139,7 +119,7 @@ namespace TBF.Rig.Uni.RegValveAnalog
// stableTimeLabel
//
this.stableTimeLabel.AutoSize = true;
this.stableTimeLabel.Location = new System.Drawing.Point(28, 142);
this.stableTimeLabel.Location = new System.Drawing.Point(28, 118);
this.stableTimeLabel.Name = "stableTimeLabel";
this.stableTimeLabel.Size = new System.Drawing.Size(81, 13);
this.stableTimeLabel.TabIndex = 13;
@@ -148,7 +128,7 @@ namespace TBF.Rig.Uni.RegValveAnalog
// flowStableSecTextBox
//
this.flowStableSecTextBox.Enabled = false;
this.flowStableSecTextBox.Location = new System.Drawing.Point(138, 163);
this.flowStableSecTextBox.Location = new System.Drawing.Point(138, 139);
this.flowStableSecTextBox.Name = "flowStableSecTextBox";
this.flowStableSecTextBox.Size = new System.Drawing.Size(46, 20);
this.flowStableSecTextBox.TabIndex = 16;
@@ -156,7 +136,7 @@ namespace TBF.Rig.Uni.RegValveAnalog
// flowStableSecLabel
//
this.flowStableSecLabel.AutoSize = true;
this.flowStableSecLabel.Location = new System.Drawing.Point(28, 166);
this.flowStableSecLabel.Location = new System.Drawing.Point(28, 142);
this.flowStableSecLabel.Name = "flowStableSecLabel";
this.flowStableSecLabel.Size = new System.Drawing.Size(74, 13);
this.flowStableSecLabel.TabIndex = 15;
@@ -211,22 +191,11 @@ namespace TBF.Rig.Uni.RegValveAnalog
this.categoryLabel.TabIndex = 5;
this.categoryLabel.Text = "Category";
//
// reTryCommandsCheckBox
//
this.reTryCommandsCheckBox.AutoSize = true;
this.reTryCommandsCheckBox.Enabled = false;
this.reTryCommandsCheckBox.Location = new System.Drawing.Point(31, 215);
this.reTryCommandsCheckBox.Name = "reTryCommandsCheckBox";
this.reTryCommandsCheckBox.Size = new System.Drawing.Size(108, 17);
this.reTryCommandsCheckBox.TabIndex = 18;
this.reTryCommandsCheckBox.Text = "Re-try commands";
this.reTryCommandsCheckBox.UseVisualStyleBackColor = true;
//
// unitsComboBox
//
this.unitsComboBox.Enabled = false;
this.unitsComboBox.FormattingEnabled = true;
this.unitsComboBox.Location = new System.Drawing.Point(138, 264);
this.unitsComboBox.Location = new System.Drawing.Point(138, 218);
this.unitsComboBox.Name = "unitsComboBox";
this.unitsComboBox.Size = new System.Drawing.Size(80, 21);
this.unitsComboBox.TabIndex = 32;
@@ -234,7 +203,7 @@ namespace TBF.Rig.Uni.RegValveAnalog
// unitsLabel
//
this.unitsLabel.AutoSize = true;
this.unitsLabel.Location = new System.Drawing.Point(28, 267);
this.unitsLabel.Location = new System.Drawing.Point(28, 221);
this.unitsLabel.Name = "unitsLabel";
this.unitsLabel.Size = new System.Drawing.Size(71, 13);
this.unitsLabel.TabIndex = 31;
@@ -243,7 +212,7 @@ namespace TBF.Rig.Uni.RegValveAnalog
// formatTextBox
//
this.formatTextBox.Enabled = false;
this.formatTextBox.Location = new System.Drawing.Point(138, 240);
this.formatTextBox.Location = new System.Drawing.Point(138, 194);
this.formatTextBox.Name = "formatTextBox";
this.formatTextBox.Size = new System.Drawing.Size(130, 20);
this.formatTextBox.TabIndex = 30;
@@ -251,13 +220,13 @@ namespace TBF.Rig.Uni.RegValveAnalog
// formatLabel
//
this.formatLabel.AutoSize = true;
this.formatLabel.Location = new System.Drawing.Point(28, 243);
this.formatLabel.Location = new System.Drawing.Point(28, 197);
this.formatLabel.Name = "formatLabel";
this.formatLabel.Size = new System.Drawing.Size(78, 13);
this.formatLabel.TabIndex = 29;
this.formatLabel.Text = "Setpoint format";
//
// RegulValveCfgCtrl
// RegValveCfgCtrl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
@@ -265,7 +234,6 @@ namespace TBF.Rig.Uni.RegValveAnalog
this.Controls.Add(this.unitsLabel);
this.Controls.Add(this.formatTextBox);
this.Controls.Add(this.formatLabel);
this.Controls.Add(this.reTryCommandsCheckBox);
this.Controls.Add(this.categoryComboBox);
this.Controls.Add(this.categoryLabel);
this.Controls.Add(this.groupBox3);
@@ -275,13 +243,11 @@ namespace TBF.Rig.Uni.RegValveAnalog
this.Controls.Add(this.stableTimeLabel);
this.Controls.Add(this.storedPosReuseCheckBox);
this.Controls.Add(this.parentNameComboBox);
this.Controls.Add(this.positionTextBox);
this.Controls.Add(this.positionLabel);
this.Controls.Add(this.parentNameLabel);
this.Controls.Add(this.nameTextBox);
this.Controls.Add(this.nameLabel);
this.Controls.Add(this.classNameLabel);
this.Name = "RegulValveCfgCtrl";
this.Name = "RegValveCfgCtrl";
this.Size = new System.Drawing.Size(300, 700);
this.Load += new System.EventHandler(this.RegulationValveCfgCtrl_Load);
this.groupBox3.ResumeLayout(false);
@@ -292,9 +258,7 @@ namespace TBF.Rig.Uni.RegValveAnalog
#endregion
private System.Windows.Forms.TextBox positionTextBox;
private System.Windows.Forms.Label positionLabel;
private System.Windows.Forms.Label parentNameLabel;
private System.Windows.Forms.Label parentNameLabel;
private System.Windows.Forms.TextBox nameTextBox;
private System.Windows.Forms.Label nameLabel;
private System.Windows.Forms.Label classNameLabel;
@@ -309,7 +273,6 @@ namespace TBF.Rig.Uni.RegValveAnalog
private System.Windows.Forms.Button openButton;
private System.Windows.Forms.ComboBox categoryComboBox;
private System.Windows.Forms.Label categoryLabel;
private System.Windows.Forms.CheckBox reTryCommandsCheckBox;
private System.Windows.Forms.ComboBox unitsComboBox;
private System.Windows.Forms.Label unitsLabel;
private System.Windows.Forms.TextBox formatTextBox;
+159 -310
View File
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using log4net;
using Config.Entities;
using TBF.Rig.ControlBoard.Uni;
using TBF.Rig.GenericDevices;
using TBF.Boxes;
@@ -15,26 +16,28 @@ namespace TBF.Rig.Uni.RegValveAnalog
private static readonly ILog log = LogManager.GetLogger(typeof(SetFlowOp));
public override string ToString()
{
return string.Format("SetFlowOp({0}, Qfrom={1}, Qto={2})", regValve.Name, finalReqFlowLo, finalReqFlowHi);
return string.Format("SetFlowOp({0}, Qfrom={1}, Qto={2})", regV.Name, shrinkedTgtFlowLo, shrinkedTgtFlowHi);
}
public const double RqrdFlowRangeRatio = 0.7;
///
/// Set by the constructor
readonly UniCB uniCB;
readonly RegValve regValve;
readonly int flowMeterId;
readonly double finalReqFlowLo;
readonly double finalReqFlowHi;
readonly double reqFlowAve;
readonly int timeout;
///
readonly UniCB uniCB;
readonly RegValve regV;
readonly IFlowMeter flowMeter;
readonly double shrinkedTgtFlowLo;
readonly double shrinkedTgtFlowHi;
readonly double targetFlowAve;
readonly int timeout;
readonly int delay;
readonly bool leaveFlowControlRunning;
readonly bool reTryCommands;
readonly double nominalFlow;
readonly double maximalFlow;
///
/// Internal states of this operation
/// Internal state of this operation
///
enum OpState
{
@@ -42,14 +45,10 @@ namespace TBF.Rig.Uni.RegValveAnalog
ValveMoveToPosition1, /// Wait 1 takt
ValveMoveToPosition2, /// This is actual move to position
ValveMoveToPosition3, /// Wait 1 takt
CheckStatePosition, /// Verify
SettingPosition,
ValveMoveToFlow1, /// Wait 1 takt
ValveMoveToFlow2, /// This is actual move to flow
ValveMoveToFlow3, /// Wait 1 takt
CheckStateFlow, /// Verify
SettingFlow,
FlowReached,
Wait4FlowMsrmntAndSendRVMove, /// Wait until the flow measurement starts, then issue reg. valve move command
SettingFlow, /// Measure the flow and verify whether it is within limits sufficiently long time
FlowReached,
SendCommandAgain,
}
OpState opState;
@@ -59,62 +58,54 @@ namespace TBF.Rig.Uni.RegValveAnalog
double targetPositionLo;
double targetPositionHi;
int setFlowTime;
int expireTime;
DoubleBox measuredFlow;
int flowWithinBoundsTime;
DoubleBox msrdFlow;
int isFlowOkDuration;
/// <summary>
/// Set required water flow. Conditionally leave the measurement running.
/// Events: FlowSet, FlowTimeOut
/// </summary>
/// <param name="controlBoard">Control board device</param>
/// <param name="_regulValve">Regulation valve component</param>
/// <param name="uniCB">Control board device</param>
/// <param name="regValve">Regulation valve component</param>
/// <param name="flowMeter">Flowmeter component</param>
/// <param name="requiredFlowLo">Lower limit of the flow to be achieved in [m3/h]</param>
/// <param name="requiredFlowHi">Upper limit of the flow to be achieved in [m3/h]</param>
/// <param name="pidCoef">PID coefficient (float)</param>
/// <param name="qFrom">Lower limit of the flow to be achieved in [m3/h]</param>
/// <param name="qTo">Upper limit of the flow to be achieved in [m3/h]</param>
/// <param name="msrdFlow">DoubleBox for measured flow</param>
/// <param name="timeout">Timeout for the flow setting in [s]</param>
/// <param name="delay">Flow setting starts after this delay in [s]</param>
/// <param name="leaveFlowControlRunning">true = Leave the measurement running after op. stop</param>
/// <remarks>Only Elde.Valve flow are used, other flow on the lists are ignored</remarks>
public SetFlowOp(TBF.Rig.ControlBoard.IControlBoard cb, IRegValve _regulValve, IFlowMeter flowMeter,
double requiredFlowLo, double requiredFlowHi, DoubleBox measuredFlow,
bool reTryCmds, int timeout, int delay, bool leaveFlowControlRunning)
public SetFlowOp(UniCB uniCB, IRegValve regValve, IFlowMeter flowMeter, double qFrom, double qTo,
DoubleBox msrdFlow, int timeout, int delay, bool leaveFlowControlRunning)
{
uniCB = cb as UniCB;
if (uniCB == null) throw new ArgumentNullException("ctrlBoard");
this.uniCB = uniCB;
if (this.uniCB == null) throw new ArgumentNullException("Control board is null or not Uni");
regValve = _regulValve as TBF.Rig.Uni.RegValveAnalog.RegValve;
if (regValve == null) throw new ArgumentNullException(string.Format("{0} is not Elde.RegulValveCoax.", _regulValve.Name));
this.regV = regValve as RegValve;
if (this.regV == null) throw new ArgumentNullException(string.Format("{0} is not Uni.RegValveAnalog", regValve.Name));
if (flowMeter is Uni.FlowMeter.FlowMeter)
{
this.flowMeterId = (flowMeter as Uni.FlowMeter.FlowMeter).Idx1;
}
else if (flowMeter is Uni.FlowMetersInParallel.FlowMeter)
{
this.flowMeterId = 0;
}
else
{
throw new ArgumentNullException("flowMeter is null or not Elde");
}
this.flowMeter = flowMeter;
if (this.flowMeter == null) throw new ArgumentNullException("flowMeter");
nominalFlow = flowMeter.NominalFlow;
maximalFlow = nominalFlow * 1.25;
maximalFlow = flowMeter.NominalFlow * 1.25;
this.reqFlowAve = (requiredFlowLo + requiredFlowHi) / 2;
this.finalReqFlowLo = (0.7 * requiredFlowLo) + (0.3 * this.reqFlowAve); /// Move the lower limit 15% of the range up
this.finalReqFlowHi = (0.7 * requiredFlowHi) + (0.3 * this.reqFlowAve); /// Move the upper limit 15% of the range down
this.measuredFlow = measuredFlow;
this.reTryCommands = reTryCmds;
double rqrdFlowLoBeforeCorr = qFrom - MeasurementCorrection.GetCorrection(qFrom, flowMeter.Corrections);
double rqrdFlowHiBeforeCorr = qTo - MeasurementCorrection.GetCorrection(qTo, flowMeter.Corrections);
targetFlowAve = (rqrdFlowLoBeforeCorr + rqrdFlowHiBeforeCorr) / 2;
shrinkedTgtFlowLo = (RqrdFlowRangeRatio * rqrdFlowLoBeforeCorr)
+ ((1 - RqrdFlowRangeRatio) * targetFlowAve); /// Move the lower limit 15% of the range up
shrinkedTgtFlowHi = (RqrdFlowRangeRatio * rqrdFlowHiBeforeCorr)
+ ((1 - RqrdFlowRangeRatio) * targetFlowAve); /// Move the upper limit 15% of the range down
this.msrdFlow = msrdFlow;
this.timeout = timeout;
this.delay = delay;
this.leaveFlowControlRunning = leaveFlowControlRunning;
log.Warn(this.ToString());
log.Debug(this.ToString());
}
/// <summary>
@@ -122,8 +113,8 @@ namespace TBF.Rig.Uni.RegValveAnalog
/// Events: FlowSet
/// </summary>
public SetFlowOp(UniCB uniCB, IRegValve regValve, IFlowMeter flowMeter, double qFrom, double qTo,
DoubleBox measuredFlow, bool reTryCmds, int timeout, int delay)
: this(uniCB, regValve, flowMeter, qFrom, qTo, measuredFlow, reTryCmds, timeout, delay, false)
DoubleBox msrdFlow, int timeout, int delay)
: this(uniCB, regValve, flowMeter, qFrom, qTo, msrdFlow, timeout, delay, false)
{
}
@@ -137,25 +128,25 @@ namespace TBF.Rig.Uni.RegValveAnalog
bool FetchTargetPosition(double avgReqFlow, out double positionLo, out double positionHi)
{
double targetPosition;
if (regValve.Dict.TryGetValue(avgReqFlow, out targetPosition))
if (regV.Dict.TryGetValue(avgReqFlow, out targetPosition))
{
positionLo = Math.Max(targetPosition * 0.95f, 0.0f);
positionHi = Math.Min(targetPosition * 1.05f, 100.0f);
positionLo = Math.Max(targetPosition * 0.95, 0.0);
positionHi = Math.Min(targetPosition * 1.05, 100.0);
return true;
}
else
{
positionLo = 0.0f;
positionHi = 0.0f;
positionLo = 0;
positionHi = 0;
return false;
}
}
void StoreTargetPosition(double avgReqFlow, double actPosition)
{
if (!regValve.Dict.ContainsKey(reqFlowAve))
if (!regV.Dict.ContainsKey(targetFlowAve))
{
regValve.Dict.Add(new KeyValuePair<double, double>(avgReqFlow, actPosition));
regV.Dict.Add(new KeyValuePair<double, double>(avgReqFlow, actPosition));
}
return;
}
@@ -163,309 +154,167 @@ namespace TBF.Rig.Uni.RegValveAnalog
/// <summary>Start this operation</summary>
public void Start()
{
double flowMtrFreq = uniCB.RefFrequency;
currentReqFlowLo = reqFlowAve;
currentReqFlowHi = reqFlowAve;
///
if (flowMtrFreq != 0)
{
double flow = flowMtrFreq * nominalFlow / 2000.0; /// TODO: ???
if (measuredFlow != null) measuredFlow.Val = flow;
if (flow >= reqFlowAve) currentReqFlowLo = finalReqFlowLo;
if (flow <= reqFlowAve) currentReqFlowHi = finalReqFlowHi;
}
else
{
currentReqFlowLo = finalReqFlowLo; /// Unexpected case when flowMtrFreq==0
currentReqFlowHi = finalReqFlowHi;
}
flowWithinBoundsTime = 0;
if (regValve.StoredPositionReuse && FetchTargetPosition(reqFlowAve, out targetPositionLo, out targetPositionHi))
{
log.WarnFormat("Start() rv#={0} flowMtr#={1} TARGET: flowLo={2} flowHi={3} FETCHED: posLo={4} posHi={5}",
regValve.Idx1, flowMeterId, currentReqFlowLo, currentReqFlowHi, targetPositionLo, targetPositionHi);
opState = OpState.ValveMoveToPosition1;
}
else
{
log.WarnFormat("Start() rv#={0} flowMtr#={1} TARGET: flowLo={2} flowHi={3}",
regValve.Idx1, flowMeterId, currentReqFlowLo, currentReqFlowHi);
opState = OpState.ValveMoveToFlow1;
}
log.InfoFormat("SetFlowOp:Start() rv#={0} flowMtr#={1} TARGET: flowLo={2} flowHi={3}",
regV.Idx1, flowMeter.Idx1, currentReqFlowLo, currentReqFlowHi);
/// Store the current time, etc.
setFlowTime = StateMachine.Time + delay;
expireTime = StateMachine.Time + timeout;
if (expireTime < 0) expireTime = int.MaxValue;
/// Start the flow measurement
uniCB.MeasureFlow(false, flowMeterId);
}
isFlowOkDuration = 0;
/// <summary>Run this operation</summary>
/// Start the flow measurement
uniCB.MeasureFlow(false, flowMeter.Idx1);
opState = OpState.Wait4FlowMsrmntAndSendRVMove;
}
/// <summary>
/// Run this operation
/// </summary>
/// <returns>
/// Event.None, Event.FlowReached, Event.RegulValveTimeOut, Event.OpArgumentError
/// Event.OpArgumentError
/// Event.Starting
/// Event.Busy
/// Event.FlowReached
/// Event.RegulValveTimeOut
/// </returns>
public Event Run()
{
double rvPosition = regValve.Position;
double flowMtrFreq = uniCB.RefFrequency;
double flow = flowMtrFreq * nominalFlow / 2000.0;
log.DebugFormat("Op.Run() opState={0}", opState);
if (flowMtrFreq != 0)
if (StateMachine.Time > expireTime) return Event.RegulValveTimeOut;
if (opState == OpState.Wait4FlowMsrmntAndSendRVMove)
{
if (measuredFlow != null) measuredFlow.Val = flow;
if (flow >= reqFlowAve) currentReqFlowLo = finalReqFlowLo;
if (flow <= reqFlowAve) currentReqFlowHi = finalReqFlowHi;
}
if (!flowMeter.MsrmntAvailable) return Event.Starting;
log.InfoFormat("Run() rv#={0} pos={1}% freq={2} flow={3} curFlLo={4} curFlHi={5} state={6}",
regValve.Idx1, rvPosition.ToString("F1"), flowMtrFreq.ToString("F1"), flow.ToString("F3"), currentReqFlowLo.ToString("F3"), currentReqFlowHi.ToString("F3"), opState);
double flow1 = flowMeter.ReadFlow();
/// Set the targer flow/frequency range
currentReqFlowLo = shrinkedTgtFlowLo; /// Default lower limit
currentReqFlowHi = shrinkedTgtFlowHi; /// Default upper limit
//if (flow1 >= targetFlowAve) currentReqFlowHi = targetFlowAve; /// Decrease upper limit
//if (flow1 <= targetFlowAve) currentReqFlowLo = targetFlowAve; /// Increase lower limit
if (opState == OpState.SendCommandAgain)
{
flowWithinBoundsTime = 0;
if (regValve.StoredPositionReuse && FetchTargetPosition(reqFlowAve, out targetPositionLo, out targetPositionHi))
{
log.InfoFormat(" Run() rv#={0} flowMtr#={1} TARGET: flowLo={2} flowHi={3} FETCHED: posLo={4} posHi={5}",
regValve.Idx1, flowMeterId, currentReqFlowLo.ToString("F3"), currentReqFlowHi.ToString("F3"), targetPositionLo, targetPositionHi);
opState = OpState.ValveMoveToPosition1;
}
else
{
log.InfoFormat(" Run() rv#={0} flowMtr#={1} TARGET: flowLo={2} flowHi={3}",
regValve.Idx1, flowMeterId, currentReqFlowLo.ToString("F3"), currentReqFlowHi.ToString("F3"));
opState = OpState.ValveMoveToFlow1;
}
expireTime = StateMachine.Time + timeout;
if (expireTime < 0) expireTime = int.MaxValue;
/// Start the flow measurement
uniCB.MeasureFlow(false, flowMeterId);
return Event.None;
}
else if (opState == OpState.ValveMoveToPosition1)
{
opState = OpState.ValveMoveToPosition2;
log.DebugFormat(" return Event.None");
return Event.None;
}
else if (opState == OpState.ValveMoveToPosition2) /// Move to position
{
/// Issues the appropriate ValveMove(...) command
// TODO: Reimplement
//uniCB.ValveMove(regValve.Idx1, RegulValveMode.TargetPosition,
// new double[2] { (targetPositionLo + targetPositionHi) / 2, (targetPositionLo + targetPositionHi) / 2 },
// regValve.StableTime);
opState = OpState.SettingPosition;
log.DebugFormat(" return Event.None");
return Event.None;
}
else if (opState == OpState.ValveMoveToPosition3)
{
if (reTryCommands)
if ((currentReqFlowLo >= currentReqFlowHi) || (currentReqFlowLo > maximalFlow) || (currentReqFlowHi <= 0))
{
opState = OpState.CheckStatePosition;
return Event.OpArgumentError;
}
else
if (StateMachine.Time > setFlowTime)
{
opState = OpState.SettingPosition;
}
log.DebugFormat(" return Event.None");
return Event.None;
}
else if (opState == OpState.CheckStatePosition) /// Verify
{
if (((ulong)uniCB.State & (ulong)StatusP.TestWithRefFlowmtr) == 0)
{
opState = OpState.SendCommandAgain;
log.DebugFormat(" return Event.None");
return Event.None;
}
else if (((ulong)uniCB.State & (ulong)StatusP.CoaxRegValveBusy) == 0)
{
// TODO: Reimplement
///// Repeat appropriate ValveMove(...) command
//uniCB.ValveMove(regValve.Idx1, RegulValveMode.TargetPosition,
// new double[2] { (targetPositionLo + targetPositionHi) / 2, (targetPositionLo + targetPositionHi) / 2 },
// regValve.StableTime);
uniCB.SetFlow(false, regV.Idx1, flowMeter.NominalFreq * currentReqFlowLo / flowMeter.NominalFlow,
flowMeter.NominalFreq * currentReqFlowHi / flowMeter.NominalFlow);
log.InfoFormat(" Run() ValveMove({0}, Position, {1}, {2}, {3})",
regValve.Idx1, (targetPositionLo + targetPositionHi) / 2, (targetPositionLo + targetPositionHi) / 2, regValve.StableTime);
log.InfoFormat("Run(): rv#={0} TARGET: flowLo={1} flowHi={2}", regV.Idx1, currentReqFlowLo, currentReqFlowHi);
opState = OpState.ValveMoveToPosition3;
log.DebugFormat(" return Event.None");
return Event.None;
}
else
{
opState = OpState.SettingPosition;
log.DebugFormat(" return Event.None");
return Event.None;
}
}
else if (opState == OpState.SettingPosition)
{
/// Repeated untill position is reached
if ((targetPositionLo <= rvPosition) && (rvPosition <= targetPositionHi))
{
opState = OpState.ValveMoveToFlow1;
}
log.DebugFormat(" return Event.None");
return Event.None;
}
else if (opState == OpState.ValveMoveToFlow1)
{
opState = OpState.ValveMoveToFlow2;
log.DebugFormat(" return Event.None");
return Event.None;
}
else if (opState == OpState.ValveMoveToFlow2) /// Move to flow
{
///
/// Done once, issues an appropriate ValveMove(...) command
///
if ((currentReqFlowLo >= currentReqFlowHi) || (currentReqFlowLo > maximalFlow) || (currentReqFlowHi <= 0))
{
log.DebugFormat(" return Event.OpArgumentError");
return Event.OpArgumentError;
}
double freqLo = 2000.0 * currentReqFlowLo / nominalFlow;
double freqHi = 2000.0 * currentReqFlowHi / nominalFlow;
// TODO: Reimplement
//uniCB.ValveMove(regValve.Idx1, RegulValveMode.TargetFrequency,
// new double[2] { (freqLo + freqHi) / 2, (freqLo + freqHi) / 2 },
// regValve.StableTime);
log.WarnFormat(" Run() ValveMove({0}, Freq., {1}, {2}, {3}) flowMtr#={4} TARGET: flowLo={5} flowHi={6}",
regValve.Idx1, (freqLo + freqHi) / 2, (freqLo + freqHi) / 2,
regValve.StableTime,
flowMeterId, currentReqFlowLo.ToString("F3"), currentReqFlowHi.ToString("F3"));
opState = OpState.ValveMoveToFlow3;
log.DebugFormat(" return Event.None");
return Event.None;
}
else if (opState == OpState.ValveMoveToFlow3)
{
if (reTryCommands)
{
opState = OpState.CheckStateFlow;
}
else
{
opState = OpState.SettingFlow;
}
log.DebugFormat(" return Event.None");
return Event.None;
}
else if (opState == OpState.CheckStateFlow) /// Verify the flow setting
return Event.Starting;
}
if (opState == OpState.ValveMoveToPosition1)
{
if (((ulong)uniCB.State & (ulong)StatusP.CoaxRegValveBusy) == 0)
{
/// Done once, issues an appropriate ValveMove(...) command
double freqLo = 2000.0 * currentReqFlowLo / nominalFlow;
double freqHi = 2000.0 * currentReqFlowHi / nominalFlow;
// TODO: Reimplement
//uniCB.ValveMove(regValve.Idx1, RegulValveMode.TargetFrequency,
// new double[2] { (freqLo + freqHi) / 2, (freqLo + freqHi) / 2 },
// regValve.StableTime);
log.WarnFormat(" Run() ValveMove({0}, Frequency, {1}, {2}, {3}) flowMtr#={4} TARGET: flowLo={5} flowHi={6}",
regValve.Idx1, (freqLo + freqHi) / 2, (freqLo + freqHi) / 2,
regValve.StableTime,
flowMeterId, currentReqFlowLo.ToString("F3"), currentReqFlowHi.ToString("F3"));
opState = OpState.ValveMoveToFlow3;
log.DebugFormat(" return Event.None");
return Event.None;
}
else
{
opState = OpState.SettingFlow;
log.DebugFormat(" return Event.None");
return Event.None;
}
opState = OpState.ValveMoveToPosition2;
return Event.Starting;
}
else if (opState == OpState.ValveMoveToPosition2) /// Move to position
{
/// Issues the appropriate ValveMove(...) command
regV.MoveToPosition(false, targetPositionLo);
opState = OpState.SettingPosition;
return Event.Starting;
}
else if (opState == OpState.ValveMoveToPosition3)
{
opState = OpState.SettingPosition;
return Event.Starting;
}
else if (opState == OpState.SettingPosition)
{
/// Repeated untill position is reached
double rvPosition = regV.Position;
if ((targetPositionLo <= rvPosition) && (rvPosition <= targetPositionHi))
{
opState = OpState.Wait4FlowMsrmntAndSendRVMove;
}
return Event.Starting;
}
else if (opState == OpState.SettingFlow)
{
///
/// Repeated untill the required flow is reached
///
if ((currentReqFlowLo <= flow) && (flow <= currentReqFlowHi))
/// Regulation valve is setting flow to the required value
///
double frequency = flowMeter.ReadFrequency();
double flow = flowMeter.ReadFlow();
if (msrdFlow != null && flow != 0) msrdFlow.Val = flow;
if (currentReqFlowLo <= flow && flow <= currentReqFlowHi)
{
if (flowWithinBoundsTime++ >= regValve.FlowStableSec)
isFlowOkDuration++; /// Increment the flow within range duration
if (isFlowOkDuration >= regV.FlowStableSec)
{
if (regValve.StoredPositionReuse)
/// Flow is within range for sufficiently long time
if (regV.StoredPositionReuse)
{
double rvPosition = regV.Position; /// Read the current position
double storedPosition;
if (regValve.Dict.TryGetValue(reqFlowAve, out storedPosition))
if (regV.Dict.TryGetValue(targetFlowAve, out storedPosition))
{
/// update the stored valve position
StoreTargetPosition(reqFlowAve, (rvPosition + storedPosition) / 2.0f);
StoreTargetPosition(targetFlowAve, (rvPosition + storedPosition) / 2.0f);
log.InfoFormat(" Run() rv#={0} reqFlow={1} pos={2}% stored={3} <--- Updating a stored position",
regValve.Idx1, reqFlowAve, rvPosition.ToString("F1"), storedPosition);
regV.Idx1, targetFlowAve, rvPosition.ToString("F1"), storedPosition);
}
else
{
/// store the valve position
StoreTargetPosition(reqFlowAve, rvPosition);
StoreTargetPosition(targetFlowAve, rvPosition);
log.InfoFormat(" Run() rv#={0} reqFlow={1} pos={2}% <--- Storing a new position",
regValve.Idx1, reqFlowAve, rvPosition.ToString("F1"));
regV.Idx1, targetFlowAve, rvPosition.ToString("F1"));
}
}
log.InfoFormat(" flow = {0} m3/h (lo={1}, hi={2}, REACHED)", flow.ToString("F3"), currentReqFlowLo.ToString("F3"), currentReqFlowHi.ToString("F3"));
opState = OpState.FlowReached;
log.DebugFormat(" return Event.FlowReached");
return Event.FlowReached;
}
else
{
log.InfoFormat(" flow = {0} m3/h (lo={1}, hi={2}, FLOW_OK_TIMER={3}s)", flow.ToString("F3"), currentReqFlowLo, currentReqFlowHi, flowWithinBoundsTime);
log.DebugFormat(" return Event.None");
return Event.None;
}
log.InfoFormat("flow = {0} m3/h (lo={1}, hi={2}, FLOW_OK_TIMER={3}s)", flow, currentReqFlowLo, currentReqFlowHi, isFlowOkDuration);
return Event.Busy;
}
}
else if (StateMachine.Time > expireTime)
{
log.DebugFormat(" return Event.RegulValveTimeOut");
return Event.RegulValveTimeOut;
}
else
{
log.InfoFormat(" flow = {0} m3/h (lo={1}, hi={2})", flow.ToString("F3"), currentReqFlowLo, currentReqFlowHi);
flowWithinBoundsTime = 0;
log.DebugFormat(" return Event.None");
return Event.None;
}
}
else
{
/// Flow is out of range
isFlowOkDuration = 0;
log.InfoFormat("flow = {0} m3/h (lo={1}, hi={2})", flow, currentReqFlowLo, currentReqFlowHi);
return Event.Busy;
}
}
else /// opState == OpState.FlowReached
{
log.InfoFormat(" flow = {0} m3/h (lo={1}, hi={2}, REACHED)", flow.ToString("F3"), currentReqFlowLo, currentReqFlowHi);
log.DebugFormat(" return Event.FlowReached");
return Event.FlowReached;
log.InfoFormat("flow = {0} m3/h (lo={1}, hi={2}, REACHED)", flowMeter.ReadFlow(), currentReqFlowLo, currentReqFlowHi);
return Event.FlowReached;
}
}
/// <summary>Start this operation</summary>
/// <summary>Stop this operation</summary>
public void Stop()
{
opState = OpState.Idle;
if (leaveFlowControlRunning) return;
uniCB.StopFlowControl(false, regValve.Idx1);
log.WarnFormat("Stop() SendCommand(Stop, {0}, ...)", flowMeterId);
if (!leaveFlowControlRunning)
{
uniCB.RegVlvMoveToPos(false, regV.Idx1, uniCB.Data.StavDA[0]); /// Stop the flow measurement
}
opState = OpState.Idle;
}
}
}
@@ -32,6 +32,7 @@ namespace TBF.Rig.Uni.RegValveAnalog
/// Set by the constructor
readonly UniCB uniCB;
readonly RegValve regV;
readonly int regValveNr;
readonly double posLoPct;
readonly double posHiPct;
readonly int timeout;
@@ -57,6 +58,7 @@ namespace TBF.Rig.Uni.RegValveAnalog
this.regV = regV;
if (this.regV == null) throw new ArgumentNullException("regValve is null or not Elde");
this.regValveNr = this.regV.Idx1;
this.posLoPct = posLoPct;
this.posHiPct = posHiPct;
@@ -100,13 +102,14 @@ namespace TBF.Rig.Uni.RegValveAnalog
regV.MoveToPosition(false, posLoPct);
opState = OpState.CheckState;
log.WarnFormat("Run(): RV#={0}, state={1}, MoveToPosition(false, {2:D1}, {3:D1}) issued", regValveNr, opState, posLoPct, posHiPct);
return Event.None;
}
if (positionReached) return Event.PositionReached;
double positionPct = regV.Position;
log.WarnFormat("Run(): RV#={0}, actPos={1}%", regV.Idx1, positionPct.ToString("F1"));
log.WarnFormat("Run(): RV#={0}, state={1}, pos={2}%", regValveNr, opState, positionPct.ToString("F1"));
if (opState == OpState.CheckState)
{
@@ -114,6 +117,7 @@ namespace TBF.Rig.Uni.RegValveAnalog
{
opState = OpState.MoveToPosition;
return Event.None;
}
else if (posLoPct <= positionPct && positionPct <= posHiPct)
{
@@ -150,6 +154,8 @@ namespace TBF.Rig.Uni.RegValveAnalog
}
/// <summary>Stop this operation</summary>
public void Stop() { }
public void Stop()
{
}
}
}
@@ -22,6 +22,7 @@ namespace TBF.Rig.Uni.RegValveTandem
UniCB uniCB { get { return regValve.UniCB; } }
public ValveCategory Category { get { return RegulValveTandemCfg.Category; } }
public int Idx1 { get { return regValve.Idx1; } }
readonly TBF.Rig.Uni.RegValve.RegValve regValve;
readonly TBF.Rig.Uni.RegValve.RegValve fixedRV;