VariableLimiter

block VariableLimiter "Limit the range of a signal with variable limits"
    extends Interfaces.SISO;

    parameter Boolean strict = false "= true, if strict limits with noEvent(..)"
        annotation (
            Evaluate = true,
            choices(checkBox = true),
            Dialog(tab = "Advanced"));
    parameter Types.VariableLimiterHomotopy homotopyType = Modelica.Blocks.Types.VariableLimiterHomotopy.Linear "Simplified model for homotopy-based initialization"
        annotation (
            Evaluate = true,
            Dialog(group = "Initialization"));
    parameter Real ySimplified = 0 "Fixed value of output in simplified model"
        annotation (Dialog(
            tab = "Advanced",
            enable = homotopyType == Modelica.Blocks.Types.VariableLimiterHomotopy.Fixed));
    parameter Boolean limitsAtInit = true "Has no longer an effect and is only kept for backwards compatibility (the implementation uses now the homotopy operator)"
        annotation (
            Dialog(tab = "Dummy"),
            Evaluate = true,
            choices(checkBox = true));
    Interfaces.RealInput limit1 "Connector of Real input signal used as maximum of input u"
        annotation (Placement(transformation(extent = {
            {-140, 60}, 
            {-100, 100}})));
    Interfaces.RealInput limit2 "Connector of Real input signal used as minimum of input u"
        annotation (Placement(transformation(extent = {
            {-140, -100}, 
            {-100, -60}})));
protected
    Real simplifiedExpr "Simplified expression for homotopy-based initialization";
