MassWithStopAndFriction

model MassWithStopAndFriction "Sliding mass with hard stop and Stribeck friction"
    extends PartialFrictionWithStop;

    SI.Velocity v(start = 0, stateSelect = StateSelect.always) "Absolute velocity of flange_a and flange_b";
    SI.Acceleration a(start = 0) "Absolute acceleration of flange_a and flange_b";
    parameter Modelica.SIunits.Mass m(start = 1) "Mass";
    parameter Real F_prop(final unit = "N.s/m", final min = 0, start = 1) "Velocity dependent friction";
    parameter Modelica.SIunits.Force F_Coulomb(start = 5) "Constant friction: Coulomb force";
    parameter Modelica.SIunits.Force F_Stribeck(start = 10) "Stribeck effect";
    parameter Real fexp(final unit = "s/m", final min = 0, start = 2) "Exponential decay";

    extends Modelica.Thermal.HeatTransfer.Interfaces.PartialElementaryConditionalHeatPortWithoutT;

    Integer stopped "Mode of stop (-1: hard stop at flange_a, 0: no stop, +1: hard stop at flange_b";

    encapsulated partial model PartialFrictionWithStop "Base model of Coulomb friction elements with stop"
        import SI = Modelica.SIunits;
        import Modelica.Mechanics.Translational.Interfaces.PartialRigid;

        parameter SI.Position smax(start = 25) "Right stop for (right end of) sliding mass";
        parameter SI.Position smin(start = -25) "Left stop for (left end of) sliding mass";
        parameter SI.Velocity v_small = 0.001 "Relative velocity near to zero (see model info text)"
            annotation (Dialog(tab = "Advanced"));
        SI.Velocity v_relfric "Relative velocity between frictional surfaces";
        SI.Acceleration a_relfric "Relative acceleration between frictional surfaces";
        SI.Force f "Friction force (positive, if directed in opposite direction of v_rel)";
        SI.Force f0 "Friction force for v=0 and forward sliding";
        SI.Force f0_max "Maximum friction force for v=0 and locked";
        Boolean free "true, if frictional element is not active";
        Real sa(unit = "1") "Path parameter of friction characteristic f = f(a_relfric)";
        Boolean startForward(start = false, fixed = true) "= true, if v_rel=0 and start of forward sliding or v_rel > v_small";
        Boolean startBackward(start = false, fixed = true) "= true, if v_rel=0 and start of backward sliding or v_rel < -v_small";
        Boolean locked(start = false) "true, if v_rel=0 and not sliding";

        extends PartialRigid(s(start = 0, stateSelect = StateSelect.always));

        constant Integer Unknown = 3 "Value of mode is not known";
        constant Integer Free = 2 "Element is not active";
        constant Integer Forward = 1 "v_rel > 0 (forward sliding)";
        constant Integer Stuck = 0 "v_rel = 0 (forward sliding, locked or backward sliding)";
        constant Integer Backward = -1 "v_rel < 0 (backward sliding)";
        Integer mode(final min = Backward, final max = Unknown, start = Unknown, fixed = true) "Mode of friction (-1: backward sliding, 0: stuck, 1: forward sliding, 2: inactive, 3: unknown)";
    protected
        constant SI.Acceleration unitAcceleration = 1 annotation (HideResult = true);
        constant SI.Force unitForce = 1 annotation (HideResult = true);
    equation
        a_relfric / unitAcceleration = if locked then 0 else if free then sa else if startForward then sa - f0_max / unitForce else if startBackward then sa + f0_max / unitForce else if pre(mode) == Forward then sa - f0_max / unitForce else sa + f0_max / unitForce;
        locked = not free and not (pre(mode) == Forward or startForward or pre(mode) == Backward or startBackward);
        mode = if free then Free else if (pre(mode) == Forward or pre(mode) == Free or startForward) and 0 < v_relfric and s < smax - 0.5 * L then Forward else if (pre(mode) == Backward or pre(mode) == Free or startBackward) and v_relfric < 0 and smin + 0.5 * L < s then Backward else Stuck;
        startBackward = pre(mode) == Stuck and (sa < -f0_max / unitForce and smin + 0.5 * L < s or pre(startBackward) and sa < -f0 / unitForce and smin + 0.5 * L < s) or pre(mode) == Forward and v_relfric < -v_small or initial() and v_relfric < 0;
        startForward = pre(mode) == Stuck and (f0_max / unitForce < sa and s < smax - 0.5 * L or pre(startForward) and f0 / unitForce < sa and s < smax - 0.5 * L) or pre(mode) == Backward and v_small < v_relfric or initial() and 0 < v_relfric;

        annotation (Documentation(info = "<html>\n<p>\nBasic model for Coulomb friction that models the stuck phase in a reliable way.<br>\nAdditionally, a left and right stop are handled.\n</p>\n</html>"));
    end PartialFrictionWithStop;
