CounterBalanceValve

model CounterBalanceValve
    import HydraulicsByFluidon.Media;
    import HydraulicsByFluidon.Media.Base.FluidInterface;

    outer HydraulicsByFluidon.Media.Environment environment;

    extends HydraulicsByFluidon.Components.Base.HydTwoPortVerticalExt;

    parameter Modelica.SIunits.VolumeFlowRate NominalVolumeFlow = 0.001 "Nominal volume flow"
        annotation (Dialog(group = "Flow parameters"));
    parameter Modelica.SIunits.Pressure NominalPressureDifference = 3e+6 "Nominal pressure difference"
        annotation (Dialog(group = "Flow parameters"));
    parameter Modelica.SIunits.Density ReferenceDensity = 860 "Reference density for volume flow and pressure difference"
        annotation (Dialog(group = "Flow parameters"));
    parameter Modelica.SIunits.Pressure ReliefPressure = 2e+7 "Relief pressure A->B"
        annotation (Dialog(group = "Flow parameters"));
    parameter Modelica.SIunits.Pressure ReliefPressureDifference = 1.5e+7 "Relief pressure difference A->B"
        annotation (Dialog(group = "Flow parameters"));
    parameter Modelica.SIunits.Pressure OpeningPressure = 100000 "Opening pressure difference B->A"
        annotation (Dialog(group = "Flow parameters"));
    parameter Modelica.SIunits.DimensionlessRatio pilotRatio = 3 "Pilot ratio"
        annotation (Dialog(group = "Flow control"));
    parameter Modelica.SIunits.Time timeConstant(final min = 0.001) = 0.05 "Response time of valve spool"
        annotation (Dialog(group = "Flow control"));
    parameter Modelica.SIunits.Volume deadVolume(final min = 1e-9) = 1e-6 "Dead volume at ports"
        annotation (Dialog(group = "Geometry"));
    parameter Boolean enableStrokeOutput = false "Enable spool stroke output"
        annotation (choices(checkBox = true));
    Modelica.Blocks.Interfaces.RealOutput spoolStroke if enableStrokeOutput "Spool stroke"
        annotation (Placement(
            visible = true,
            transformation(
                origin = {100, -40},
                extent = {
                    {-10, -10}, 
                    {10, 10}},
                rotation = 0),
            iconTransformation(
                extent = {
                    {100, -30}, 
                    {120, -10}},
                rotation = 0)));
    HydraulicsByFluidon.Interfaces.FluidPort fluidPortPilot(p(start = environment.pAmbient, nominal = 100000)) "Hydraulic port pilot"
        annotation (Placement(
            visible = true,
            transformation(
                extent = {
                    {90, 10}, 
                    {110, -10}},
                rotation = 0),
            iconTransformation(
                extent = {
                    {100, 30}, 
                    {120, 10}},
                rotation = 0)));
    HydraulicsByFluidon.Components.Valves.Base.IdealReliefResistor Resistor(NominalPressureDifference = NominalPressureDifference, NominalVolumeFlow = NominalVolumeFlow, ReferenceDensity = ReferenceDensity, forwardFluidProperties = forwardFluidProperties) annotation (Placement(
        visible = true,
        transformation(
            origin = {0, 0},
            extent = {
                {10, -10}, 
                {-10, 10}},
            rotation = 0)));
    HydraulicsByFluidon.Components.Volumes.Volume volumeB(capacity = deadVolume) annotation (Placement(
        visible = true,
        transformation(
            origin = {0, 60},
            extent = {
                {-10, -10}, 
                {10, 10}},
            rotation = 0)));
    HydraulicsByFluidon.Components.Volumes.Volume volumeA(capacity = deadVolume) annotation (Placement(
        visible = true,
        transformation(
            origin = {0, -60},
            extent = {
                {-10, -10}, 
                {10, 10}},
            rotation = 0)));
protected
    Real ssU "Steady state valve input";
    Real dU(start = 1) "dynamic valve input";
