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 \(t\) 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;
Quadratic function, which we will discuss shortly,
evaluates a quadratic polynomial.
Simulating this model gives the following solution for
So far, all of this appears quite reasonable and, based on our
previous discussion on Polynomial Evaluation, the
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 \(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
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
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
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 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 \(y\), we can now solve the following explicit equation:
by using the
InverseQuadratic function as the inverse function.
ImplicitEvaluation model we get the following
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