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:
where is time. This model can be implemented in Modelica as follows:
model ExplicitEvaluation
"Model that evaluates the quadratic function explicitly"
Real y;
equation
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);
equation
time+1 = Quadratic(2.0, 3.0, 1.0, y);
end ImplicitEvaluation;
This model amounts to solving the following equation:
The important difference here is that the left hand side is known and we must compute the value of 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";
algorithm
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;
algorithm
x := sqrt(b*b - 4*a*(c - y))/(2*a);
end InverseQuadratic;
Note
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:
which must be solved as an implicit equation for , we can now solve the following explicit equation:
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.