I'd like to figure out whether it's possible (and semantically legal) in Modelica to simulate a model of a first-order transfer function, with a time constant equal to zero (T below). I'm using OpenModelica 1.15.0~dev-48-g3656b95, but I'm asking the question in a general Modelica context.
My context is experimenting Model Order Reduction on Modelica models, which brings me to try to use the Modelica.Blocks.Continuous.FirstOrder with a sometimes null time constant. However, to make the discussion simpler, here is the flat model I'm working on (a simplification and adaptation of the standard FirstOrder block):
model FirstOrderZero
import Modelica.SIunits;
Real u "input";
Real y "output";
parameter Real k(unit="1")=1 "Gain";
constant SIunits.Time T=0 "Time Constant";
equation
u = 1;
der(y) = (k*u - y)/T;
end FirstOrderZero;
I understand that the way Modelica tools operate a symbolic equation analysis, the time constant T should be constant rather than a parameter. Indeed, for T=0, the differential equation gets degenerated into an algebraic equation y = k*u. Unless the Modelica simulation tool can generate different code pathways for different values of T (which I think no Modelica tool does, except maybe Modia in the future?), the fact that T is null or not should be decided at the beginning of the equation analysis.
What I don't understand is why the above model fails to simulate ("division by zero at time 0 [...] where divisor expression is 0.0" with OM 1.15 dev) whereas it works when the last equation is rewritten as:
T*der(y) = (k*u - y);
I would assume that the symbolic equation analysis should reformulate the equation automatically? (I can see with OM Transformational Debugger that the equation becomes der(y) = (k - y)/0.0 which, of course, breaks at simulation).
Or perhaps, is it syntactically illegal to write Modelica equations with a division by a null constant?
Variability of T
If the time constant T is constant, a parameter, or maybe a (discrete) variable depends on what you want to do.
the value of constants gets fixed during translation
parameters can be changed after translation (so before a simulation is started), but not during simulation
discrete variables can change their value during simulation, but only at event instances
continuous variables can change their value during simulation
See 4.4.4 Component Variability Prefixes discrete, parameter, constant in the Modelica Specification 3.4 for details.
For first order elements you usually use a transfer function that will not change during simulation, but the user should be able to set the value of T. Therefore parameter would be the natural choice.
Why your simulation fails
By using a constant for T, the Modelica tool can optimize your equations more than it can when you use a parameter. And depending on how you write your equations, you will end up with a different optimized equation.
For constant T=0 your original model reduces to
model FirstOrderZero
Real u, y;
parameter Real k=1;
equation
u = 1;
der(y) = (k*u - y)/0;
end FirstOrderZero;
To solve y its derivative der(y) is needed - but it can not be computed, as a division by zero always occurs.
In the second case with T*der(y) = (k*u - y); your model reduces to
model FirstOrderZero
Real u, y;
parameter Real k=1;
equation
u = 1;
0 * der(y) = (k*u - y);
end FirstOrderZero;
The equation 0 * der(y) = (k*u - y) results in 0 = (k*u - y) and therefore y = k*u. There is no division by zero and the model can be simulated.
You see, even though Modelica is an acausal language, it can matter how you write your equations.
What you can do
A first order element with T=0 is not a first order element anymore, but only a proportional gain. To model that, use the block Modelica.Blocks.Continuous.TransferFunction.
If T is not zero, parametrize it like this:
Modelica.Blocks.Continuous.TransferFunction transferFunction(b={k}, a={T,1})
and if its zero use
Modelica.Blocks.Continuous.TransferFunction transferFunction(b={k}, a={1})
Related
I build a model that includes a derivative of dy/dx=5, as shown in the following segment, but the model fails during initialization in Dymola, in another question, it has been answered. The reason is that at time=0, the values of der(x) and der(y) are both 0. So there would be an error of division by 0.
model HowToExpressDerivative "dy/dx=5, how to describe this equation in Modelica?"
extends Modelica.Icons.Example;
Real x, y;
equation
x = time ^ 2;
der(y) / der(x) = 5;
end HowToExpressDerivative;
Here is the result in Dymola:
But when I try the same model in the Wolfram System Modeler and OpenModelica, the model works fine.
In the Wolfram System Modeler, it uses the equation of der(y)/der(x)=5 directly.
My questions are:
Why Would the same model fail in Dymola?
Does Dymola NOT have the ability to do automatic symbolic manipulation to transform this equation of der(y)/der(x)=5 into der(y)=5*der(x)?
Or the numerical solver in Dymola can't handle this kind of situation?
Dymola does currently not recognize that trivial simplification in that case (it is done in another case), not because it would be too complicated, but because Dymola uses a simple rule:
Division in the Modelica code are safe, other divisions are not considered safe.
Thus der(x)/der(y)=5 indicates that division by der(y) is safe (even though it clearly isn't), whereas solving that equation technically involves dividing by 1/der(y) which isn't deemed safe (as it didn't occur in the Modelica code).
Obviously the logic can be improved, but the simplest solution is to use the following rule: don't divide in your code unless it is safe to do so.
A benefit of following that rule is that it will be possible to check all the original equations and see that they are satisfied (up to numerical precision) - without triggering division by zero.
Update: In Dymola2023 the model compiles and runs correctly.
// Initial Section
der(x) := 2.0*time;
der(y) := 5.0*der(x);
// --------------------------------------------------------------------------
// Dynamics Section
der(x) := 2.0*time;
der(y) := 5.0*der(x);
I have to solve the following system:
X'(t) = -D(t)x(t)+μ(s(t), p(t))x(t);
S'(t) = D(t)(s(t)^in - s(t)) - Yxsμ(s(t), p(t))x(t)
p'(t) = -D(t)p(t)+(aμ(s(t), p(t))+b)x(t)
where
μ(s(t), p(t)) = Μmax ((1 - (p(t)/pm))s(t)) / (km+s(t)+(s(t) ^ 2)/ki)
where Yxs, a,b, Mmax, Pm, km, ki are constant variables, then I have to linearizate the system and find the balance Points of thiw system. any suggestion how to do it with Matlab or Mathematica??
Matlab can help with some steps, but there might be few where you do have to write down some equations yourself.
To start with a simple side note: Matlabs ODE45 function allows to simulate any function of the form dx/dt = f(x,u), regardless of how non-linear or time variant they might become.
to linearize such a system, you need to derive a jacobian matrix and substitute the linearization point in this matrix. This linearization point is any point where all state derivatives equal 0, it does not need to be a balance point. However, it is desired to have it a balance point as this means the linearization point is a stable equilibrium.
So in MATLAB:
create symbolic variables for all states and inputs (so x(t), s(t) and p(t))
create symbolic state equations dx/dt = f(x,u) and output equation y = g(x,u)
derive symbolic State space matrices A,B,C,D using the "jacobian" function
substitute linearization point in these symbolic state space matrices using "subs"
use eval(symbolic matrix) to retrieve a numeric matrix.
Depending on the non-linear complexity and the chosen linearization point, the linearized system might only within acceptable bounds from the actual system for a very tight region, so be aware of that.
I wanted to do the following in Modelica: in a specific model I have several parameters h and I want to deduce some time independent values k from them by solving a set of implicit equations between the parameters and the other values. Since the equations are implicit by nature, I cannot simply assign an expression, I rather have to let the solver find the solution.
Since the parameters are constant, I want to be able to solve the equations only once at the beginning, before the actual time integration of the rest of the system (e.g. a differential equation that contains k as a coefficient) takes place.
See the following example of what I would like to be able to write:
model ConstantTest
parameter Real h = 2;
const Real k;
initial equation
k*k=h; // just an example of an implicit equation, which in this simple case could also be written explicitly
end ConstantTest;
But this fails because a "constant" in Modelica is not only constant in the sense of having vanishing time derivative, but it is also already immutable at the time when the initial equations are being solved. So the solver complains that it cannot solve the initial equation 0 = 2, which is because it is assuming that k invariably equals 0.
Of course I can just make k a variable, but then I have to tell the solver explicitly that k has vanishing time derivative (amounting to it being practically "constant" in the naive physical sense):
model ConstantTest
parameter Real h = 2;
Real k;
initial equation
k*k=h;
equation
der(k) = 0;
end ConstantTest;
This works, but it is somewhat odd because the solver has to solve a trivial differential equation at every time step in order to do basically nothing at all to k. And that would be a waste of computational resources.
Is there any way to solve static implicit equations with Modelica without introducing "time evolution overhead"?
I guess you could do this:
model ConstantTest
parameter Real h = 2;
parameter Real k(fixed=false);
initial equation
k*k=h;
end ConstantTest;
k will be computed at initialization.
I think the best way to define these kinds of systems is:
model ConstantTest
parameter Real h = 2;
Real k;
equation
2*k=h;
end ConstantTest;
Which OpenModelica will put in an initial section and solve only once. I would consider OpenModelica's behaviour for your system a bug since it's solving a time-independent equation multiple times.
The following construct generates an error saying that there are too many equations.
model Model1
model myBlock
input Modelica.Blocks.Interfaces.RealInput u(start=1e99);
output Modelica.Blocks.Interfaces.RealOutput y;
parameter Real p=1 "Parameter";
equation
u=min(u,p);
u=y;
end myBlock;
myBlock b1;
myBlock b2 (p=0.5);
myBlock b3;
input Modelica.Blocks.Interfaces.RealInput u;
output Modelica.Blocks.Interfaces.RealOutput y;
equation
connect(y,b1.u);
connect(b1.y,b2.u);
connect(b2.y,b3.u);
connect(b3.y,u);
end Model1;
The idea is to get the same minimum value for u and y in all the "myBlock" components.
However the assignement for u (=min...) seems to be obligatory valid for all components and cannot be calculate one after the other.
Any idea how I can solve this problem? Thanks.
I don't entirely understand the intent of this model. It is not clear to me whether you expect to find the minimum of all u values over time or just the current value of u vs. p? If the former, then that isn't what min is for. If the latter, then you are on the right track...
Assuming the latter, then your main misconception seems to be about the semantics of equations. It looks to me like you are assuming that you start with one value of u. Then you "reassign" that value to be the min(u,p). Then, finally, you assign y to this "reassigned" value of u.
All that would be fine if you had an algorithm section in your model. This is because an algorithm section has assignment semantics (this is the "imperative" semantic in most programming languages).
But you have an equation section. The thing about an equation section is that the statements you wrote are equations. The important thing about equations is that they always apply. So in you model you have stated that u=min(u,p). This is not "overwriting" the value of u, it is stating an additional mathematical constraint. It is a bit like trying to solve the equation x=x*x. If you put this equation in your model it is the equivalent of saying x=0 because that is the only value of x that can satisfy the equation.
So the error about too many equations comes because if you look at your myBlock model, it has one input and one output. That means it has only one "unknown" to compute and therefore requires only one equation. You've given two equations (one too many).
I think what you want is:
model myBlock
input Modelica.Blocks.Interfaces.RealInput u;
output Modelica.Blocks.Interfaces.RealOutput y;
parameter Real p;
equation
y = min(u,p);
end myBlock;
This will "limit" the output, y, to be no less than p. Is that what you wanted?
Alternatively, you could write your model with an algorithm section and get something like this:
model myBlock
input Modelica.Blocks.Interfaces.RealInput u;
output Modelica.Blocks.Interfaces.RealOutput y;
parameter Real p;
algorithm
u := min(u,p) "This is assignment";
y := u;
end myBlock;
Note the behavior should be the same (although I confess I didn't test either model).
I hope that helps.
If i have to use a partial derivative in modelica, how can that be used. I am not sure if partial derivative can be solved in modelica but i would like to know, if it can be used then, how should it be implemented.
There are two different potential "partial derivatives" you might want. One is the partial derivative with respect to spatial variables (if you are interested in solving PDEs) or you might want the partial derivative of an expression with respect to a simulation variable.
But it doesn't matter, because you cannot express either of these in Modelica.
If your motivation is to solve PDEs, then I'm afraid you will simply have to process the spatial aspects in your models (using some kind of discretization, weak formulation, etc) so that the resulting equations are simple ODEs.
If you want to compute the derivative of expressions with respect to variables other than time, the question would be ... why? I'm hard pressed to think of an application where this is really necessary. But if you can explain your use case, I could comment further on how to handle it.
I've discretized PDE systems for solution in Modelica: heat equation, wave equation, PDEs from double-pipe heat exchangers, PDEs from water hammer to model pressure surges in pipelines etc
At a simple level, you can replace the spatial derivative with a central difference approximation, and then generate the entire set of ODEs with a for loop. For example. here's a Modelica code snippet for a simple discretization of the heat equation.
parameter Real L = 1 "Length";
parameter Integer n = 50 "Number of sections";
parameter Real alpha = 1;
Real dL = L/n "Section length";
Real[n] u(each start = 0);
equations
u[1] = 273; //boundary condition
u[n] =0; //boundary condition
for i in 2:n-1 loop
der(u[i]) = alpha * (u[i+1] - 2 * u[i] + u[i-1]) / dL^2;
end for;
This is just a simple example entered from the top of my head, so excuse any mistakes.
Do you have a specific example or application?