ElastoBacklash

model ElastoBacklash "Backlash connected in series to linear spring and damper (backlash is modeled with elasticity)"
    parameter SI.RotationalSpringConstant c(final min = Modelica.Constants.small, start = 100000) "Spring constant (c > 0 required)";
    parameter SI.RotationalDampingConstant d(final min = 0, start = 0) "Damping constant";
    parameter SI.Angle b(final min = 0) = 0 "Total backlash";
    parameter SI.Angle phi_rel0 = 0 "Unstretched spring angle";

    extends Modelica.Mechanics.Rotational.Interfaces.PartialCompliantWithRelativeStates;
    extends Modelica.Thermal.HeatTransfer.Interfaces.PartialElementaryConditionalHeatPortWithoutT;

protected
    final parameter SI.Angle bMax = 0.5 * b "Backlash in range bMin <= phi_rel - phi_rel0 <= bMax";
    final parameter SI.Angle bMin = -bMax "Backlash in range bMin <= phi_rel - phi_rel0 <= bMax";
    SI.Torque tau_c;
    SI.Torque tau_d;
    SI.Angle phi_diff = phi_rel - phi_rel0;
    constant SI.Angle bEps = 1e-10 "Minimum backlash";
equation
    if initial() then 
        tau_c = if 1.5 * bMax < phi_diff then c * (phi_diff - bMax) else if phi_diff < 1.5 * bMin then c * (phi_diff - bMin) else 0.333333333333333 * c * phi_diff;
        tau_d = d * w_rel;
        tau = tau_c + tau_d;
        lossPower = tau_d * w_rel;
    else 
        tau_c = if abs(b) <= bEps then c * phi_diff else if bMax < phi_diff then c * (phi_diff - bMax) else if phi_diff < bMin then c * (phi_diff - bMin) else 0;
        tau_d = d * w_rel;
        tau = if abs(b) <= bEps then tau_c + tau_d else if bMax < phi_diff then smooth(0, noEvent(if tau_c + tau_d <= 0 then 0 else tau_c + min(tau_c, tau_d))) else if phi_diff < bMin then smooth(0, noEvent(if 0 <= tau_c + tau_d then 0 else tau_c + max(tau_c, tau_d))) else 0;
        lossPower = if abs(b) <= bEps then tau_d * w_rel else if bMax < phi_diff then smooth(0, noEvent(if tau_c + tau_d <= 0 then 0 else min(tau_c, tau_d) * w_rel)) else if phi_diff < bMin then smooth(0, noEvent(if 0 <= tau_c + tau_d then 0 else max(tau_c, tau_d) * w_rel)) else 0;
    end if;

    annotation (
        Documentation(info = "<html>\n<p>\nThis element consists of a <strong>backlash</strong> element <strong>connected in series</strong>\nto a <strong>spring</strong> and <strong>damper</strong> element which are <strong>connected in parallel</strong>.\nThe spring constant shall be non-zero, otherwise the component cannot be used.\n</p>\n\n<p>\nIn combination with components IdealGear, the ElastoBacklash model\ncan be used to model a gear box with backlash, elasticity and damping.\n</p>\n\n<p>\nDuring initialization, the backlash characteristic is replaced by a continuous\napproximation in the backlash region, in order to reduce problems during\ninitialization, especially for inverse models.\n</p>\n\n<p>\nIf the backlash b is smaller as 1e-10 rad (especially, if b=0),\nthen the backlash is ignored and the component reduces to a spring/damper\nelement in parallel.\n</p>\n\n<p>\nIn the backlash region (-b/2 &le; flange_b.phi - flange_a.phi - phi_rel0 &le; b/2) no torque\nis exerted (flange_b.tau = 0). Outside of this region, contact is present and\nthe contact torque is basically computed with a linear\nspring/damper characteristic:\n</p>\n\n<pre>\n   desiredContactTorque = c*phi_contact + d*<strong>der</strong>(phi_contact)\n\n            phi_contact = phi_rel - phi_rel0 - b/2 <strong>if</strong> phi_rel - phi_rel0 &gt;  b/2\n                        = phi_rel - phi_rel0 + b/2 <strong>if</strong> phi_rel - phi_rel0 &lt; -b/2\n\n            phi_rel     = flange_b.phi - flange_a.phi;\n</pre>\n\n<p>\nThis torque characteristic leads to the following difficulties:\n</p>\n\n<ol>\n<li> If the damper torque becomes larger as the spring torque and with opposite sign,\n     the contact torque would be \"pulling/sticking\" which is unphysical, since during\n     contact only pushing torques can occur.</li>\n\n<li> When contact occurs with a non-zero relative speed (which is the usual\n     situation), the damping torque has a non-zero value and therefore the contact\n     torque changes discontinuously at phi_rel = phi_rel0. Again, this is not physical\n     because the torque 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). However, there\nseems to be no proposal to avoid sticking. For this reason, the most simple\napproach is used in the ElastoBacklash model, to fix both problems by slight changes\nto the linear spring/damper characteristic:\n</p>\n\n<pre>\n    // Torque characteristic when phi_rel > phi_rel0\n    <strong>if</strong> phi_rel - phi_rel0 &lt; b/2 <strong>then</strong>\n       tau_c = 0;          // spring torque\n       tau_d = 0;          // damper torque\n       flange_b.tau = 0;\n    <strong>else</strong>\n       tau_c = c*(phi_rel - phi_rel0);    // spring torque\n       tau_d = d*<strong>der</strong>(phi_rel);            // damper torque\n       flange_b.tau = <strong>if</strong> tau_c + tau_d &le; 0 <strong>then</strong> 0 <strong>else</strong> tau_c + <strong>min</strong>( tau_c, tau_d );\n    <strong>end if</strong>;\n</pre>\n\n<p>\nNote, when sticking would occur (tau_c + tau_d &le; 0), then the contact torque\nis explicitly set to zero. The \"min(tau_c, tau_d)\" part in the if-expression,\nlimits the damping torque when it is pushing. This means that at the start of\nthe contact (phi_rel - phi_rel0 = b/2), the damping torque is zero and is continuous.\nThe effect of both modifications is that the absolute value of the damping torque\nis always limited by the absolute value of the spring torque: |tau_d| &le; |tau_c|.\n</p>\n\n<p>\nIn the next figure, a typical simulation with the ElastoBacklash model is shown\n(<a href=\"modelica://Modelica.Mechanics.Rotational.Examples.Backlash\">Examples.Backlash</a>)\nwhere the different effects are visualized:\n</p>\n\n<ol>\n<li> Curve 1 (elastoBacklash1.tau) is the unmodified contact torque, i.e., the linear spring/damper\n     characteristic. A pulling/sticking torque is present at the end of the contact.</li>\n<li> Curve 2 (elastoBacklash2.tau) is the contact torque, where the torque is explicitly set to\n     zero when pulling/sticking occurs. The contact torque is discontinuous at begin of\n     contact.</li>\n<li> Curve 3 (elastoBacklash3.tau) is the ElastoBacklash 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/Rotational/elastoBacklash1.png\">\n</p>\n\n<p>\nSee also the discussion\n<a href=\"modelica://Modelica.Mechanics.Rotational.UsersGuide.StateSelection\">State Selection</a>\nin the User's Guide of the Rotational library.\n</p>\n</html>"),
        Icon(
            coordinateSystem(
                preserveAspectRatio = true,
                extent = {
                    {-100, -100}, 
                    {100, 100}}),
            graphics = {
                Line(points = {
                    {-80, 32}, 
                    {-58, 32}, 
                    {-48, 0}, 
                    {-34, 61}, 
                    {-20, 0}, 
                    {-8, 60}, 
                    {0, 30}, 
                    {20, 30}}), 
                Rectangle(
                    extent = {
                        {-60, -10}, 
                        {-10, -50}},
                    fillColor = {192, 192, 192},
                    fillPattern = FillPattern.Solid), 
                Line(points = {
                    {-60, -50}, 
                    {0, -50}}), 
                Line(points = {
                    {-60, -10}, 
                    {0, -10}}), 
                Line(points = {
                    {-10, -30}, 
                    {20, -30}}), 
                Line(points = {
                    {-80, -30}, 
                    {-60, -30}}), 
                Line(points = {
                    {-80, 32}, 
                    {-80, -30}}), 
                Line(points = {
                    {20, 30}, 
                    {20, -30}}), 
                Line(points = {
                    {-90, 0}, 
                    {-80, 0}}), 
                Line(points = {
                    {90, 0}, 
                    {80, 0}}), 
                Line(points = {
                    {20, 0}, 
                    {60, 0}, 
                    {60, -30}}), 
                Line(points = {
                    {40, -12}, 
                    {40, -40}, 
                    {80, -40}, 
                    {80, 0}}), 
                Text(
                    extent = {
                        {-150, -130}, 
                        {150, -90}},
                    textString = "b=%b"), 
                Text(
                    extent = {
                        {-150, 100}, 
                        {150, 60}},
                    lineColor = {0, 0, 255},
                    textString = "%name"), 
                Text(
                    extent = {
                        {-152, -92}, 
                        {148, -52}},
                    textString = "c=%c"), 
                Line(
                    visible = useHeatPort,
                    points = {
                        {-100, -100}, 
                        {-100, -43}, 
                        {-34, -43}},
                    color = {191, 0, 0},
                    pattern = LinePattern.Dot)}),
        Diagram(
            coordinateSystem(
                preserveAspectRatio = true,
                extent = {
                    {-100, -100}, 
                    {100, 100}}),
            graphics = {
                Line(
                    points = {
                        {-80, 32}, 
                        {-58, 32}, 
                        {-48, 0}, 
                        {-34, 60}, 
                        {-20, 0}, 
                        {-8, 60}, 
                        {0, 30}, 
                        {20, 30}},
                    thickness = 0.5), 
                Line(
                    points = {
                        {-68, 32}, 
                        {-68, 97}},
                    color = {128, 128, 128}), 
                Line(
                    points = {
                        {80, 0}, 
                        {80, 96}},
                    color = {128, 128, 128}), 
                Line(
                    points = {
                        {-68, 92}, 
                        {72, 92}},
                    color = {128, 128, 128}), 
                Polygon(
                    points = {
                        {70, 95}, 
                        {80, 92}, 
                        {70, 89}, 
                        {70, 95}},
                    lineColor = {128, 128, 128},
                    fillColor = {128, 128, 128},
                    fillPattern = FillPattern.Solid), 
                Text(
                    extent = {
                        {-34, 77}, 
                        {40, 90}},
                    lineColor = {128, 128, 128},
                    textString = "phi_rel"), 
                Rectangle(
                    extent = {
                        {-60, -20}, 
                        {-10, -80}},
                    lineThickness = 0.5,
                    fillColor = {192, 192, 192},
                    fillPattern = FillPattern.Solid), 
                Line(
                    points = {
                        {-52, -80}, 
                        {0, -80}},
                    thickness = 0.5), 
                Line(
                    points = {
                        {-52, -20}, 
                        {0, -20}},
                    thickness = 0.5), 
                Line(
                    points = {
                        {-10, -50}, 
                        {20, -50}},
                    thickness = 0.5), 
                Line(
                    points = {
                        {-80, -50}, 
                        {-60, -50}},
                    thickness = 0.5), 
                Line(
                    points = {
                        {-80, 32}, 
                        {-80, -50}},
                    thickness = 0.5), 
                Line(
                    points = {
                        {20, 30}, 
                        {20, -50}},
                    thickness = 0.5), 
                Line(points = {
                    {-96, 0}, 
                    {-80, 0}}), 
                Line(
                    points = {
                        {96, 0}, 
                        {80, 0}},
                    thickness = 0.5), 
                Line(
                    points = {
                        {20, 0}, 
                        {60, 0}, 
                        {60, -30}},
                    thickness = 0.5), 
                Line(
                    points = {
                        {40, -12}, 
                        {40, -40}, 
                        {80, -40}, 
                        {80, 0}},
                    thickness = 0.5), 
                Line(
                    points = {
                        {30, 0}, 
                        {30, 64}},
                    color = {128, 128, 128}), 
                Line(
                    points = {
                        {30, 60}, 
                        {80, 60}},
                    color = {128, 128, 128}), 
                Polygon(
                    points = {
                        {70, 63}, 
                        {80, 60}, 
                        {70, 57}, 
                        {70, 63}},
                    lineColor = {128, 128, 128},
                    fillColor = {128, 128, 128},
                    fillPattern = FillPattern.Solid), 
                Text(
                    extent = {
                        {39, 60}, 
                        {68, 46}},
                    lineColor = {160, 160, 164},
                    textString = "b")}));
end ElastoBacklash;