ElastoGap

model ElastoGap "1D translational spring damper combination with gap"
    extends Modelica.Mechanics.Translational.Interfaces.PartialCompliantWithRelativeStates;

    parameter SI.TranslationalSpringConstant c(final min = 0, start = 1) "Spring constant";
    parameter SI.TranslationalDampingConstant d(final min = 0, start = 1) "Damping constant";
    parameter SI.Position s_rel0 = 0 "Unstretched spring length";
    parameter Real n(final min = 1) = 1 "Exponent of spring force ( f_c = -c*|s_rel-s_rel0|^n )";

    extends Modelica.Thermal.HeatTransfer.Interfaces.PartialElementaryConditionalHeatPortWithoutT;

    Boolean contact "=true, if contact, otherwise no contact";
protected
    Modelica.SIunits.Force f_c "Spring force";
    Modelica.SIunits.Force f_d2 "Linear damping force";
    Modelica.SIunits.Force f_d "Linear damping force which is limited by spring force (|f_d| <= |f_c|)";
equation
    f = f_c + f_d;
    contact = s_rel < s_rel0;
    f_c = smooth(1, noEvent(if contact then -c * abs(s_rel - s_rel0) ^ n else 0));
    f_d = smooth(0, noEvent(if contact then if f_d2 < f_c then f_c else if -f_c < f_d2 then -f_c else f_d2 else 0));
    f_d2 = if contact then d * v_rel else 0;
    lossPower = f_d * v_rel;

    annotation (
        Documentation(info = "<html>\n<p>\nThis component models a spring damper combination that can lift off.\nIt can be connected between a sliding mass and the housing (model\n<a href=\"modelica://Modelica.Mechanics.Translational.Components.Fixed\">Fixed</a>),\nto describe the contact of a sliding mass with the housing.\n</p>\n\n<p>\nAs long as s_rel &gt; s_rel0, no force is exerted (s_rel = flange_b.s - flange_a.s).\nIf s_rel &le; s_rel0, the contact force is basically computed with a linear\nspring/damper characteristic. With parameter n&ge;1 (exponent of spring force),\na nonlinear spring force can be modeled:\n</p>\n\n<pre>\n   desiredContactForce = c*|s_rel - s_rel0|^n + d*<strong>der</strong>(s_rel)\n</pre>\n\n<p>\nNote, Hertzian contact is described by:\n</p>\n<ul>\n<li> Contact between two metallic spheres: n=1.5</li>\n<li> Contact between two metallic plates: n=1</li>\n</ul>\n\n<p>\nThe above force law leads to the following difficulties:\n</p>\n\n<ol>\n<li> If the damper force becomes larger as the spring force and with opposite sign,\n     the contact force would be \"pulling/sticking\" which is unphysical, since during\n     contact only pushing forces can occur.</li>\n\n<li> When contact occurs with a non-zero relative speed (which is the usual\n     situation), the damping force has a non-zero value and therefore the contact\n     force changes discontinuously at s_rel = s_rel0. Again, this is not physical\n     because the force can only change continuously. (Note, this component is not an\n     idealized model where a steep characteristic is approximated by a discontinuity,\n     but it shall model the steep characteristic.)</li>\n</ol>\n\n<p>\nIn the literature there are several proposals to fix problem (2). Especially, often\nthe following model is used (see, e.g.,\nLankarani, Nikravesh: Continuous Contact Force Models for Impact\nAnalysis in Multibody Systems, Nonlinear Dynamics 5, pp. 193-207, 1994,\n<a href=\"http://www.springerlink.com/content/h50x61270q06p65n/fulltext.pdf\">pdf-download</a>):\n</p>\n\n<pre>\n   f = c*s_rel^n + (d*s_rel^n)*<strong>der</strong>(s_rel)\n</pre>\n\n<p>\nHowever, this and other models proposed in literature violate\nissue (1), i.e., unphysical pulling forces can occur (if d*<strong>der</strong>(s_rel)\nbecomes large enough). Note, if the force law is of the form \"f = f_c + f_d\", then a\nnecessary condition is that |f_d| &le; |f_c|, otherwise (1) and (2) are violated.\nFor this reason, the most simplest approach is used in the ElastoGap model\nto fix both problems by using this necessary condition in the force law directly.\nIf s_rel0 = 0, the equations are:\n</p>\n\n<pre>\n    <strong>if</strong> s_rel &ge; 0 <strong>then</strong>\n       f = 0;    // contact force\n    <strong>else</strong>\n       f_c  = -c*|s_rel|^n;          // contact spring force (Hertzian contact force)\n       f_d2 = d*<strong>der</strong>(s_rel);         // linear contact damper force\n       f_d  = <strong>if</strong> f_d2 &lt;  f_c <strong>then</strong>  f_c <strong>else</strong>\n              <strong>if</strong> f_d2 &gt; -f_c <strong>then</strong> -f_c <strong>else</strong> f_d2;  // bounded damper force\n       f    = f_c + f_d;            // contact force\n    <strong>end if</strong>;\n</pre>\n\n<p>\nNote, since |f_d| &le; |f_c|, pulling forces cannot occur and the contact force\nis always continuous, especially around the start of the penetration at s_rel = s_rel0.\n</p>\n\n<p>\nIn the next figure, a typical simulation with the ElastoGap model is shown\n(<a href=\"modelica://Modelica.Mechanics.Translational.Examples.ElastoGap\">Examples.ElastoGap</a>)\nwhere the different effects are visualized:\n</p>\n\n<ol>\n<li> Curve 1 (elastoGap1.f) is the unmodified contact force, i.e., the linear spring/damper\n     characteristic. A pulling/sticking force is present at the end of the contact.</li>\n<li> Curve 2 (elastoGap2.f) is the contact force, where the force is explicitly set to\n     zero when pulling/sticking occurs. The contact force is discontinuous when contact starts.</li>\n<li> Curve 3 (elastoGap3.f) is the ElastoGap model of this library. No discontinuity and no\n     pulling/sticking occurs.</li>\n</ol>\n\n<p>\n<img src=\"modelica://Modelica/Resources/Images/Mechanics/Translational/ElastoGap1.png\">\n</p>\n</html>"),
        Diagram(
            coordinateSystem(
                preserveAspectRatio = false,
                extent = {
                    {-100, -100}, 
                    {100, 100}}),
            graphics = {
                Line(
                    points = {
                        {-100, 0}, 
                        {-50, 0}},
                    color = {0, 127, 0}), 
                Line(
                    points = {
                        {-48, 34}, 
                        {-48, -46}},
                    thickness = 1), 
                Line(points = {
                    {8, 40}, 
                    {8, 2}}), 
                Line(points = {
                    {-2, 0}, 
                    {38, 0}, 
                    {38, 44}, 
                    {-2, 44}}), 
                Line(points = {
                    {38, 22}, 
                    {72, 22}}), 
                Line(
                    points = {
                        {-12, -38}, 
                        {-12, 20}},
                    thickness = 1), 
                Line(points = {
                    {-12, 22}, 
                    {8, 22}}), 
                Line(points = {
                    {-12, -38}, 
                    {-2, -38}}), 
                Line(
                    points = {
                        {72, 0}, 
                        {100, 0}},
                    color = {0, 127, 0}), 
                Line(points = {
                    {72, 22}, 
                    {72, -42}}), 
                Line(points = {
                    {-2, -38}, 
                    {10, -28}, 
                    {22, -48}, 
                    {38, -28}, 
                    {50, -48}, 
                    {64, -28}, 
                    {72, -40}}), 
                Rectangle(
                    extent = {
                        {8, 44}, 
                        {38, 0}},
                    fillColor = {192, 192, 192},
                    fillPattern = FillPattern.Solid), 
                Text(
                    extent = {
                        {-64, -80}, 
                        {64, -64}},
                    lineColor = {0, 0, 255},
                    textString = "s_rel"), 
                Line(points = {
                    {-100, -29}, 
                    {-100, -61}}), 
                Line(points = {
                    {100, -61}, 
                    {100, -28}}), 
                Line(points = {
                    {-98, -60}, 
                    {98, -60}}), 
                Polygon(
                    points = {
                        {-101, -60}, 
                        {-96, -59}, 
                        {-96, -61}, 
                        {-101, -60}},
                    fillPattern = FillPattern.Solid), 
                Polygon(
                    points = {
                        {100, -60}, 
                        {95, -61}, 
                        {95, -59}, 
                        {100, -60}},
                    fillPattern = FillPattern.Solid)}),
        Icon(
            coordinateSystem(
                preserveAspectRatio = true,
                extent = {
                    {-100, -100}, 
                    {100, 100}}),
            graphics = {
                Line(
                    points = {
                        {-98, 0}, 
                        {-48, 0}},
                    color = {0, 127, 0}), 
                Line(
                    points = {
                        {-48, 36}, 
                        {-48, -38}},
                    thickness = 1,
                    color = {0, 127, 0}), 
                Line(
                    points = {
                        {-12, -38}, 
                        {-12, 36}},
                    thickness = 1,
                    color = {0, 127, 0}), 
                Line(
                    points = {
                        {-12, -28}, 
                        {70, -28}, 
                        {70, 24}},
                    color = {0, 127, 0}), 
                Line(
                    points = {
                        {70, 0}, 
                        {98, 0}},
                    color = {0, 127, 0}), 
                Line(
                    points = {
                        {-12, 24}, 
                        {0, 24}, 
                        {6, 34}, 
                        {18, 14}, 
                        {30, 34}, 
                        {42, 14}, 
                        {54, 34}, 
                        {60, 24}, 
                        {70, 24}},
                    color = {0, 127, 0}), 
                Rectangle(
                    extent = {
                        {10, -6}, 
                        {50, -50}},
                    fillColor = {192, 192, 192},
                    fillPattern = FillPattern.Solid,
                    lineColor = {0, 127, 0}), 
                Line(
                    points = {
                        {-52, -70}, 
                        {28, -70}},
                    color = {95, 127, 95}), 
                Polygon(
                    points = {
                        {58, -70}, 
                        {28, -60}, 
                        {28, -80}, 
                        {58, -70}},
                    lineColor = {95, 127, 95},
                    fillColor = {95, 127, 95},
                    fillPattern = FillPattern.Solid), 
                Text(
                    extent = {
                        {-150, 100}, 
                        {150, 60}},
                    textString = "%name",
                    lineColor = {0, 0, 255}), 
                Text(
                    extent = {
                        {-150, -125}, 
                        {150, -95}},
                    textString = "c=%c"), 
                Text(
                    extent = {
                        {-150, -160}, 
                        {150, -130}},
                    textString = "d=%d"), 
                Line(
                    visible = useHeatPort,
                    points = {
                        {-100, -100}, 
                        {-100, -44}, 
                        {22, -44}, 
                        {22, -28}},
                    color = {191, 0, 0},
                    pattern = LinePattern.Dot), 
                Line(
                    points = {
                        {0, -50}, 
                        {50, -50}, 
                        {50, -6}, 
                        {0, -6}},
                    color = {0, 127, 0})}));
end ElastoGap;