model LossyGear "Gear with mesh efficiency and bearing friction (stuck/rolling possible)"
extends Modelica.Mechanics.Rotational.Icons.Gear;
extends Modelica.Mechanics.Rotational.Interfaces.PartialElementaryTwoFlangesAndSupport2;
parameter Real ratio(start = 1) "Transmission ratio (flange_a.phi/flange_b.phi)";
parameter Real lossTable[:,5] = [0,1,1,0,0] "Array for mesh efficiencies and bearing friction depending on speed";
extends Modelica.Thermal.HeatTransfer.Interfaces.PartialElementaryConditionalHeatPortWithoutT;
Modelica.SIunits.Angle phi_a "Angle between left shaft flange and support";
Modelica.SIunits.Angle phi_b "Angle between right shaft flange and support";
Real sa(final unit = "1") "Path parameter for acceleration and torque loss";
SI.AngularVelocity w_a "Angular velocity of flange_a with respect to support";
SI.AngularAcceleration a_a "Angular acceleration of flange_a with respect to support";
Real interpolation_result[1,4] "Result of interpolation in lossTable (= [eta_mf1, eta_mf2, tau_bf1, tau_bf2])";
Real eta_mf1(unit = "1") "Mesh efficiency in case that flange_a is driving";
Real eta_mf2(unit = "1") "Mesh efficiency in case that flange_b is driving";
SI.Torque tau_bf_a "Bearing friction torque on flange_a side";
SI.Torque tau_eta "Torque that determines the driving side (= if forwardSliding then flange_a.tau-tau_bf_a else if backwardSliding then flange_a.tau+tau_bf_a else flange_a.tau)";
SI.Torque tau_bf1 "Absolute resultant bearing friction torque with respect to flange_a in case that flange_a is driving (= |tau_bf_a*eta_mf1 + tau_bf_b/i|)";
SI.Torque tau_bf2 "Absolute resultant bearing friction torque with respect to flange_a in case that flange_b is driving (= |tau_bf_a/eta_mf2 + tau_bf_b/i|)";
SI.Torque quadrant1 "Torque loss if w_a > 0 and flange_a.tau >= 0";
SI.Torque quadrant2 "Torque loss if w_a > 0 and flange_a.tau < 0";
SI.Torque quadrant3 "Torque loss if w_a < 0 and flange_a.tau >= 0";
SI.Torque quadrant4 "Torque loss if w_a < 0 and flange_a.tau < 0";
SI.Torque quadrant1_p "Torque loss at w_a = 0+ to determine driving side (flange_a.tau >= 0)";
SI.Torque quadrant2_p "Torque loss at w_a = 0+ to determine driving side (flange_a.tau < 0)";
SI.Torque quadrant3_m "Torque loss at w_a = 0- to determine driving side (flange_a.tau >=0)";
SI.Torque quadrant4_m "Torque loss at w_a = 0- to determine driving side (flange_a.tau < 0)";
SI.Torque tauLoss "Torque loss due to friction in the gear teeth and in the bearings";
SI.Torque tauLossMax "Torque loss for positive speed";
SI.Torque tauLossMin "Torque loss for negative speed";
SI.Torque tauLossMax_p "Torque loss for positive speed";
SI.Torque tauLossMin_m "Torque loss for negative speed";
Boolean tau_aPos(start = true) "Only for backwards compatibility (was previously: true, if torque of flange_a is not negative)";
Boolean tau_etaPos(start = true) "true, if torque tau_eta is not negative";
Boolean startForward(start = false) "true, if starting to roll forward";
Boolean startBackward(start = false) "true, if starting to roll backward";
Boolean locked(start = false) "true, if gear is locked";
Boolean ideal "= true, if losses are neglected (that is lossTable = [0, 1, 1, 0, 0])";
constant Integer Unknown = 3 "Value of mode is not known";
constant Integer Free = 2 "Element is not active";
constant Integer Forward = 1 "w_a > 0 (forward rolling)";
constant Integer Stuck = 0 "w_a = 0 (forward rolling, locked or backward rolling)";
constant Integer Backward = -1 "w_a < 0 (backward rolling)";
Integer mode(final min = Backward, final max = Unknown, start = Free, fixed = true) "Mode of friction element (unknown, not active, forward/backward rolling, stuck)";
SI.Torque tau_eta_p "tau_eta assuming positive omega";
SI.Torque tau_eta_m "tau_eta assuming negative omega";
protected
constant SI.AngularAcceleration unitAngularAcceleration = 1;
constant SI.Torque unitTorque = 1;
parameter Real eta_mf1_0(unit = "1") = Modelica.Math.Vectors.interpolate(lossTable[:,1], lossTable[:,2], 0, 1);
parameter Real eta_mf2_0(unit = "1") = Modelica.Math.Vectors.interpolate(lossTable[:,1], lossTable[:,3], 0, 1);
parameter SI.Torque tau_bf1_0 = abs(Modelica.Math.Vectors.interpolate(lossTable[:,1], lossTable[:,4], 0, 1));
parameter SI.Torque tau_bf2_0 = abs(Modelica.Math.Vectors.interpolate(lossTable[:,1], lossTable[:,5], 0, 1));
parameter SI.Torque tau_bf_a_0 = if Modelica.Math.isEqual(eta_mf1_0, 1, Modelica.Constants.eps) and Modelica.Math.isEqual(eta_mf2_0, 1, Modelica.Constants.eps) then 0.5 * tau_bf1_0 else (tau_bf1_0 - tau_bf2_0) / (eta_mf1_0 - eta_mf2_0 ^ (-1));
equation
if Modelica.Math.isEqual(eta_mf1, 1, Modelica.Constants.eps) and Modelica.Math.isEqual(eta_mf2, 1, Modelica.Constants.eps) then
tau_bf_a = 0.5 * tau_bf1;
else
tau_bf_a = (tau_bf1 - tau_bf2) / (eta_mf1 - eta_mf2 ^ (-1));
end if;
if ideal then
interpolation_result = [1,1,0,0];
eta_mf1 = 1;
eta_mf2 = 1;
tau_bf1 = 0;
tau_bf2 = 0;
else
interpolation_result = [Modelica.Math.Vectors.interpolate(lossTable[:,1], lossTable[:,2], noEvent(abs(w_a)), 1),Modelica.Math.Vectors.interpolate(lossTable[:,1], lossTable[:,3], noEvent(abs(w_a)), 1),Modelica.Math.Vectors.interpolate(lossTable[:,1], lossTable[:,4], noEvent(abs(w_a)), 1),Modelica.Math.Vectors.interpolate(lossTable[:,1], lossTable[:,5], noEvent(abs(w_a)), 1)];
eta_mf1 = interpolation_result[1,1];
eta_mf2 = interpolation_result[1,2];
tau_bf1 = noEvent(abs(interpolation_result[1,3]));
tau_bf2 = noEvent(abs(interpolation_result[1,4]));
end if;
assert(0 < abs(ratio), "Error in initialization of LossyGear: ratio may not be zero");
0 = flange_b.tau + ratio * (flange_a.tau - tauLoss);
a_a = unitAngularAcceleration * (if locked then 0 else sa - tauLoss / unitTorque);
a_a = der(w_a);
ideal = Modelica.Math.Matrices.isEqual(lossTable, [0,1,1,0,0], Modelica.Constants.eps);
locked = not (ideal or pre(mode) == Forward or startForward or pre(mode) == Backward or startBackward);
lossPower = tauLoss * w_a;
mode = if ideal then Free else if (pre(mode) == Forward or startForward) and 0 < w_a then Forward else if (pre(mode) == Backward or startBackward) and w_a < 0 then Backward else Stuck;
phi_a = ratio * phi_b;
phi_a = flange_a.phi - phi_support;
phi_b = flange_b.phi - phi_support;
quadrant1 = (1 - eta_mf1) * flange_a.tau + tau_bf1;
quadrant2 = (1 - eta_mf2 ^ (-1)) * flange_a.tau + tau_bf2;
quadrant3 = (1 - eta_mf1) * flange_a.tau - tau_bf1;
quadrant4 = (1 - eta_mf2 ^ (-1)) * flange_a.tau - tau_bf2;
tauLoss = if ideal then 0 else if locked then sa * unitTorque else if startForward or pre(mode) == Forward then tauLossMax else tauLossMin;
tau_aPos = tau_etaPos;
tau_eta = if ideal then flange_a.tau else if locked then flange_a.tau else if startForward or pre(mode) == Forward then flange_a.tau - tau_bf_a else flange_a.tau + tau_bf_a;
tau_eta_m = flange_a.tau + tau_bf_a_0;
tau_eta_p = flange_a.tau - tau_bf_a_0;
w_a = der(phi_a);
quadrant1_p = (1 - eta_mf1_0) * flange_a.tau + tau_bf1_0;
quadrant2_p = (1 - eta_mf2_0 ^ (-1)) * flange_a.tau + tau_bf2_0;
quadrant3_m = (1 - eta_mf1_0) * flange_a.tau - tau_bf1_0;
quadrant4_m = (1 - eta_mf2_0 ^ (-1)) * flange_a.tau - tau_bf2_0;
startBackward = pre(mode) == Stuck and sa < tauLossMin_m / unitTorque or initial() and w_a < 0;
startForward = pre(mode) == Stuck and tauLossMax_p / unitTorque < sa or initial() and 0 < w_a;
tauLossMax = if tau_etaPos then quadrant1 else quadrant2;
tauLossMax_p = if noEvent(0 < tau_eta_p) then quadrant1_p else quadrant2_p;
tauLossMin = if tau_etaPos then quadrant4 else quadrant3;
tauLossMin_m = if noEvent(0 < tau_eta_m) then quadrant4_m else quadrant3_m;
tau_etaPos = 0 <= tau_eta;
annotation (
Documentation(info = "<html>\n<p>\nThis component models the gear ratio and the <strong>losses</strong> of\na standard gear box in a <strong>reliable</strong> way including the stuck phases\nthat may occur at zero speed. The gear boxes that can\nbe handled are fixed in the ground or on a moving support, have one input and one\noutput shaft, and are essentially described by the equations:\n</p>\n<blockquote><pre>\n flange_a.phi = i*flange_b.phi;\n-(flange_b.tau - tau_bf_b) = i*eta_mf*(flange_a.tau - tau_bf_a);\n\n// or -flange_b.tau = i*eta_mf*(flange_a.tau - tau_bf_a - tau_bf_b/(i*eta_mf));\n</pre></blockquote>\n<p>\nwhere\n</p>\n\n<ul>\n<li> <strong>i</strong> is the constant <strong>gear ratio</strong>,</li>\n\n<li> <strong>eta_mf</strong> = eta_mf(w_a) is the <strong>mesh efficiency</strong> due to the\n friction between the teeth of the gear wheels,</li>\n\n<li> <strong>tau_bf_a</strong> = tau_bf_a(w_a) is the <strong>bearing friction torque</strong>\n on the flange_a side,</li>\n\n<li> <strong>tau_bf_b</strong> = tau_bf_b(w_a) is the <strong>bearing friction torque</strong>\n on the flange_b side, and</li>\n\n<li><strong>w_a</strong> = der(flange_a.phi) is the speed of flange_a</li>\n</ul>\n\n<p>\nThe loss terms \"eta_mf\", \"tau_bf_a\" and \"tau_bf_b\" are functions of the\n<em>absolute value</em> of the input shaft speed w_a and of the energy\nflow direction. They are defined by parameter <strong>lossTable[:,5]\n</strong> where the columns of this table have the following\nmeaning:\n</p>\n\n<table border=1 cellspacing=0 cellpadding=2>\n <tbody>\n <tr>\n <td>|w_a|</td>\n <td>eta_mf1</td>\n <td>eta_mf2</td>\n <td>|tau_bf1|</td>\n <td>|tau_bf2|</td>\n </tr>\n <tr>\n <td align=\"center\">...</td>\n <td align=\"center\">...</td>\n <td align=\"center\">...</td>\n <td align=\"center\">...</td>\n <td align=\"center\">...</td>\n </tr>\n <tr>\n <td align=\"center\">...</td>\n <td align=\"center\">...</td>\n <td align=\"center\">...</td>\n <td align=\"center\">...</td>\n <td align=\"center\">...</td>\n </tr>\n </tbody>\n</table>\n\n<p>with</p>\n<table border=1 cellspacing=0 cellpadding=2>\n <tbody>\n <tr>\n <td>|w_a|</td>\n <td>Absolute value of angular velocity of input shaft flange_a</td>\n </tr>\n <tr>\n <td>eta_mf1</td>\n <td>Mesh efficiency in case that flange_a is driving</td>\n </tr>\n <tr>\n <td>eta_mf2</td>\n <td>Mesh efficiency in case that flange_b is driving</td>\n </tr>\n <tr>\n <td>|tau_bf1|</td>\n <td> Absolute resultant bearing friction torque with respect to flange_a\n in case that flange_a is driving<br>\n (= |tau_bf_a*eta_mf1 + tau_bf_b/i|)\n </td>\n </tr>\n <tr>\n <td>|tau_bf2|</td>\n <td> Absolute resultant bearing friction torque with respect to flange_a\n in case that flange_b is driving<br>\n (= |tau_bf_a/eta_mf2 + tau_bf_b/i|)\n </td>\n </tr>\n </tbody>\n</table>\n<p>\nWith these variables, the mesh efficiency and the bearing friction\nare formally defined as:\n</p>\n\n<blockquote><pre>\n<strong>if</strong> (flange_a.tau - tau_bf_a)*w_a > 0 <strong>or</strong>\n (flange_a.tau - tau_bf_a) == 0 <strong>and</strong> w_a > 0 <strong>then</strong>\n eta_mf := eta_mf1\n tau_bf := tau_bf1\n<strong>elseif</strong> (flange_a.tau - tau_bf_a)*w_a < 0 <strong>or</strong>\n (flange_a.tau - tau_bf_a) == 0 <strong>and</strong> w_a < 0 <strong>then</strong>\n eta_mf := 1/eta_mf2\n tau_bf := tau_bf2\n<strong>else</strong> // w_a == 0\n eta_mf and tau_bf are computed such that <strong>der</strong>(w_a) = 0\n<strong>end if</strong>;\n-flange_b.tau = i*(eta_mf*flange_a.tau - tau_bf);\n</pre></blockquote>\n\n<p>\nNote, that the losses are modeled in a physically meaningful way taking\ninto account that at zero speed the movement may be locked due\nto the friction in the gear teeth and/or in the bearings.\nDue to this important property, this component can be used in\nsituations where the combination of the components\nModelica.Mechanics.Rotational.IdealGear and\nModelica.Mechanics.Rotational.GearEfficiency will fail because,\ne.g., chattering occurs when using the\nModelica.Mechanics.Rotational.GearEfficiency model.\n</p>\n\n<h4>Acknowledgement:</h4>\n<ul>\n<li> The essential idea to model efficiency\n in this way is from Christoph Pelchen, ZF Friedrichshafen.</li>\n<li> The article (Pelchen et.al. 2002), see Literature below,\n and the first implementation of LossyGear (up to version 3.1 of package Modelica)\n contained a bug leading to a non-converging solution in cases where the\n driving side is not obvious.\n This was pointed out by Christian Bertsch and Max Westenkirchner, Bosch,\n and Christian Bertsch proposed a concrete solution how to fix this\n bug, see Literature below.</li>\n</ul>\n\n<h4>Literature</h4>\n\n<ul>\n<li>Pelchen C.,\nSchweiger C.,\nand <a href=\"http://www.robotic.dlr.de/Martin.Otter/\">Otter M.</a>:\n"<a href=\"https://www.modelica.org/events/Conference2002/papers/p33_Pelchen.pdf\">Modeling\nand Simulating the Efficiency of Gearboxes and of Planetary Gearboxes</a>," in\n<em>Proceedings of the 2nd International Modelica Conference, Oberpfaffenhofen, Germany,</em>\npp. 257-266, The Modelica Association and Institute of Robotics and Mechatronics,\nDeutsches Zentrum für Luft- und Raumfahrt e. V., March 18-19, 2002.</li>\n\n<li>Bertsch C. (2009):\n"<a href=\"modelica://Modelica/Resources/Documentation/Mechanics/Lossy-Gear-Bug_Solution.pdf\">Problem\nwith model LossyGear and a proposed solution</a>",\nTicket <a href=\"https://trac.modelica.org/Modelica/ticket/108\">#108</a>,\nSept. 11, 2009.</li>\n</ul>\n\n</html>"),
Icon(
coordinateSystem(
preserveAspectRatio = true,
extent = {
{-100, -100},
{100, 100}}),
graphics = {
Polygon(
fillColor = {161, 35, 41},
pattern = LinePattern.None,
fillPattern = FillPattern.Solid,
points = {
{-110, 50},
{-80, 50},
{-80, 80},
{-90, 80},
{-70, 100},
{-50, 80},
{-60, 80},
{-60, 30},
{-110, 30},
{-110, 50}}),
Line(points = {
{-80, 20},
{-60, 20}}),
Text(
lineColor = {0, 0, 255},
extent = {
{-148, 105},
{152, 145}},
textString = "%name"),
Text(
extent = {
{-145, -79},
{155, -49}},
textString = "ratio=%ratio"),
Line(
visible = useHeatPort,
points = {
{-100, -100},
{-100, -30},
{0, -30},
{0, 0}},
color = {191, 0, 0},
pattern = LinePattern.Dot)}));
end LossyGear;