equation
    if strict then 
        if homotopyType == Types.VariableLimiterHomotopy.NoHomotopy then 
            y = smooth(0, noEvent(if limit1 < u then limit1 else if u < limit2 then limit2 else u));
        else 
            y = homotopy(actual = smooth(0, noEvent(if limit1 < u then limit1 else if u < limit2 then limit2 else u)), simplified = simplifiedExpr);
        end if;
    else 
        if homotopyType == Types.VariableLimiterHomotopy.NoHomotopy then 
            y = smooth(0, if limit1 < u then limit1 else if u < limit2 then limit2 else u);
        else 
            y = homotopy(actual = smooth(0, if limit1 < u then limit1 else if u < limit2 then limit2 else u), simplified = simplifiedExpr);
        end if;
    end if;
    assert(limit2 <= limit1, "Input signals are not consistent: limit1 < limit2");
    simplifiedExpr = if homotopyType == Types.VariableLimiterHomotopy.Linear then u else if homotopyType == Types.VariableLimiterHomotopy.Fixed then ySimplified else 0;

    annotation (
        Documentation(info = "<html>\n<p>\nThe Limiter block passes its input signal as output signal\nas long as the input is within the upper and lower\nlimits specified by the two additional inputs limit1 and\nlimit2. If this is not the case, the corresponding limit\nis passed as output.\n</p>\n<p>\nThe parameter <code>homotopyType</code> in the Advanced tab specifies the\nsimplified behaviour if homotopy-based initialization is used:\n</p>\n<ul>\n<li><code>NoHomotopy</code>: the actual expression with limits is used</li>\n<li><code>Linear</code>: a linear behaviour y = u is assumed (default option)</li>\n<li><code>Fixed</code>: it is assumed that the output is fixed at the value <code>ySimplified</code></li>\n</ul>\n<p>\nIf it is known a priori in which region the input signal will be located, this option can help\na lot by removing one strong nonlinearity from the initialization problem.\n</p>\n</html>"),
        Icon(
            coordinateSystem(
                preserveAspectRatio = true,
                extent = {
                    {-100, -100}, 
                    {100, 100}}),
            graphics = {
                Line(
                    points = {
                        {0, -90}, 
                        {0, 68}},
                    color = {192, 192, 192}), 
                Line(
                    points = {
                        {-90, 0}, 
                        {68, 0}},
                    color = {192, 192, 192}), 
                Polygon(
                    points = {
                        {90, 0}, 
                        {68, -8}, 
                        {68, 8}, 
                        {90, 0}},
                    lineColor = {192, 192, 192},
                    fillColor = {192, 192, 192},
                    fillPattern = FillPattern.Solid), 
                Line(points = {
                    {-80, -70}, 
                    {-50, -70}, 
                    {50, 70}, 
                    {80, 70}}), 
                Line(
                    points = {
                        {-100, 80}, 
                        {66, 80}, 
                        {66, 70}},
                    color = {0, 0, 127}), 
                Line(
                    points = {
                        {-100, -80}, 
                        {-64, -80}, 
                        {-64, -70}},
                    color = {0, 0, 127}), 
                Polygon(
                    points = {
                        {-64, -70}, 
                        {-66, -74}, 
                        {-62, -74}, 
                        {-64, -70}},
                    lineColor = {0, 0, 127}), 
                Polygon(
                    points = {
                        {66, 70}, 
                        {64, 74}, 
                        {68, 74}, 
                        {66, 70}},
                    lineColor = {0, 0, 127}), 
                Polygon(
                    points = {
                        {0, 90}, 
                        {-8, 68}, 
                        {8, 68}, 
                        {0, 90}},
                    lineColor = {192, 192, 192},
                    fillColor = {192, 192, 192},
                    fillPattern = FillPattern.Solid), 
                Line(
                    visible = strict,
                    points = {
                        {50, 70}, 
                        {80, 70}},
                    color = {255, 0, 0}), 
                Line(
                    visible = strict,
                    points = {
                        {-80, -70}, 
                        {-50, -70}},
                    color = {255, 0, 0})}),
        Diagram(
            coordinateSystem(
                preserveAspectRatio = true,
                extent = {
                    {-100, -100}, 
                    {100, 100}}),
            graphics = {
                Line(
                    points = {
                        {0, -60}, 
                        {0, 50}},
                    color = {192, 192, 192}), 
                Polygon(
                    points = {
                        {0, 60}, 
                        {-5, 50}, 
                        {5, 50}, 
                        {0, 60}},
                    lineColor = {192, 192, 192},
                    fillColor = {192, 192, 192},
                    fillPattern = FillPattern.Solid), 
                Line(
                    points = {
                        {-60, 0}, 
                        {50, 0}},
                    color = {192, 192, 192}), 
                Polygon(
                    points = {
                        {60, 0}, 
                        {50, -5}, 
                        {50, 5}, 
                        {60, 0}},
                    lineColor = {192, 192, 192},
                    fillColor = {192, 192, 192},
                    fillPattern = FillPattern.Solid), 
                Line(points = {
                    {-50, -40}, 
                    {-30, -40}, 
                    {30, 40}, 
                    {50, 40}}), 
                Text(
                    extent = {
                        {46, -6}, 
                        {68, -18}},
                    lineColor = {128, 128, 128},
                    textString = "input"), 
                Text(
                    extent = {
                        {-30, 70}, 
                        {-5, 50}},
                    lineColor = {128, 128, 128},
                    textString = "output"), 
                Text(
                    extent = {
                        {-66, -40}, 
                        {-26, -20}},
                    lineColor = {128, 128, 128},
                    textString = "uMin"), 
                Text(
                    extent = {
                        {30, 20}, 
                        {70, 40}},
                    lineColor = {128, 128, 128},
                    textString = "uMax"), 
                Line(
                    points = {
                        {-100, 80}, 
                        {40, 80}, 
                        {40, 40}},
                    color = {0, 0, 127}), 
                Line(
                    points = {
                        {-100, -80}, 
                        {-40, -80}, 
                        {-40, -40}},
                    color = {0, 0, 127}), 
                Polygon(
                    points = {
                        {40, 40}, 
                        {35, 50}, 
                        {45, 50}, 
                        {40, 40}},
                    lineColor = {0, 0, 127}), 
                Polygon(
                    points = {
                        {-40, -40}, 
                        {-45, -50}, 
                        {-35, -50}, 
                        {-40, -40}},
                    lineColor = {0, 0, 127})}));
end VariableLimiter;