Search code examples
modelicaopenmodelica

Modelica Sliding mass valve implementing a "hard stop" for min and max displacement


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;

Solution

  • 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;