tbf/TestBenchFramework/BenchControl/TestBenchSim.cs
Milan Hanajik 08468e60d6 - reconfigured to use Munich component and 5 watermeters
- valve categories used in paths, Category property added to IValve
2014-09-02 18:10:16 +02:00

434 lines
13 KiB
C#

using System;
using log4net;
namespace TBF.BenchControl
{
/// <summary>
/// Test bench model inherited by all classes for the simulation of devices.
/// Define DN100, MUNICH or nothing.
/// </summary>
public class TestBenchSim
{
private static readonly ILog log = LogManager.GetLogger(typeof(TestBenchSim));
///
/// Incremented in RunDevice() depending on diverters and valves
///
public static float Mass1sim; /// Volume in [ltr] or mass in [kg] in the tank1 on the balance1, filled by the diverter1
public static float Mass2sim; /// Volume in [ltr] or mass in [kg] in the tank2 on the balance2, filled by the diverter2
///
/// Set by regulation valves
///
public static float Flow1sim; /// flow in [m3/h] through RV1
public static float Flow2sim; /// flow in [m3/h] through RV2
public static float Flow3sim; /// flow in [m3/h] through RV3
public static float Flow4sim; /// flow in [m3/h] through RV4
public static float Flow5sim; /// flow in [m3/h] through RV5
///
/// Valves and diverters
///
public static ulong RouteSim;
public static bool Div1sim;
public static bool Div2sim;
public static bool Div3sim;
int regulValveNo; /// 0=undefined, 1..5
int refFlowmtrNo; /// 0=undefined, 1..4
public void Initialize()
{
Mass1sim = 0.0f; /// Initialize tanks
Mass2sim = 0.0f;
Flow1sim = 0.0f; /// Initialize regulation valves
Flow2sim = 0.0f;
Flow3sim = 0.0f;
Flow4sim = 0.0f;
Flow5sim = 0.0f;
RouteSim = 0; /// Initialize other valves
Div1sim = false;
Div2sim = false;
Div3sim = false;
}
#if DN100
/// Paths modulating the flows
const ulong K5 = (1 << 0);
const ulong K7 = (1 << 1);
const ulong K10 = (1 << 2);
const ulong K13 = (1 << 3);
const ulong K16 = (1 << 4);
const ulong K2 = (1 << 5);
const ulong EmptyValve1 = (1 << 17);
const ulong EmptyValve2 = (1 << 18);
const ulong Vl5 = (1 << 21);
const ulong Path1 = K2 | K5 | K7;
const ulong Path2 = K2 | K5 | K10;
const ulong Path3 = K2 | K5 | K13;
const ulong Path4 = K2 | K5 | K16;
const ulong Path5 = K2 | K5 | Vl5;
#elif MUNICH
const ulong VL11 = (1 << 0);
const ulong VL13 = (1 << 1);
const ulong VL21 = (1 << 2);
const ulong VL23 = (1 << 3);
const ulong VZ1 = (1 << 4);
const ulong VP2 = (1 << 5);
const ulong VP4 = (1 << 6);
const ulong VP5 = (1 << 7);
const ulong VP6 = (1 << 8);
const ulong VL12 = (1 << 9);
const ulong VL22 = (1 << 10);
const ulong VI11 = (1 << 11);
const ulong VI12 = (1 << 12);
const ulong VI13 = (1 << 13);
const ulong VI21 = (1 << 14);
const ulong VI22 = (1 << 15);
const ulong VI2P = (1 << 16);
const ulong VI31 = (1 << 17);
const ulong VI32 = (1 << 18);
const ulong VI3P = (1 << 19);
const ulong VI41 = (1 << 20);
const ulong VI42 = (1 << 21);
const ulong VI43 = (1 << 22);
const ulong VI4P = (1 << 23);
const ulong VB1 = (1 << 24);
const ulong VB1a = (1 << 25);
const ulong VB2 = (1 << 26);
const ulong VB2a = (1 << 27);
const ulong VM1 = (1 << 28);
const ulong VM2 = (1 << 29);
const ulong VM3 = (1 << 30);
const ulong VM4 = ((ulong)1 << 31);
const ulong Pump1 = ((ulong)1 << 32);
const ulong Block = ((ulong)1 << 33);
const ulong VZ8 = ((ulong)1 << 37);
const ulong EmptyValve1 = VB1 | VB1a;
const ulong EmptyValve2 = VB2 | VB2a;
const ulong Path1 = VZ1 | VL12 | VI11 | VI13;
const ulong Path2 = VZ1 | VL11 | VL12 | VI21 | VI22 | VI13;
const ulong Path3 = VZ1 | VL11 | VL12 | VI31 | VI32;
const ulong Path4 = VZ1 | VL11 | VL12 | VI41 | VI42;
const ulong Path5 = VZ1 | VL11 | VL12 | VI41 | VI43;
#elif FUZHOU150
const ulong VL11 = (1 << 2);
const ulong VL13 = (1 << 3);
const ulong VL4 = (1 << 4);
const ulong VZ6 = (1 << 5);
const ulong VZ7 = (1 << 6);
const ulong VP5 = (1 << 7);
const ulong VP6 = (1 << 8);
const ulong VL12 = (1 << 9);
const ulong VZ14 = (1 << 10);
const ulong VI11 = (1 << 11);
const ulong VI12 = (1 << 12);
const ulong VI13 = (1 << 13);
const ulong VI21 = (1 << 14);
const ulong VI22 = (1 << 15);
const ulong VI2p = (1 << 16);
const ulong VI31 = (1 << 17);
const ulong VI32 = (1 << 18);
const ulong VI3p = (1 << 19);
const ulong VI41 = (1 << 20);
const ulong VI42 = (1 << 21);
const ulong VI43 = (1 << 22);
const ulong VI4p = (1 << 23);
const ulong VB1 = (1 << 24);
const ulong VB1a = (1 << 25);
const ulong VB2 = (1 << 26);
const ulong VB2a = (1 << 27);
const ulong VM1 = (1 << 28);
const ulong VM2 = (1 << 29);
const ulong VM3 = (1 << 20);
const ulong Pump1 = ((ulong)1 << 32);
const ulong Pump4 = ((ulong)1 << 33);
const ulong Pump2 = ((ulong)1 << 37);
const ulong Pump3 = ((ulong)1 << 38);
const ulong Pump5 = ((ulong)1 << 39);
const ulong EmptyValve1 = VB1 | VB1a;
const ulong EmptyValve2 = VB2 | VB2a;
const ulong Path1 = VL12 | VI11 | VI13;
const ulong Path2 = VL12 | VI21 | VI22 | VI13;
const ulong Path3 = VL12 | VI31 | VI32;
const ulong Path4 = VL12 | VI41 | VI42;
const ulong Path5 = VL12 | VI41 | VI43;
#elif FUZHOU300
const ulong VL11 = (1 << 2);
const ulong VL13 = (1 << 3);
const ulong VL4 = (1 << 4);
const ulong VZ6 = (1 << 5);
const ulong VZ7 = (1 << 6);
const ulong VP5 = (1 << 7);
const ulong VP6 = (1 << 8);
const ulong VL12 = (1 << 9);
const ulong VZ14 = (1 << 10);
const ulong VI11 = (1 << 11);
const ulong VI12 = (1 << 12);
const ulong VI13 = (1 << 13);
const ulong VI21 = (1 << 14);
const ulong VI22 = (1 << 15);
const ulong VI2p = (1 << 16);
const ulong VI31 = (1 << 17);
const ulong VI32 = (1 << 18);
const ulong VI3p = (1 << 19);
const ulong VI41 = (1 << 20);
const ulong VI42 = (1 << 21);
const ulong VI43 = (1 << 22);
const ulong VI4p = (1 << 23);
const ulong VB1 = (1 << 24);
const ulong VB1a = (1 << 25);
const ulong VB2 = (1 << 26);
const ulong VB2a = (1 << 27);
const ulong VM1 = (1 << 28);
const ulong VM2 = (1 << 29);
const ulong VM3 = (1 << 20);
const ulong Pump1 = ((ulong)1 << 32);
const ulong Pump4 = ((ulong)1 << 33);
const ulong Pump2 = ((ulong)1 << 37);
const ulong Pump3 = ((ulong)1 << 38);
const ulong Pump5 = ((ulong)1 << 39);
const ulong EmptyValve1 = VB1 | VB1a;
const ulong EmptyValve2 = VB2 | VB2a;
const ulong Path1 = VL12 | VI11 | VI13;
const ulong Path2 = VL12 | VI21 | VI22 | VI13;
const ulong Path3 = VL12 | VI31 | VI32;
const ulong Path4 = VL12 | VI41 | VI42;
const ulong Path5 = VL12 | VI41 | VI43;
#else
/// Paths modulating the flows
const ulong V1 = (1 << 1);
const ulong V2 = (1 << 2);
const ulong V3 = (1 << 3);
const ulong V3b = (1 << 4);
const ulong V4 = (1 << 5);
const ulong V4b = (1 << 6);
const ulong V5 = (1 << 7);
const ulong V5b = (1 << 8);
const ulong EmptyValve1 = (1 << 9); // =Ve1
const ulong EmptyValve2 = (1 << 10); // =Ve2
const ulong Path1 = V1 | V3 | V3b | V4 | V4b;
const ulong Path2 = V2 | V3 | V3b | V5 | V5b;
const ulong Path3 = 0;
const ulong Path4 = 0;
const ulong Path5 = 0;
#endif
/// <summary>Run this device</summary>
public void RunDevice(int regulValveNo, int refFlowmtrNo, Elde.StatusP statusP)
{
this.regulValveNo = regulValveNo;
this.refFlowmtrNo = refFlowmtrNo;
float time = 1.0f;
#if DN100
if (Div1sim && (RouteSim & Path1) == Path1) Mass1sim += DiffKg(Flow1sim, time);
if (Div1sim && (RouteSim & Path2) == Path2) Mass1sim += DiffKg(Flow2sim, time);
if (Div2sim && (RouteSim & Path3) == Path3) Mass2sim += DiffKg(Flow3sim, time);
if (Div2sim && (RouteSim & Path4) == Path4) Mass2sim += DiffKg(Flow4sim, time);
if (Div1sim && (RouteSim & Path5) == Path5) Mass1sim += DiffKg(Flow5sim, time);
#elif MUNICH || FUZHOU150 || FUZHOU300
if (Div1sim && (RouteSim & Path1) == Path1) Mass1sim += DiffKg(Flow1sim, time);
if (Div1sim && (RouteSim & Path2) == Path2) Mass1sim += DiffKg(Flow2sim, time);
if (Div2sim && (RouteSim & Path3) == Path3)
{
Mass2sim += DiffKg(Flow3sim, time);
}
if (Div3sim && (RouteSim & Path4) == Path4) Mass2sim += DiffKg(Flow4sim, time);
if (Div3sim && (RouteSim & Path5) == Path5) Mass2sim += DiffKg(Flow5sim, time);
#else
if (Div1sim && (RouteSim & Path1) == Path1) Mass1sim += DiffKg(Flow1sim, time);
if (Div2sim && (RouteSim & Path2) == Path2) Mass2sim += DiffKg(Flow2sim, time);
#endif
if ((RouteSim & EmptyValve1) == EmptyValve1) Mass1sim -= DiffKg(100.0f, time);
if (Mass1sim < 0) Mass1sim = 0;
if ((RouteSim & EmptyValve2) == EmptyValve2) Mass2sim -= DiffKg(10.0f, time);
if (Mass2sim < 0) Mass2sim = 0;
UiBridge.Bridge.OnLog(this, string.Format("I{1}/RV{2}: q1={3}, q2={4}, q3={5}, q4={6}, q5={7}, D123={8}{9}{10}, m1={11}, m2={12}, S={13}\r\n",
time,
refFlowmtrNo, regulValveNo,
Flow1sim.ToString("F1"), Flow2sim.ToString("F1"), Flow3sim.ToString("F1"), Flow4sim.ToString("F1"), Flow5sim.ToString("F1"),
(Div1sim ? "o" : "x"), (Div2sim ? "o" : "x"), (Div3sim ? "o" : "x"),
Mass1sim.ToString("F1"), Mass2sim.ToString("F1"), ((ulong)statusP).ToString("X")));
}
/// <summary>
/// Calculate the mass change from the flow and the time period
/// </summary>
/// <param name="flowM3H">Flow in [m3/h]</param>
/// <param name="timeSec">Time period in [s]</param>
/// <returns>Mass change in [kg]</returns>
float DiffKg(float flowM3H, float timeSec)
{
return timeSec * flowM3H / 3.6f;
}
/// <summary>
/// Get the simulated mass. Use the balance range to distinguish the balances.
/// </summary>
/// <param name="balanceNr">0-based balance number</param>
/// <returns>Simulated mass reading [kg]</returns>
public float GetSimMass(int balanceNr)
{
if (balanceNr == 0) return Mass1sim;
else if (balanceNr == 1) return Mass2sim;
else return 0;
}
/// <summary>
/// Set the simulated diverter. Use the nominal flow to distinguish the path.
/// </summary>
/// <param name="toTank">Diverter state: true = to the tank</param>
/// <param name="nominalFlow">Nominal flow of the path [m3/h]</param>
public void SetSimDiverter(bool toTank)
{
#if DN100
switch (regulValveNo)
{
case 1:
case 2:
case 5:
Div1sim = toTank;
break;
case 3:
case 4:
Div2sim = toTank;
break;
default:
if (toTank) { throw (new Exception()); }
break;
}
#elif MUNICH || FUZHOU150 || FUZHOU300
switch (regulValveNo)
{
case 1:
case 2:
Div1sim = toTank;
break;
case 3:
Div2sim = toTank;
break;
case 4:
case 5:
Div3sim = toTank;
break;
default:
if (toTank) { throw (new Exception()); }
break;
}
#else
switch (regulValveNo)
{
case 1: Div1sim = toTank; break;
case 2: Div2sim = toTank; break;
default:
if (toTank) { throw (new Exception()); }
break;
}
#endif
return;
}
/// <summary>
/// Determine which autput section is used
/// </summary>
/// <param name="nominalFlow"></param>
/// <returns></returns>
int OutputPathId(float nominalFlow)
{
#if DN100
//
// Qn1=0.3, Qn2=2.5, Qn3=25, Qn4=250, Qn5=0.2
//
if (nominalFlow < 0.25f) return 5;
else if (nominalFlow < 1.0f) return 1;
else if (nominalFlow < 10.0f) return 2;
else if (nominalFlow < 100.0f) return 3;
else return 4;
#elif MUNICH
//
// Qn1=200, Qn2=20, Qn3=3, Qn4=0.25
//
if (nominalFlow <= 0.25f) return 4;
else if (nominalFlow <= 3.0f) return 3;
else if (nominalFlow <= 20.0f) return 2;
else return 1;
#elif FUZHOU150
//
// Qn1=350, Qn2=50, Qn3=7, Qn4=0.5
//
if (nominalFlow <= 0.5f) return 4;
else if (nominalFlow <= 7.0f) return 3;
else if (nominalFlow <= 50.0f) return 2;
else return 1;
#elif FUZHOU300
//
// Qn1=350, Qn2=50, Qn3=7, Qn4=0.5
//
if (nominalFlow <= 0.5f) return 4;
else if (nominalFlow <= 7.0f) return 3;
else if (nominalFlow <= 50.0f) return 2;
else return 1;
#else
//
// Qn1=1, Qn2=10
//
if (nominalFlow < 3.0f) return 1;
else return 2;
#endif
}
/// <summary>
/// Get the simulated flow in [m3/h].
/// </summary>
/// <returns>Simulated flow [m3/h]</returns>
public float GetSimFlow()
{
switch (refFlowmtrNo)
{
case 1: return ((RouteSim & Path1) == Path1) ? Flow1sim : 0;
case 2: return ((RouteSim & Path2) == Path2) ? Flow2sim : 0;
case 3: return ((RouteSim & Path3) == Path3) ? Flow3sim : 0;
case 4: return (((RouteSim & Path4) == Path4) ? Flow4sim : 0) +
(((RouteSim & Path5) == Path5) ? Flow5sim : 0);
default: return 0;
}
}
/// <summary>
/// Update simulated flow. Use the nominal flow to distinguish the path.
/// </summary>
/// <param name="targetFlow">Target flow [m3/h]</param>
/// <param name="nominalFlow">Nominal flow of the path [m3/h]</param>
public void UpdateSimFlow(float targetFlow)
{
float A = 0.7f; /// higher value -> slower regulation
float B = 1.0f - A;
switch (regulValveNo)
{
case 1: Flow1sim = A * Flow1sim + B * targetFlow; break;
case 2: Flow2sim = A * Flow2sim + B * targetFlow; break;
case 3: Flow3sim = A * Flow3sim + B * targetFlow; break;
case 4: Flow4sim = A * Flow4sim + B * targetFlow; break;
case 5: Flow5sim = A * Flow5sim + B * targetFlow; break;
default: break;
}
}
}
}