modelica / ModelicaStandardLibrary

Free (standard conforming) library to model mechanical (1D/3D), electrical (analog, digital, machines), magnetic, thermal, fluid, control systems and hierarchical state machines. Also numerical functions and functions for strings, files and streams are included.

Home Page:https://doc.modelica.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Finding minimum and maximum values over time

ceraolo opened this issue · comments

Finding minimum and maximum of a signal over time has been discussed along the time, see:
modelica/ModelicaSpecification#109
and
https://stackoverflow.com/questions/30732774/modelica-compute-minimum-maximum-of-continuous-variable-over-time.

It seems to me that no final solution was found. In particular It results to me that all solutions proposed in the above stackoverflow ticket do not work in OpenModelica, because of being ill-conditioned or invalid Modelica code.

I think the two models I propose below for min(t) and max(t) work well. I've checked them with Dymola and Openmodelica: they simulate very fast and do not show any sign of numerical difficulties.

In case it is agreed upon, I could create a PR to insert them somewhere in MSL Blocks.

The following tiny package contains the two blocks TimeMin and TimeMax, and a "Test" model, to show their behaviour.
The following screenshot clarifies.
a

package FindMinMax
  model Test
    TimeMax timeMax(y_start=1)
                    annotation (
      Placement(transformation(origin={30,30},   extent = {{-10, -10}, {10, 10}})));
    Modelica.Blocks.Sources.RealExpression signal(y = time*sin(time/one)) annotation (
      Placement(transformation(origin = {-25, 0}, extent = {{-13, -10}, {13, 10}})));
    TimeMin timeMin(y_start=-1)
      annotation (Placement(transformation(extent={{20,-40},{40,-20}})));
    Modelica.Units.SI.Time one=1;
  equation 
    connect(signal.y, timeMax.u) annotation (
      Line(points={{-10.7,0},{8,0},{8,30},{18,30}},
                                        color = {0, 0, 127}));
    connect(timeMin.u, signal.y) annotation (Line(points={{18,-30},{8,-30},{8,0},{
            -10.7,0}}, color={0,0,127}));
    annotation (
      experiment(
        StopTime=30,
        Interval=0.04,
        Tolerance=1e-06), Diagram(coordinateSystem(extent={{-60,-60},
              {60,60}})));
  end Test;

  block TimeMax
    extends Modelica.Blocks.Interfaces.SISO(y(start=y_start));
    parameter Real y_start=0 "Initial or guess value of output";
    Boolean derpos(start=true);
    Real prevy;
  equation 
    when der(u)>0 then
      prevy=pre(y);
      derpos=true;
    elsewhen der(u)<0 then
      prevy=pre(y);
      derpos=false;
    end when;

    if derpos then
      y=max(u,prevy);
    else
      y=prevy;
    end if;
    annotation (Icon(graphics={                                                                           Text(textColor = {160, 160, 164}, extent={{-100,32},
                {100,-26}},                                                                                                                                                  textString = "max(t)")}),
        Documentation(info="<html>
<p><span style=\"font-size: 9pt;\">Outputs the maximum value over time during the simulation.</span></p>
</html>",   revisions="<html>
<ul>
<li><em>June, 2024   </em>
       by Massimo Ceraolo <br>initially implemented<br>
</li>
</html>"));
  end TimeMax;

  block TimeMin
    extends Modelica.Blocks.Interfaces.SISO(y(start=y_start));
    parameter Real y_start=0 "Initial or guess value of output";
    Boolean derNeg(start=true);
    Real prev_y;
  equation 
    when der(u)<0 then
      prev_y=pre(y);
      derNeg=true;
    elsewhen der(u)>0 then
      prev_y=pre(y);
      derNeg=false;
    end when;

    if derNeg then
      y=min(u,prev_y);
    else
      y=prev_y;
    end if;
    annotation (Icon(graphics={   Text(textColor={160,160,
                164},   extent={{-100,30},
                {100,-28}},
            textString="min(t)")}), Documentation(info="<html>
<p><span style=\"font-size: 9pt;\">Outputs the minimum value over time during the simulation.</span></p>
</html>",   revisions="<html>
<ul>
<li><em>June, 2024   </em>
       by Massimo Ceraolo <br>initially implemented<br>
</li>
</html>"));
  end TimeMin;
  annotation (uses(Modelica(version="4.0.0")));
end FindMinMax;

It seems to me that no final solution was found.

It actually is available since end of 2017: See #4381 for an alternative to the derivative-based or sample-based implementations.

I've had a look at the link.

It seems to me that is shows something different than this ticket's proposal:
I see in the comment:
here is one drawback, too: LastLib is not tool-agnostic and requires a tool-specific redeclaration of LastLib.Last for the imported FMU.

My implementation, instead, is tool-agnostic, does not require any lib, and is totally unrelated to FMI. It would offer two very simple blocks directly inside MSL.
And, looking at the several discussions out there, its seems there is much need for them.

It seems to me that is shows something different than this ticket's proposal

I am afraid I cannot follow. It seems to me that you did not check the references given by #4381. #4381 is a showcase to compensate the drawbacks of the existing sample-based implementation of Modelica.Blocks.Math.SignalExtrema (many artificial time-events) or derivative-based implementation of Modelica.Blocks.Math.ContinuousSignalExtrema (artificial state variable or need for approximation).

Closing in favour of the available blocks or alternatives:

  1. Modelica.Blocks.Math.SignalExtrema: sample-based
  2. Modelica.Blocks.Math.ContinuousSignalExtrema: derivative-based
  3. MinimumTest.Minimum via LastLib: event-free and derivative-free