BugFix - after applying the transition valve 40% in procedure-purge begin, the RegValve was not regulating correctly after starting the test

This commit is contained in:
Marek Frniak 2026-03-09 14:20:37 +01:00
parent 4bfd5c8e11
commit c445b3e098
6 changed files with 88 additions and 92 deletions

View File

@ -1,9 +1,10 @@
///
/// Copyright (c) 2021 Sensus Metering Systems
/// Copyright (c) 2021-2023 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using log4net;
using TBF.Rig.ControlBoard.Uni;
using TBF.Rig.GenericDevices;
namespace TBF.Rig.Uni.RegValve
@ -13,12 +14,12 @@ namespace TBF.Rig.Uni.RegValve
private static readonly ILog log = LogManager.GetLogger(typeof(ChangeRegValvePositionOp));
public override string ToString()
{
return string.Format("ChangeRegValvePositionOp({0},{1}s)", regulValve.Name, timePulseSec.ToString("F2"));
return string.Format("ChangeRegValvePositionOp({0},{1}s)", regV.Name, timePulseSec.ToString("F2"));
}
/// Set by the constructor
readonly TBF.Rig.ControlBoard.Uni.UniCB controlBoard;
readonly RegValve regulValve;
readonly UniCB uniCB;
readonly RegValve regV;
readonly int regulValveNr;
readonly double timePulseSec;
@ -32,14 +33,14 @@ namespace TBF.Rig.Uni.RegValve
/// <param name="posHiPct">Upper limit of the position to be achieved</param>
/// <param name="timeout">Timeout in sec. for setting the flow</param>
/// <remarks>Only Elde.Valve flow are used, other flow on the lists are ignored</remarks>
public ChangeRegValvePositionOp(TBF.Rig.ControlBoard.IControlBoard cb, RegValve rv, double timePulseSec)
public ChangeRegValvePositionOp(UniCB uniCB, RegValve regV, double timePulseSec)
{
controlBoard = cb as TBF.Rig.ControlBoard.Uni.UniCB;
if (controlBoard == null) throw new ArgumentNullException("ctrlBoard");
this.uniCB = uniCB;
if (this.uniCB == null) throw new ArgumentNullException("ctrlBoard");
regulValve = rv as RegValve;
if (regulValve == null) throw new ArgumentNullException("regValve is null or not Elde");
regulValveNr = this.regulValve.Idx1;
this.regV = regV as RegValve;
if (this.regV == null) throw new ArgumentNullException("regValve is null or not Uni");
regulValveNr = this.regV.Idx1;
this.timePulseSec = timePulseSec;
@ -49,13 +50,7 @@ namespace TBF.Rig.Uni.RegValve
/// <summary>Start this operation</summary>
public void Start()
{
//double positionPct = controlBoard.RValvePosition(regulValveNr);
//log.WarnFormat("RV#={0}, actPos={1}%", regulValveNr, positionPct.ToString("F1"));
//controlBoard.ValveMove(regulValveNr,
// TBF.Rig.ControlBoard.Legacy.RegulValveMode.PulseWidth,
// new double[2] { timePulseSec, timePulseSec },
// regulValve.StableTime);
uniCB.RegVlvIncrMove(false, regulValveNr, timePulseSec);
}
/// <summary>Run this operation</summary>
@ -64,9 +59,6 @@ namespace TBF.Rig.Uni.RegValve
/// </returns>
public Event Run()
{
//float positionPct = controlBoard.RValvePosition(regulValveNr);
//log.WarnFormat("RV#={0}, actPos={1}%", regulValveNr, positionPct.ToString("F1"));
return Event.PositionReached;
}

View File

@ -1,5 +1,5 @@
///
/// Copyright (c) 2021 Sensus Metering Systems
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System.Collections.Generic;
using TBF.Rig.Generic;

View File

@ -1,5 +1,5 @@
///
/// Copyright (c) 2021 Sensus Metering Systems
/// Copyright (c) 2021 Sensus Slovensko a.s.
///
using System;
using log4net;

View File

@ -32,15 +32,30 @@ namespace TBF.Rig.Uni.RegValve
public bool StoredPositionReuse { get { return regValveCfg.StoredPositionReuse; } }
///
public bool IsCoax { get { return false; } }
/// 0.0 .. 100.0
public RegValveState RegValveState
{
get
{
switch (UniCB.Data.RegVStatus[Idx1 - 1])
{
default:
case 0: return ControlBoard.Uni.RegValveState.Idle;
case 2: return ControlBoard.Uni.RegValveState.PwOrFreqRegul;
case 3: return ControlBoard.Uni.RegValveState.DacValueRegul;
}
}
}
/// Position 0.0 .. 100.0 in %
public double Position
{
get
{
int denominator = DacValueOpen - DacValueClosed;
if (denominator == 0) denominator = 1;
return 100.0 * Convert.ToDouble(UniCB.AnalogInput(adcChannel) - DacValueClosed) / Convert.ToDouble(denominator);
return 100.0 * Convert.ToDouble(Math.Max(0, Math.Min(denominator, (int)UniCB.AnalogInput(adcChannel) - DacValueClosed)))
/ Convert.ToDouble(denominator);
}
}
///
@ -61,7 +76,6 @@ namespace TBF.Rig.Uni.RegValve
}
int adcChannel;
public RegValveState RegValveState;
public double TargetRegValvePosition;
@ -79,11 +93,15 @@ namespace TBF.Rig.Uni.RegValve
/// </summary>
/// <param name="rvId">Reg. valve ID</param>
/// <param name="position">Reg. valve position (0 .. 1.0)</param>
public void MoveToPosition(bool isFromUI, double positionLo, double positionHi = -1)
public void MoveToPosition(bool isFromUI, double posPctLo, double posPctHi = -1)
{
int positionLoInt = Convert.ToInt32(positionLo);
int positionHiInt = Convert.ToInt32(positionHi);
UniCB.RegVlvMoveToPos(isFromUI, Idx1, positionLoInt, positionHiInt);
int adcDiff = Math.Abs(regValveCfg.AdcValueOpen - regValveCfg.AdcValueClosed);
int adcLower = Math.Min(regValveCfg.AdcValueOpen, regValveCfg.AdcValueClosed);
int targetAdcValLo = Math.Max(0, Convert.ToInt32(Math.Round((posPctLo * adcDiff / 100.0) + adcLower)));
int targetAdcValHi = (posPctHi < 0) ? -1 : Math.Min(1023, Convert.ToInt32(Math.Round((posPctHi * adcDiff / 100.0) + adcLower)));
UniCB.RegVlvMoveToPos(isFromUI, Idx1, targetAdcValLo, targetAdcValHi);
}
@ -139,8 +157,6 @@ namespace TBF.Rig.Uni.RegValve
this.UniCB = TbfComponents.FindComponent(cfg.ParentName, components) as UniCB;
if (this.UniCB == null) throw new Exception(string.Format("Cannot find {0} (a parent of {1})", cfg.ParentName, Name));
log.Warn(this.ToString());
}
public override void Initialize()
@ -155,6 +171,8 @@ namespace TBF.Rig.Uni.RegValve
if (args.Increase) IncreaseSetpoint(); else DecreaseSetpoint();
}
};
log.FatalFormat("{0} initialized: {1}", Name, this);
}
///

