Our next example involving functions demonstrates how to address issues that come up when solving non-linear systems of equations that involve functions.

We’ll start with a simple model that includes this simple mathematical relationship:

y = 2 t^2 + 3 t + 1

where t is time. This model can be implemented in Modelica as follows:

model ExplicitEvaluation
  "Model that evaluates the quadratic function explicitly"
  Real y;
  y = Quadratic(2.0, 3.0, 1.0, time);
end ExplicitEvaluation;

where the Quadratic function, which we will discuss shortly, evaluates a quadratic polynomial.

Simulating this model gives the following solution for y:


So far, all of this appears quite reasonable and, based on our previous discussion on Polynomial Evaluation, the implementation of Quadratic isn’t likely to hold too many surprises. However, let’s make things a little more complicated. Consider the following model:

model ImplicitEvaluation
  "Model that requires the inverse of the quadratic function"
  parameter Real y_guess=2;
  Real y(start=y_guess);
  time+1 = Quadratic(2.0, 3.0, 1.0, y);
end ImplicitEvaluation;

This model amounts to solving the following equation:

t+5 = 2 y^2 + 3 y + 1

The important difference here is that the left hand side is known and we must compute the value of y that satisfies this equation. In other words, instead of evaluating a quadratic polynomial, like we were doing in the previous example, now we have to solve a quadratic equation.

A model that requires solving a non-linear system of equations is not remarkable by itself. Modelica compilers are certainly more than capable of recognizing and solving non-linear systems of equations (although these methods usually depend on having a reasonable initial guess in order to converge).

However, it turns out that in this case, the Modelica compiler doesn’t actually need to solve a non-linear system. Although we couldn’t know this until we saw how the Quadratic function is implemented:

function Quadratic "A quadratic function"
  input Real a "2nd order coefficient";
  input Real b "1st order coefficient";
  input Real c "constant term";
  input Real x "independent variable";
  output Real y "dependent variable";
  y := a*x*x + b*x + c;
  annotation(inverse(x = InverseQuadratic(a,b,c,y)));
end Quadratic;

In particular, note the line specifying the inverse annotation. With this function definition, we not only tell the Modelica compiler how to evaluate the Quadratic function, but, through the inverse annotation, we are also indicating that the InverseQuadratic function should be used to compute x in terms of y.

The InverseQuadratic function is defined as follows:

function InverseQuadratic
  "An inverse of the quadratic function returning the positive root"
  input Real a;
  input Real b;
  input Real c;
  input Real y;
  output Real x;
  x := sqrt(b*b - 4*a*(c - y))/(2*a);
end InverseQuadratic;


Note that the InverseQuadratic function computes only the positive root in the quadratic equation. This can be both a good thing and a bad thing. By computing only a single root, we avoid the issue of having multiple solutions when we invert the quadratic relationship. However, if the negative root happens to be the one you want, this can be a problem.

In the case of our ImplicitEvaluation model, the Modelica compiler can then substitute this inverse function into the equations. So, where we initially had, ignoring the coefficient arguments for the moment, the following equation to solve:

t+5 = f(y)

which must be solved as an implicit equation for y , we can now solve the following explicit equation:

y = f^{-1}(t+5)

by using the InverseQuadratic function as the inverse function.

Simulating the ImplicitEvaluation model we get the following solution for y:


Looking at this figure, we can see that, in fact, we got the correct result, but, in general, without the need to solve the non-linear system that would otherwise result from our ImplicitEvaluation model.