I am trying to create a model for a poppet valve with a mass element that is held down by a spring and opens when the pressure force on the inlet side is greater than the sum of the spring force and outlet side pressure force.
I have decided to do this by creating a "controller" which takes the fluid pressure on the inlet side and outlet side as input and output a [0,1] signal for the openess of the valve that it controlls.
Like in the MSL sliding mass with stop component, I have introduced a stopped variable which is -1 when the position of the mass s is below the min value and 1 when s > smax. When s becomes a non zero value (i.e. at either stop) the position and velocity of the mass element is reinitiated.
However, the position keeps going well above the smax value that I have set and not sure what the reason for it is.
package ValveCompIdea
model ValveCompSlideMass
replaceable package Medium = Modelica.Media.Water.StandardWater "Medium in the component" annotation(
choicesAllMatching = true);
//parameters
parameter Real eps = 1e-2 "stopped sensor error";
parameter Modelica.Units.SI.Mass m=0.15 "mass of moving parts";
parameter Modelica.Units.SI.Length smax=0.0033 "max displacement";
parameter Modelica.Units.SI.Length smin=0 "min displacement";
parameter Modelica.Units.SI.TranslationalSpringConstant k=19.8e3 "spring constant";
//parameter Modelica.Units.SI.Length s0=0.0033 "Spring free height";
parameter Modelica.Units.SI.Area SAIn=90e-6 "piston surface area - Inlet side";
parameter Modelica.Units.SI.Area SAOut=30e-6 "piston surface area - Outlet side";
parameter Modelica.Units.SI.Force preload = -171 "Spring preload (PreComp = Negative N)";
parameter Modelica.Units.SI.Force uHigh = 15"Hysterisis Upper";
parameter Modelica.Units.SI.Force uLow = -15"Hysterisis Lower";
parameter Boolean pre_moving_start=true "Value of pre(moving) at initial time";
//variables
Boolean moving;
Integer stopped(start = 0) "-1 stopped at min, 0 not stopped, 1 stopped at max";
Modelica.Units.SI.Position s(start = 0) "spring end position";
Modelica.Units.SI.Velocity v "spring end velocity";
Modelica.Units.SI.Acceleration a "spring end acceleration";
Modelica.Units.SI.Force sprf "spring force";
Modelica.Units.SI.Force prsf "Pressure force";
Modelica.Units.SI.Force nf "Net Force on mass";
Modelica.Units.SI.Pressure pIn "Inletside pressure";
Modelica.Units.SI.Pressure pOut "Outletside pressure";
Modelica.Fluid.Interfaces.FluidPort_a port_In(redeclare package Medium = Medium) annotation(
Placement(transformation(origin = {100, 0}, extent = {{-10, -10}, {10, 10}}), iconTransformation(origin = {0, 100}, extent = {{-20, -20}, {20, 20}})));
Modelica.Blocks.Interfaces.RealOutput y annotation(
Placement(transformation(origin = {2, -96}, extent = {{-10, -10}, {10, 10}}, rotation = -90), iconTransformation(origin = {100, 0}, extent = {{-20, -20}, {20, 20}})));
Modelica.Fluid.Sensors.Pressure pressureIn(redeclare package Medium = Medium) annotation(
Placement(transformation(origin = {30, 10}, extent = {{10, -10}, {-10, 10}})));
Modelica.Fluid.Interfaces.FluidPort_a port_Out(redeclare package Medium = Medium) annotation(
Placement(transformation(origin = {100, -80}, extent = {{-10, -10}, {10, 10}}), iconTransformation(origin = {0, -100}, extent = {{-20, -20}, {20, 20}})));
Modelica.Fluid.Sensors.Pressure pressureOut(redeclare package Medium = Medium) annotation(
Placement(transformation(origin = {30, -70}, extent = {{10, -10}, {-10, 10}})));
initial equation
nf = prsf + sprf;
pre(moving) = pre_moving_start;
equation
//I-O definitions
pressureIn.p = pIn;
pressureOut.p = pOut;
y = if (s <= smin) then 0 else if (s >= smax) then 1 else 1 - (smax-s)/(smax-smin);
//mass mechanics
v = der(s);
a = der(v);
m * a = nf;
//forces on mass
sprf = k * (smin - s) + preload;
prsf = pIn * SAIn + pOut * SAOut;
//stop state
stopped = if s <= smin then -1 elseif s >= smax then 1 else 0;
moving = not pre(moving) and prsf+sprf > uHigh or pre(moving) and prsf+sprf >= uLow;
//stop contact
when stopped <> 0 then
reinit(s,if stopped < 0 then smin else smax);
reinit(v,0);
end when;
when not moving then
reinit(s,if s<smin then smin else smax);
reinit(v,0);
end when;
when s > smax or s< smin then
reinit(s,if s > smax then smax else smin);
reinit(v,0);
end when;
nf = if moving then sprf + prsf else 0;
//connection
connect(pressureIn.port, port_In) annotation(
Line(points = {{30, 0}, {100, 0}}, color = {0, 127, 255}, thickness = 0.5));
connect(pressureOut.port, port_Out) annotation(
Line(points = {{30, -80}, {100, -80}}, thickness = 0.5));
annotation(
Icon(graphics = {Text(origin = {2, 61}, extent = {{34, -13}, {-34, 13}}, textString = "In"), Text(origin = {-2, -59}, extent = {{34, -13}, {-34, 13}}, textString = "Out")}));
end ValveCompSlideMass;
model NRVtest
replaceable package Medium = Modelica.Media.Water.StandardWater constrainedby Modelica.Media.Interfaces.PartialMedium;
Modelica.Fluid.Sources.Boundary_pT boundaryOut(p(displayUnit = "bar") = 1e6, nPorts = 1, redeclare package Medium = Medium) annotation(
Placement(transformation(origin = {0, -90}, extent = {{-10, -10}, {10, 10}}, rotation = 90)));
inner Modelica.Fluid.System system(p_ambient = 2e6, energyDynamics = Modelica.Fluid.Types.Dynamics.DynamicFreeInitial, massDynamics = Modelica.Fluid.Types.Dynamics.DynamicFreeInitial, momentumDynamics = Modelica.Fluid.Types.Dynamics.DynamicFreeInitial) annotation(
Placement(transformation(origin = {-130, 90}, extent = {{-10, -10}, {10, 10}})));
Modelica.Fluid.Sources.Boundary_pT boundary(redeclare package Medium = Medium, use_p_in = true, nPorts = 1, p = 5e6) annotation(
Placement(transformation(origin = {-10, 90}, extent = {{-10, -10}, {10, 10}})));
Modelica.Fluid.Pipes.DynamicPipe pipe(redeclare package Medium = Medium, length = 1, diameter = 0.008, height_ab = 0.15) annotation(
Placement(transformation(origin = {0, 50}, extent = {{-10, -10}, {10, 10}}, rotation = -90)));
Modelica.Fluid.Valves.ValveLinear valveLinear(redeclare package Medium = Medium, dp_nominal = 1e5, m_flow_nominal = 100) annotation(
Placement(transformation(extent = {{-10, 10}, {10, -10}}, rotation = -90)));
Modelica.Fluid.Pipes.DynamicPipe pipe1(redeclare package Medium = Medium, diameter = 0.008, height_ab = 0.15, length = 1) annotation(
Placement(transformation(origin = {0, -40}, extent = {{-10, -10}, {10, 10}}, rotation = -90)));
Modelica.Blocks.Sources.Trapezoid trapezoid(amplitude = 100e5, rising = 5, width = 10, falling = 5, period = 30, offset = 1e5) annotation(
Placement(transformation(origin = {-68, 84}, extent = {{-10, -10}, {10, 10}}, rotation = 90)));
ValveCompSlideMass valveCompSlideMass(redeclare package Medium = Medium, s(fixed = true), stopped(fixed = false), uHigh = 50, uLow = -50) annotation(
Placement(transformation(origin = {-40, 0}, extent = {{-10, -10}, {10, 10}})));
equation
connect(boundary.ports[1], pipe.port_a) annotation(
Line(points = {{0, 90}, {0, 60}}, color = {0, 127, 255}));
connect(pipe.port_b, valveLinear.port_a) annotation(
Line(points = {{0, 40}, {0, 10}}, color = {0, 127, 255}));
connect(valveLinear.port_b, pipe1.port_a) annotation(
Line(points = {{0, -10}, {0, -30}}, color = {0, 127, 255}, thickness = 0.5));
connect(pipe1.port_b, boundaryOut.ports[1]) annotation(
Line(points = {{0, -50}, {0, -80}}, color = {0, 127, 255}, thickness = 0.5));
connect(trapezoid.y, boundary.p_in) annotation(
Line(points = {{-68, 95}, {-68, 98}, {-22, 98}}, color = {0, 0, 127}, thickness = 0.5));
connect(valveCompSlideMass.port_In, pipe.port_b) annotation(
Line(points = {{-40, 10}, {-40, 40}, {0, 40}}, color = {0, 127, 255}, thickness = 0.5));
connect(valveCompSlideMass.port_Out, pipe1.port_a) annotation(
Line(points = {{-40, -10}, {-40, -30}, {0, -30}}, color = {0, 127, 255}, thickness = 0.5));
connect(valveCompSlideMass.y, valveLinear.opening) annotation(
Line(points = {{-30, 0}, {-8, 0}}, color = {0, 0, 127}, thickness = 0.5));
annotation(
Diagram);
end NRVtest;
end ValveCompIdea;
UPDATE: Moving some of the when clauses into the algorithm section seems to have resolved my issue
model ValveCompSlideMassAlgo
replaceable package Medium = Modelica.Media.Water.StandardWater "Medium in the component" annotation(
choicesAllMatching = true);
//parameters
parameter Real eps = 1e-2 "stopped sensor error";
parameter Modelica.Units.SI.Mass m = 0.15 "mass of moving parts";
parameter Modelica.Units.SI.Length smax = 0.0033 "max displacement";
parameter Modelica.Units.SI.Length smin = 0 "min displacement";
parameter Modelica.Units.SI.TranslationalSpringConstant k = 19.8e3 "spring constant";
//parameter Modelica.Units.SI.Length s0=0.0033 "Spring free height";
parameter Modelica.Units.SI.Area SAIn = 90e-6 "piston surface area - Inlet side";
parameter Modelica.Units.SI.Area SAOut = 30e-6 "piston surface area - Outlet side";
parameter Modelica.Units.SI.Force preload = -171 "Spring preload (PreComp = Negative N)";
parameter Modelica.Units.SI.Force uHigh = 0.1 "Hysterisis Upper";
parameter Modelica.Units.SI.Force uLow = -0.1 "Hysterisis Lower";
parameter Boolean pre_moving_start = true "Value of pre(moving) at initial time";
//variables
Boolean moving;
Integer stopped(start = 0) "-1 stopped at min, 0 not stopped, 1 stopped at max";
Modelica.Units.SI.Position s(start = 0) "spring end position";
Modelica.Units.SI.Velocity v "spring end velocity";
Modelica.Units.SI.Acceleration a "spring end acceleration";
Modelica.Units.SI.Force sprf "spring force";
Modelica.Units.SI.Force prsf "Pressure force";
Modelica.Units.SI.Force nf "Net Force on mass";
Modelica.Units.SI.Pressure pIn "Inletside pressure";
Modelica.Units.SI.Pressure pOut "Outletside pressure";
Modelica.Fluid.Interfaces.FluidPort_a port_In(redeclare package Medium = Medium) annotation(
Placement(transformation(origin = {100, 0}, extent = {{-10, -10}, {10, 10}}), iconTransformation(origin = {0, 100}, extent = {{-20, -20}, {20, 20}})));
Modelica.Blocks.Interfaces.RealOutput y1 annotation(
Placement(transformation(origin = {2, -96}, extent = {{-10, -10}, {10, 10}}, rotation = -90), iconTransformation(origin = {106, 0}, extent = {{-20, -20}, {20, 20}})));
Modelica.Units.SI.Force sf;
Modelica.Fluid.Sensors.Pressure pressureIn(redeclare package Medium = Medium) annotation(
Placement(transformation(origin = {30, 10}, extent = {{10, -10}, {-10, 10}})));
Modelica.Fluid.Interfaces.FluidPort_a port_Out(redeclare package Medium = Medium) annotation(
Placement(transformation(origin = {100, -80}, extent = {{-10, -10}, {10, 10}}), iconTransformation(origin = {0, -100}, extent = {{-20, -20}, {20, 20}})));
Modelica.Fluid.Sensors.Pressure pressureOut(redeclare package Medium = Medium) annotation(
Placement(transformation(origin = {30, -70}, extent = {{10, -10}, {-10, 10}})));
Modelica.Blocks.Interfaces.RealOutput y2 annotation(
Placement(transformation(origin = {-38, -96}, extent = {{-10, -10}, {10, 10}}, rotation = -90), iconTransformation(origin = {108, -60}, extent = {{-20, -20}, {20, 20}})));
initial equation
nf = prsf + sprf;
pre(moving) = pre_moving_start;
equation
//I-O definitions
pressureIn.p = pIn;
pressureOut.p = pOut;
y1 = if (s <= smin) then 0.00 else if (s >= smax) then 1 else 1 - (smax - s)/(smax - smin);
y2 = if y1 >= 0.1 then 0 else 1;
//mass mechanics
v = der(s);
a = der(v);
m*a = nf;
//forces on mass
sprf = k*(smin - s) + preload;
prsf = pIn*SAIn + pOut*SAOut;
sf = sprf + prsf;
nf = if moving then sf else 0;
//stop state
stopped = if s <= smin then -1 elseif s >= smax then 1 else 0;
//stop contact
when stopped <> 0 then
reinit(s, if stopped < 0 then smin else smax);
reinit(v, 0);
end when;
when not moving then
reinit(s, if stopped < 0 then smin else smax);
reinit(v, 0);
end when;
//connection
connect(pressureIn.port, port_In) annotation(
Line(points = {{30, 0}, {100, 0}}, color = {0, 127, 255}, thickness = 0.5));
connect(pressureOut.port, port_Out) annotation(
Line(points = {{30, -80}, {100, -80}}, thickness = 0.5));
algorithm
when stopped == 0 then
moving := true;
end when;
when stopped < 0 and sf > uHigh then
moving := true;
end when;
when stopped < 0 and sf <= 0 then
moving := false;
end when;
when stopped > 0 and sf >= 0 then
moving := false;
end when;
when stopped > 0 and sf < uLow then
moving := true;
end when;
annotation(
Icon(graphics = {Text(origin = {2, 61}, extent = {{34, -13}, {-34, 13}}, textString = "In"), Text(origin = {-2, -59}, extent = {{34, -13}, {-34, 13}}, textString = "Out"), Line(origin = {61.3119, -0.6238}, points = {{-19, 4}, {19, 4}, {19, -4}, {-19, -4}, {-19, 4}, {-13, 4}}, thickness = 0.5), Line(origin = {61.3119, -68.8232}, points = {{-19, 4}, {19, 4}, {19, -4}, {-19, -4}, {-19, 4}, {-13, 4}}, thickness = 0.5), Line(origin = {60.9743, -49.9164}, points = {{-19, 4}, {19, 4}, {19, -4}, {-19, -4}, {-19, 4}, {-13, 4}}, thickness = 0.5)}));
end ValveCompSlideMassAlgo;
As suggested by Markus adjusting the when statements to avoid multiple when statements being triggered at the same time resolved my problem.
model ValveCompSlideMassAlgo
replaceable package Medium = Modelica.Media.Water.StandardWater "Medium in the component" annotation(
choicesAllMatching = true);
//parameters
parameter Real eps = 1e-2 "stopped sensor error";
parameter Modelica.Units.SI.Mass m = 0.15 "mass of moving parts";
parameter Modelica.Units.SI.Length smax = 0.0033 "max displacement";
parameter Modelica.Units.SI.Length smin = 0 "min displacement";
parameter Modelica.Units.SI.TranslationalSpringConstant k = 19.8e3 "spring constant";
//parameter Modelica.Units.SI.Length s0=0.0033 "Spring free height";
parameter Modelica.Units.SI.Area SAIn = 90e-6 "piston surface area - Inlet side";
parameter Modelica.Units.SI.Area SAOut = 30e-6 "piston surface area - Outlet side";
parameter Modelica.Units.SI.Force preload = -171 "Spring preload (PreComp = Negative N)";
parameter Modelica.Units.SI.Force uHigh = 0.1 "Hysterisis Upper";
parameter Modelica.Units.SI.Force uLow = -0.1 "Hysterisis Lower";
parameter Boolean pre_moving_start = true "Value of pre(moving) at initial time";
//variables
Boolean moving;
Integer stopped(start = 0) "-1 stopped at min, 0 not stopped, 1 stopped at max";
Modelica.Units.SI.Position s(start = 0) "spring end position";
Modelica.Units.SI.Velocity v "spring end velocity";
Modelica.Units.SI.Acceleration a "spring end acceleration";
Modelica.Units.SI.Force sprf "spring force";
Modelica.Units.SI.Force prsf "Pressure force";
Modelica.Units.SI.Force nf "Net Force on mass";
Modelica.Units.SI.Pressure pIn "Inletside pressure";
Modelica.Units.SI.Pressure pOut "Outletside pressure";
Modelica.Fluid.Interfaces.FluidPort_a port_In(redeclare package Medium = Medium) annotation(
Placement(transformation(origin = {100, 0}, extent = {{-10, -10}, {10, 10}}), iconTransformation(origin = {0, 100}, extent = {{-20, -20}, {20, 20}})));
Modelica.Blocks.Interfaces.RealOutput y1 annotation(
Placement(transformation(origin = {2, -96}, extent = {{-10, -10}, {10, 10}}, rotation = -90), iconTransformation(origin = {106, 0}, extent = {{-20, -20}, {20, 20}})));
Modelica.Units.SI.Force sf;
Modelica.Fluid.Sensors.Pressure pressureIn(redeclare package Medium = Medium) annotation(
Placement(transformation(origin = {30, 10}, extent = {{10, -10}, {-10, 10}})));
Modelica.Fluid.Interfaces.FluidPort_a port_Out(redeclare package Medium = Medium) annotation(
Placement(transformation(origin = {100, -80}, extent = {{-10, -10}, {10, 10}}), iconTransformation(origin = {0, -100}, extent = {{-20, -20}, {20, 20}})));
Modelica.Fluid.Sensors.Pressure pressureOut(redeclare package Medium = Medium) annotation(
Placement(transformation(origin = {30, -70}, extent = {{10, -10}, {-10, 10}})));
Modelica.Blocks.Interfaces.RealOutput y2 annotation(
Placement(transformation(origin = {-38, -96}, extent = {{-10, -10}, {10, 10}}, rotation = -90), iconTransformation(origin = {108, -60}, extent = {{-20, -20}, {20, 20}})));
initial equation
nf = prsf + sprf;
pre(moving) = pre_moving_start;
equation
//I-O definitions
pressureIn.p = pIn;
pressureOut.p = pOut;
y1 = if (s <= smin) then 0.00 else if (s >= smax) then 1 else 1 - (smax - s)/(smax - smin);
y2 = if y1 >= 0.1 then 0 else 1;
//mass mechanics
v = der(s);
a = der(v);
m*a = nf;
//forces on mass
sprf = k*(smin - s) + preload;
prsf = pIn*SAIn + pOut*SAOut;
sf = sprf + prsf;
nf = if moving then sf else 0;
//stop state
stopped = if s <= smin then -1 elseif s >= smax then 1 else 0;
//stop contact
when stopped <> 0 then
reinit(s, if stopped < 0 then smin else smax);
reinit(v, 0);
end when;
when not moving then
reinit(s, if stopped < 0 then smin else smax);
reinit(v, 0);
end when;
//connection
connect(pressureIn.port, port_In) annotation(
Line(points = {{30, 0}, {100, 0}}, color = {0, 127, 255}, thickness = 0.5));
connect(pressureOut.port, port_Out) annotation(
Line(points = {{30, -80}, {100, -80}}, thickness = 0.5));
algorithm
when stopped == 0 then
moving := true;
end when;
when stopped < 0 and sf > uHigh then
moving := true;
end when;
when stopped < 0 and sf <= 0 then
moving := false;
end when;
when stopped > 0 and sf >= 0 then
moving := false;
end when;
when stopped > 0 and sf < uLow then
moving := true;
end when;
annotation(
Icon(graphics = {Text(origin = {2, 61}, extent = {{34, -13}, {-34, 13}}, textString = "In"), Text(origin = {-2, -59}, extent = {{34, -13}, {-34, 13}}, textString = "Out"), Line(origin = {61.3119, -0.6238}, points = {{-19, 4}, {19, 4}, {19, -4}, {-19, -4}, {-19, 4}, {-13, 4}}, thickness = 0.5), Line(origin = {61.3119, -68.8232}, points = {{-19, 4}, {19, 4}, {19, -4}, {-19, -4}, {-19, 4}, {-13, 4}}, thickness = 0.5), Line(origin = {60.9743, -49.9164}, points = {{-19, 4}, {19, 4}, {19, -4}, {-19, -4}, {-19, 4}, {-13, 4}}, thickness = 0.5)}));
end ValveCompSlideMassAlgo;