View File

@ -3,7 +3,6 @@
///
using System;
using System.Collections.Generic;
using Common;
using log4net;
using Config.Entities;
using TBF.Rig.ControlBoard.Uni;
@ -20,11 +19,10 @@ namespace TBF.Rig.Uni.RegValve
return string.Format("SetFlowOp({0}, Qfrom={1}, Qto={2})", regV.Name, shrinkedTgtFlowLo, shrinkedTgtFlowHi);
}
public const double RqrdFlowRangeRatio = 0.5;
///
/// Set by the constructor
/// Set by the constructor
///
readonly UniCB uniCB;
readonly RegValve regV;
@ -37,8 +35,8 @@ namespace TBF.Rig.Uni.RegValve
readonly bool leaveFlowControlRunning;
readonly double maximalFlow;
///
///
/// Internal state of this operation
///
enum OpState
@ -57,13 +55,12 @@ namespace TBF.Rig.Uni.RegValve
double currentReqFlowLo;
double currentReqFlowHi;
double targetPositionLo;
double targetPositionHi;
double targetPositionLo;
double targetPositionHi;
int startTime;
int setFlowTime;
int expireTime;
DoubleBox flowBox;
DoubleBox msrdFlow;
int isFlowOkDuration;
@ -72,23 +69,23 @@ namespace TBF.Rig.Uni.RegValve
/// Events: FlowSet, FlowTimeOut
/// </summary>
/// <param name="uniCB">Control board device</param>
/// <param name="regulValve">Regulation valve component</param>
/// <param name="regValve">Regulation valve component</param>
/// <param name="flowMeter">Flowmeter component</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="pidCoef">PID coefficient (float)</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 [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(UniCB uniCB, IRegValve regValve, IFlowMeter flowMeter, double qFrom, double qTo, DoubleBox flowBox,
public SetFlowOp(UniCB uniCB, IRegValve regValve, IFlowMeter flowMeter, double qFrom, double qTo, DoubleBox msrdFlow,
int timeout, int delay, bool leaveFlowControlRunning)
{
this.uniCB = uniCB;
if (this.uniCB == null) throw new ArgumentNullException("cBoard is null or not Uni");
this.uniCB = uniCB;
if (this.uniCB == null) throw new ArgumentNullException("Control board is null or not Uni");
this.regV = regValve as RegValve;
if (this.regV == null) throw new ArgumentNullException("regValve is null or not Uni");
if (this.regV == null) throw new ArgumentNullException(string.Format("{0} is not Uni.RegValve", regValve.Name));
this.flowMeter = flowMeter;
if (this.flowMeter == null) throw new ArgumentNullException("flowMeter");
@ -98,15 +95,14 @@ namespace TBF.Rig.Uni.RegValve
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.flowBox = flowBox;
if (this.flowBox == null) throw new ArgumentNullException("flowBox");
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.Debug(this.ToString());
@ -172,16 +168,13 @@ namespace TBF.Rig.Uni.RegValve
return;
}
/// <summary>
/// Start this operation
/// </summary>
/// <summary>Start this operation</summary>
public void Start()
{
log.InfoFormat("SetFlowOp:Start() rv#={0} flowMtr#={1} TARGET: flowLo={2} flowHi={3}",
regV.Idx1, flowMeter.Idx1, currentReqFlowLo, currentReqFlowHi);
/// Store the current time, etc.
startTime = StateMachine.Time;
setFlowTime = StateMachine.Time + delay;
expireTime = StateMachine.Time + timeout;
if (expireTime < 0) expireTime = int.MaxValue;
@ -212,8 +205,6 @@ namespace TBF.Rig.Uni.RegValve
if (opState == OpState.Wait4FlowMsrmntAndSendRVMove)
{
if (flowMeter.DebugLevel == DebugMode.Simulate) return Event.FlowReached;
if (!flowMeter.MsrmntAvailable) return Event.Starting;
double flow1 = flowMeter.ReadFlow();
@ -231,8 +222,8 @@ namespace TBF.Rig.Uni.RegValve
if (StateMachine.Time > setFlowTime)
{
uniCB.SetFlow(false, regV.Idx1, 2000.0 * currentReqFlowLo / flowMeter.NominalFlow,
2000.0 * currentReqFlowHi / flowMeter.NominalFlow);
uniCB.SetFlow(false, regV.Idx1, flowMeter.NominalFreq * currentReqFlowLo / flowMeter.NominalFlow,
flowMeter.NominalFreq * currentReqFlowHi / flowMeter.NominalFlow);
log.InfoFormat("Run(): rv#={0} TARGET: flowLo={1} flowHi={2}", regV.Idx1, currentReqFlowLo, currentReqFlowHi);
@ -276,17 +267,16 @@ namespace TBF.Rig.Uni.RegValve
///
double frequency = flowMeter.ReadFrequency();
double flow = flowMeter.ReadFlow();
if (flow != 0) flowBox.Val = flow;
if (msrdFlow != null && flow != 0) msrdFlow.Val = flow;
if ((currentReqFlowLo <= flow) && (flow <= currentReqFlowHi))
if (currentReqFlowLo <= flow && flow <= currentReqFlowHi)
{
/// Flow is within range
isFlowOkDuration++;
isFlowOkDuration++; /// Increment the flow within range duration
if (isFlowOkDuration >= regV.FlowStableSec)
{
/// Flow is within range for sufficiently long time
if (regV.regValveCfg.StoredPositionReuse)
if (regV.StoredPositionReuse)
{
double rvPosition = regV.Position; /// Read the current position
double storedPosition;
@ -333,13 +323,12 @@ namespace TBF.Rig.Uni.RegValve
}
}
/// <summary>Start this operation</summary>
/// <summary>Stop this operation</summary>
public void Stop()
{
if (!leaveFlowControlRunning)
{
/// Stop flow measurement
uniCB.StopFlowControl(false, regV.Idx1);
uniCB.StopFlowControl(false, regV.Idx1); /// Stop the flow measurement
}
opState = OpState.Idle;

View File

@ -1,5 +1,5 @@
///
/// Copyright (c) 2021 Sensus Slovensko a.s.
/// Copyright (c) 2021-2022 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
@ -17,8 +17,6 @@ namespace TBF.Rig.Uni.RegValve
return string.Format("SetRegValvePositionOp({0},{1},{2})", regV.Name, posLoPct, posHiPct);
}
const int CoaxValveNr = 7; /// Coax. valve has number 7
///
/// Internal states of this operation
///
@ -32,7 +30,7 @@ namespace TBF.Rig.Uni.RegValve
OpState opState;
/// Set by the constructor
readonly UniCB cBoard;
readonly UniCB uniCB;
readonly RegValve regV;
readonly int regValveNr;
readonly double posLoPct;
@ -47,24 +45,23 @@ namespace TBF.Rig.Uni.RegValve
/// Set required water flow.
/// Events: FlowSet, FlowTimeOut
/// </summary>
/// <param name="cBoard">Control board device</param>
/// <param name="uniCB">Control board device</param>
/// <param name="_regulValve">Regulation valve component</param>
/// <param name="posLoPct">Lower limit of the position to be achieved</param>
/// <param name="posHiPct">Upper limit of the position to be achieved</param>
/// <param name="timeout">Timeout in sec. for setting the flow</param>
/// <remarks>Only Elde.Valve flow are used, other flow on the lists are ignored</remarks>
public SetRegValvePositionOp(UniCB cBoard, RegValve regValve, double posLoPct, double posHiPct, int timeout)
public SetRegValvePositionOp(UniCB uniCB, RegValve regV, double posLoPct, double posHiPct, int timeout)
{
this.cBoard = cBoard;
if (this.cBoard == null) throw new ArgumentNullException("ctrlBoard");
this.uniCB = uniCB;
if (this.uniCB == null) throw new ArgumentNullException("ctrlBoard");
this.regV = regValve as RegValve;
if (this.regV == null) throw new ArgumentNullException("regValve is null or not Elde");
this.regV = regV as RegValve;
if (this.regV == null) throw new ArgumentNullException("regValve is null or not Uni");
this.regValveNr = this.regV.Idx1;
this.posLoPct = posLoPct;
this.posHiPct = posHiPct;
this.timeout = timeout;
log.Debug(this.ToString());
@ -88,7 +85,9 @@ namespace TBF.Rig.Uni.RegValve
opState = OpState.MoveToPosition;
}
/// <summary>Run this operation</summary>
/// <summary>
/// Run this operation
/// </summary>
/// <returns>
/// Event.None . . . . . . . busy adjusting position
/// Event.PositionReached . . position reached
@ -98,29 +97,25 @@ namespace TBF.Rig.Uni.RegValve
{
if (opState == OpState.MoveToPosition)
{
if (posLoPct >= posHiPct || posLoPct > 100.0f || posHiPct < 0)
if (posLoPct >= posHiPct || posLoPct > 100.0 || posHiPct < 0)
{
return Event.OpArgumentError;
}
regV.MoveToPosition(false, posLoPct, posHiPct);
opState = OpState.CheckState;
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}%", regValveNr, positionPct.ToString("F1"));
log.WarnFormat("Run(): RV#={0}, state={1}, pos={2}%", regValveNr, opState, positionPct.ToString("F1"));
if (opState == OpState.CheckState)
{
if (regValveNr == CoaxValveNr && (cBoard.State & (ulong)StatusP.CoaxRegValveBusy) == 0)
{
opState = OpState.MoveToPosition;
return Event.None;
}
else if (posLoPct <= positionPct && positionPct <= posHiPct)
if (posLoPct <= positionPct && positionPct <= posHiPct)
{
positionReached = true;
return Event.PositionReached;
@ -153,6 +148,8 @@ namespace TBF.Rig.Uni.RegValve
}
/// <summary>Stop this operation</summary>
public void Stop() { }
public void Stop()
{
}
}
}