equation
    if enableStrokeOutput then 
        spoolStroke = ssU;
    end if;
    if forwardFluidProperties then 
        fluidPortPilot.fluidTemperature = fluidPortA.fluidTemperature;
        fluidPortPilot.fluidId = fluidPortA.fluidId;
        fluidPortPilot.proportionUndissolvedAir = fluidPortA.proportionUndissolvedAir;
        fluidPortPilot.polytropicExponent = fluidPortA.polytropicExponent;
    end if;
    if fluidPortB.p < fluidPortA.p then 
        Resistor.dpOffset = min(fluidPortA.p - fluidPortB.p, max(0, ReliefPressure - (fluidPortPilot.p - environment.pAmbient) * pilotRatio));
        Resistor.pScaling = ReliefPressureDifference / NominalPressureDifference;
    else 
        Resistor.dpOffset = 0;
        Resistor.pScaling = 1;
    end if;
    connect(fluidPortA,volumeA.fluidPort) annotation (Line(
        points = {
            {0, -100}, 
            {0, -60}},
        color = {0, 93, 152}));
    connect(fluidPortB,volumeB.fluidPort) annotation (Line(
        points = {
            {0, 100}, 
            {0, 60}},
        color = {0, 93, 152}));
    connect(Resistor.fluidPortA,volumeA.fluidPort) annotation (Line(
        points = {
            {0, -10}, 
            {0, -60}},
        color = {0, 93, 152}));
    connect(Resistor.fluidPortB,volumeB.fluidPort) annotation (Line(
        points = {
            {0, 10}, 
            {0, 60}},
        color = {0, 93, 152}));
    der(dU) * timeConstant = ssU - dU;
    ssU = max(0, min(1, (fluidPortA.p - environment.pAmbient - ReliefPressure + pilotRatio * (fluidPortPilot.p - environment.pAmbient) - (fluidPortB.p - environment.pAmbient) * (pilotRatio + 1)) / ReliefPressureDifference)) + max(0, 1e-5 * (fluidPortB.p - OpeningPressure - fluidPortA.p));
    Resistor.u = dU;
    fluidPortPilot.mFlow = 0;

    annotation (
        Icon(
            coordinateSystem(
                extent = {
                    {-140, -100}, 
                    {140, 100}},
                preserveAspectRatio = true),
            graphics = {
                Line(points = {
                    {0, -100}, 
                    {0, 100}}), 
                Rectangle(
                    fillColor = {255, 255, 255},
                    fillPattern = FillPattern.Solid,
                    extent = {
                        {-40, 40}, 
                        {40, -40}}), 
                Polygon(
                    origin = {20, 40},
                    fillPattern = FillPattern.Solid,
                    points = {
                        {0, 0}, 
                        {-5, -20}, 
                        {5, -20}, 
                        {0, 0}}), 
                Line(
                    origin = {20, -10},
                    points = {
                        {0, 30}, 
                        {0, -30}}), 
                Line(
                    origin = {0, -40},
                    rotation = 180,
                    points = {
                        {0, 0}, 
                        {-40, 40}, 
                        {-80, 40}, 
                        {-80, -20}, 
                        {-40, -20}},
                    pattern = LinePattern.Dash), 
                Line(
                    origin = {-40, -20},
                    points = {
                        {0, 0}, 
                        {-4, -20}, 
                        {-12, 20}, 
                        {-20, -20}, 
                        {-28, 20}, 
                        {-36, -20}, 
                        {-44, 20}, 
                        {-48, 0}}), 
                Rectangle(
                    origin = {80, 40},
                    fillColor = {255, 255, 255},
                    fillPattern = FillPattern.Solid,
                    extent = {
                        {-40, 0}, 
                        {20, -40}}), 
                Polygon(
                    origin = {-72.5, 35},
                    fillPattern = FillPattern.Solid,
                    points = {
                        {0, 0}, 
                        {9.57, -18.36}, 
                        {-0.89, -20.69}, 
                        {0, 0}}), 
                Line(
                    origin = {-52.5, -55},
                    points = {
                        {0, 0}, 
                        {-20, 90}}), 
                Line(
                    origin = {-120, 12.5},
                    rotation = 270,
                    points = {
                        {0, 0}, 
                        {4, -20}, 
                        {12, 20}, 
                        {20, -20}, 
                        {28, 20}, 
                        {36, -20}, 
                        {44, 20}, 
                        {48, 0}}), 
                Line(
                    origin = {-120, 36.5},
                    rotation = 180,
                    points = {
                        {-20, 20}, 
                        {0, 0}, 
                        {20, 20}}), 
                Ellipse(
                    origin = {-120, 22},
                    fillColor = {255, 255, 255},
                    fillPattern = FillPattern.Solid,
                    extent = {
                        {-10, -10}, 
                        {10, 10}},
                    endAngle = 360), 
                Polygon(
                    origin = {100, 20},
                    fillPattern = FillPattern.Solid,
                    points = {
                        {0, 0}, 
                        {0, 20}, 
                        {-34.6, 0}, 
                        {0, -20}, 
                        {0, 0}}), 
                Line(
                    origin = {0, 40},
                    points = {
                        {0, 0}, 
                        {-20, 20}, 
                        {-80, 20}, 
                        {-80, -40}},
                    pattern = LinePattern.Dash), 
                Line(
                    origin = {-60, 58},
                    points = {
                        {60, 22}, 
                        {-60, 22}, 
                        {-60, -22}}), 
                Line(
                    origin = {-60, -34},
                    points = {
                        {60, -46}, 
                        {-60, -46}, 
                        {-60, 46}}), 
                Ellipse(
                    origin = {0, 80},
                    fillPattern = FillPattern.Solid,
                    extent = {
                        {-2.5, 2.5}, 
                        {2.5, -2.5}},
                    endAngle = 360), 
                Ellipse(
                    origin = {0, -80},
                    fillPattern = FillPattern.Solid,
                    extent = {
                        {-2.5, 2.5}, 
                        {2.5, -2.5}},
                    endAngle = 360)}),
        Documentation(info = "<html>\n                <p>\n                    The component CounterBalanceValve is a model of a counterbalance valve (or load control valve) with signal based\n                    dynamics of the spool.\n                </p>\n                <p>\n                    <center><img src=\"modelica://HydraulicsByFluidon/Resources/Images/Components/Valves/PressureValves/CounterBalanceValve.png\"></center>\n                </p>\n                <p>\n                    The following images show how to determine the parameters of the valve.\n                </p>\n                <p>\n                    The flow characteristic of fully opened valve is given by parameters <var>Nominal volume flow</var> and \n                    <var>Nominal pressure difference</var>.\n                </p>\n                <p>\n                    <center><img src=\"modelica://HydraulicsByFluidon/Resources/Images/Components/Valves/PressureValves/CounterBalanceValveFreeFlow.png\"></center>\n                </p>\n                <p>\n                    Relief and pilot performance diagram gives the parameters <var>Relief pressure A->B</var> and <var>Relief pressure difference A->B</var>.\n                </p>\n                <p>\n                    <center><img src=\"modelica://HydraulicsByFluidon/Resources/Images/Components/Valves/PressureValves/CounterBalanceValveRelief.png\"></center>\n                </p>\n                <p>\n                    <var>Pilot ratio</var> is one the main characteristics of a counter balance valve and is given in the data sheet.\n                </p>\n                <p>\n                    <var>Opening pressure difference B->A</var> is a characteristics parameter of the check valve for reverse flow. It can be determined also from free flow diagram.\n                    In the presented diagram the opening pressure difference is very small. Typically, values are around 1 bar.\n                </p>\n                <p>\n                    Counterbalance valves are used with cylinders to safely hold suspended loads and deal with over-running loads. \n                    This valve can also be used with hydraulic motors and is then commonly called a brake valve. Both counterbalance \n                    valves and pilot-operated check valves can be used to lock fluid in a cylinder to prevent drifting. \n                    However, a pilot-operated check valve cannot control an over-running load. Whenever uncontrolled movement \n                    can occur from an overrunning load, a counterbalance valve should be used.\n                </p>\n                </html>"));
end CounterBalanceValve;