equation
    when initial() then 
        assert(smin + 0.5 * L < s or smin + 0.5 * L <= s and 0 <= v, "Error in initialization of hard stop. (s - L/2) must be >= smin\n(s=" + String(s) + ", L=" + String(L) + ", smin=" + String(smin) + ")");
        assert(s < smax - 0.5 * L or s <= smax - 0.5 * L and v <= 0, "Error in initialization of hard stop. (s + L/2) must be <= smax\n(s=" + String(s) + ", L=" + String(L) + ", smax=" + String(smax) + ")");
    end when;
    when stopped <> 0 then 
        reinit(s, if stopped < 0 then smin + 0.5 * L else smax - 0.5 * L);
        reinit(v, 0);
    end when;
    0 = flange_a.f + flange_b.f - f - m * der(v);
    a = der(v);
    f = if locked then sa * unitForce else if free then 0 else if startForward then F_prop * v + F_Coulomb + F_Stribeck else if startBackward then F_prop * v - F_Coulomb - F_Stribeck else if pre(mode) == Forward then F_prop * v + F_Coulomb + F_Stribeck * Modelica.Math.exp(-fexp * abs(v)) else F_prop * v - F_Coulomb - F_Stribeck * Modelica.Math.exp(-fexp * abs(v));
    v = der(s);
    a_relfric = a;
    f0 = F_Coulomb + F_Stribeck;
    f0_max = f0 * (1.001);
    free = f0 <= 0 and F_prop <= 0 and smin + 0.5 * L < s and s < smax - 0.5 * L;
    lossPower = f * v_relfric;
    stopped = if s <= smin + 0.5 * L then -1 else if smax - 0.5 * L <= s then 1 else 0;
    v_relfric = v;

    annotation (
        Documentation(
            info = "<html>\n<p>This element describes the <em>Stribeck friction characteristics</em> of a sliding mass,\ni. e. the frictional force acting between the sliding mass and the support. Included is a\n<em>hard stop</em> for the position.</p>\n<p>\nThe surface is fixed and there is friction between sliding mass and surface.\nThe frictional force f is given for positive velocity v by:\n</p>\n<blockquote><pre>\nf = F_Coulomb + F_prop * v + F_Stribeck * exp (-fexp * v)\n</pre></blockquote>\n\n<p>\n<img src=\"modelica://Modelica/Resources/Images/Mechanics/Translational/Stribeck.png\">\n</p>\n\n<p>\nThe distance between the left and the right connector is given by parameter L.\nThe position of the center of gravity, coordinate s, is in the middle between\nthe two flanges.</p>\n<p>\nThere are hard stops at smax and smin, i. e. if\n<em><code>flange_a.s &gt;= smin</code></em> and <em><code>flange_b.s &lt;= xmax </code></em> the sliding mass can move freely.</p>\n<p>When the absolute velocity becomes zero, the sliding mass becomes stuck, i.e., the absolute position remains constant. In this phase the\nfriction force is calculated from a force balance due to the requirement that the\nabsolute acceleration shall be zero. The elements begin to slide when the friction\nforce exceeds a threshold value, called the maximum static friction force, computed via:</p>\n<blockquote><pre>\n   maximum_static_friction =  F_Coulomb + F_Stribeck\n</pre></blockquote>\n<p>\n<font color=\"#ff0000\"> <strong>This requires the states Stop.s and Stop.v</strong> </font>. If these states are eliminated during the index reduction\nthe model will not work. To avoid this any inertias should be connected via springs\nto the Stop element, other sliding masses, dampers or hydraulic chambers must be avoided.</p>\n<p>For more details of the used friction model see the following reference:</p>\n\n<dl>\n<dt>Beater P. (1999):</dt>\n<dd><a href=\"http://www.springer.de/cgi-bin/search_book.pl?isbn=3-540-65444-5\">\nEntwurf hydraulischer Maschinen</a>. Springer Verlag Berlin Heidelberg New York.</dd>\n</dl>\n\n<p>The friction model is implemented in a \"clean\" way by state events and leads to\ncontinuous/discrete systems of equations which have to be solved by appropriate\nnumerical methods. The method is described in\n(see also a short sketch in <a href=\"modelica://Modelica.Mechanics.Rotational.UsersGuide.ModelingOfFriction\">UsersGuide.ModelingOfFriction</a>):\n</p>\n\n<dl>\n<dt>Otter M., Elmqvist H., and Mattsson S.E. (1999):</dt>\n<dd><em>Hybrid Modeling in Modelica based on the Synchronous Data Flow Principle</em>.\n    CACSD'99, Aug. 22.-26, Hawaii. </dd>\n</dl>\n\n<p>More precise friction models take into account the elasticity of the material when\nthe two elements are \"stuck\", as well as other effects, like hysteresis. This has\nthe advantage that the friction element can be completely described by a differential\nequation without events. The drawback is that the system becomes stiff (about 10-20 times\nslower simulation) and that more material constants have to be supplied which requires more\nsophisticated identification. For more details, see the following references, especially\n(Armstrong and Canudas de Wit 1996):</p>\n<dl>\n<dt>\nArmstrong B. (1991):</dt>\n<dd><em>Control of Machines with Friction</em>. Kluwer Academic Press, Boston MA.<br>\n</dd>\n<dt>Armstrong B., and Canudas de Wit C. (1996): </dt>\n<dd><em>Friction Modeling and Compensation.</em> The Control Handbook, edited by W.S.Levine, CRC Press, pp. 1369-1382.<br>\n</dd>\n<dt>Canudas de Wit C., Olsson H., &Aring;str&ouml;m K.J., and Lischinsky P. (1995): </dt>\n<dd><em>A new model for control of systems with friction.</em> IEEE Transactions on Automatic Control, Vol. 40, No. 3, pp. 419-425.<br>\n</dd>\n</dl>\n\n<h4>Optional heatPort</h4>\n<p>\nThe dissipated energy is transported in form of heat to the optional heatPort connector\nthat can be enabled via parameter \"useHeatPort\". Independently whether the heatPort is\nor is not enabled, the dissipated power is defined with variable \"lossPower\".\nIf contact occurs at the hard stops, the lossPower is not correctly modelled\nat this time instant, because the hard stop would introduce a Dirac impulse\nin the lossPower due to the discontinuously changing kinetic energy of the mass\n(lossPower is the derivative of the kinetic energy at the time instant of the impact).\n</p>\n\n</html>",
            revisions = "<html>\n<h4>Release Notes:</h4>\n<ul>\n<li><em>First Version from December 7, 1999 by P. Beater (based on Rotational.BearingFriction)</em></li>\n<li><em>July 14, 2001 by P. Beater, assert on initialization added, diagram modified</em></li>\n<li><em>October 11, 2001, by Hans Olsson, Dassault Syst&egrave;mes AB, modified assert to handle start at stops,\nmodified event logic such if you have friction parameters equal to zero you do not get events\nbetween the stops.</em></li>\n<li><em>June 10, 2002 by P. Beater, StateSelect.always for variables s and v (instead of fixed=true). </em></li>\n</ul>\n</html>"),
        Icon(
            coordinateSystem(
                preserveAspectRatio = true,
                extent = {
                    {-100, -100}, 
                    {100, 100}}),
            graphics = {
                Line(
                    points = {
                        {-100, 0}, 
                        {100, 0}},
                    color = {0, 127, 0}), 
                Polygon(
                    points = {
                        {80, -100}, 
                        {50, -90}, 
                        {50, -110}, 
                        {80, -100}},
                    lineColor = {95, 127, 95},
                    fillColor = {95, 127, 95},
                    fillPattern = FillPattern.Solid), 
                Line(
                    points = {
                        {-40, -100}, 
                        {50, -100}},
                    color = {95, 127, 95}), 
                Rectangle(
                    extent = {
                        {-30, 30}, 
                        {30, -30}},
                    fillPattern = FillPattern.Sphere,
                    fillColor = {166, 221, 166},
                    lineColor = {0, 127, 0}), 
                Rectangle(
                    extent = {
                        {-64, -16}, 
                        {-56, -46}},
                    fillPattern = FillPattern.Solid,
                    lineColor = {0, 127, 0},
                    fillColor = {0, 127, 0}), 
                Rectangle(
                    extent = {
                        {56, -16}, 
                        {64, -46}},
                    fillPattern = FillPattern.Solid,
                    lineColor = {0, 127, 0},
                    fillColor = {0, 127, 0}), 
                Text(
                    extent = {
                        {-150, 80}, 
                        {150, 40}},
                    textString = "%name",
                    lineColor = {0, 0, 255}), 
                Line(
                    points = {
                        {-50, -90}, 
                        {-28, -68}},
                    color = {0, 127, 0}), 
                Line(
                    points = {
                        {-30, -90}, 
                        {-8, -68}},
                    color = {0, 127, 0}), 
                Line(
                    points = {
                        {-10, -90}, 
                        {12, -68}},
                    color = {0, 127, 0}), 
                Line(
                    points = {
                        {10, -90}, 
                        {32, -68}},
                    color = {0, 127, 0}), 
                Text(
                    extent = {
                        {-150, -110}, 
                        {150, -140}},
                    textString = "m=%m"), 
                Line(
                    visible = useHeatPort,
                    points = {
                        {-100, -100}, 
                        {-100, -40}, 
                        {3, -40}},
                    color = {191, 0, 0},
                    pattern = LinePattern.Dot), 
                Rectangle(
                    extent = {
                        {-70, -46}, 
                        {70, -70}},
                    fillColor = {160, 215, 160},
                    fillPattern = FillPattern.Solid,
                    lineColor = {0, 127, 0})}),
        Diagram(
            coordinateSystem(
                preserveAspectRatio = true,
                extent = {
                    {-100, -100}, 
                    {100, 100}}),
            graphics = {
                Polygon(
                    points = {
                        {50, -75}, 
                        {20, -65}, 
                        {20, -85}, 
                        {50, -75}},
                    lineColor = {128, 128, 128},
                    fillColor = {128, 128, 128},
                    fillPattern = FillPattern.Solid), 
                Line(points = {
                    {-60, -75}, 
                    {20, -75}}), 
                Rectangle(
                    extent = {
                        {-30, 26}, 
                        {35, -9}},
                    fillPattern = FillPattern.Sphere,
                    fillColor = {255, 255, 255}), 
                Line(
                    points = {
                        {-90, 0}, 
                        {-30, 0}},
                    color = {0, 127, 0}), 
                Line(
                    points = {
                        {35, 0}, 
                        {90, 0}},
                    color = {0, 127, 0}), 
                Rectangle(
                    extent = {
                        {-68, -14}, 
                        {76, -29}},
                    fillColor = {192, 192, 192},
                    fillPattern = FillPattern.Solid), 
                Rectangle(
                    extent = {
                        {-119, 43}, 
                        {-111, 17}},
                    fillPattern = FillPattern.Solid), 
                Line(points = {
                    {-111, 43}, 
                    {-111, 50}}), 
                Line(points = {
                    {-151, 49}, 
                    {-113, 49}}), 
                Text(
                    extent = {
                        {-149, 51}, 
                        {-126, 60}},
                    textString = "s min",
                    lineColor = {0, 0, 255}), 
                Polygon(
                    points = {
                        {-121, 52}, 
                        {-111, 49}, 
                        {-121, 46}, 
                        {-121, 52}},
                    fillPattern = FillPattern.Solid), 
                Rectangle(
                    extent = {
                        {124, 42}, 
                        {132, 17}},
                    fillPattern = FillPattern.Solid), 
                Line(points = {
                    {124, 39}, 
                    {124, 87}}), 
                Line(points = {
                    {-19, 78}, 
                    {121, 78}}), 
                Text(
                    extent = {
                        {-17, 83}, 
                        {6, 92}},
                    textString = "s max",
                    lineColor = {0, 0, 255}), 
                Polygon(
                    points = {
                        {114, 81}, 
                        {124, 78}, 
                        {114, 75}, 
                        {114, 81}},
                    fillPattern = FillPattern.Solid), 
                Line(points = {
                    {5, 26}, 
                    {5, 63}}), 
                Line(points = {
                    {-77, 58}, 
                    {-1, 58}}), 
                Text(
                    extent = {
                        {-75, 60}, 
                        {-38, 71}},
                    textString = "Position s",
                    lineColor = {0, 0, 255}), 
                Polygon(
                    points = {
                        {-5, 61}, 
                        {5, 58}, 
                        {-5, 55}, 
                        {-5, 61}},
                    fillPattern = FillPattern.Solid), 
                Line(points = {
                    {-100, -10}, 
                    {-100, -60}}), 
                Line(points = {
                    {100, -10}, 
                    {100, -60}}), 
                Polygon(
                    points = {
                        {90, -47}, 
                        {100, -50}, 
                        {90, -53}, 
                        {90, -47}},
                    fillPattern = FillPattern.Solid), 
                Polygon(
                    points = {
                        {-90, -47}, 
                        {-90, -53}, 
                        {-100, -50}, 
                        {-90, -47}},
                    fillPattern = FillPattern.Solid), 
                Line(points = {
                    {-90, -50}, 
                    {92, -50}}), 
                Text(
                    extent = {
                        {-11, -46}, 
                        {26, -36}},
                    textString = "Length L",
                    lineColor = {0, 0, 255})}));
end MassWithStopAndFriction;