Modelica Simulation breaks when if condition changes - modelica

I try a simple code on modelica using if:
model thermostat1
parameter Real T0=10;
Real T(start=T0);
equation
if T<73 then
der(T)=-T+80;
else
der(T)=-T+50;
end if;
end thermostat1;
the simulation stops at the moment T reaches 73.
Why can't the simulation continue with the new equation ( der(T)=-T+50 )?
And how can i fix it?
Thank you.

What happens in your model is called chattering. This means, that there are very frequent events happening.
In you case specifically this is caused by the condition T<73 combined with the definitions of the derivatives. Let me try to explain what happens with the model you have provided:
The temperature rises until it reaches 73
Then the temperature starts to fall because the condition in the if-statement turns fall
This causes the if-statement to immediately change to true again, making the temperature rise
This causes the if-statement to change to false again, making the temperature fall
goto 3.
This causes the condition T<73 to change at a very high frequency, in turn creating many events, which have to be handled by the solver. This makes the progress in time very little (what you refer to as "the simulation stops").
There are multiple ways to solve this problem. One is to add a hysteresis to the model. I did that in code below. To describe the hysteresis part I used the code from Modelica.Blocks.Logical.Hysteresis. This will make the boolean variable upperLimit (which replaces your T<73) change only if temperature gets higher than T_highand lower than T_low. I chose this solution as it seems reasonable for a thermostat.
model thermostat1
parameter Real T0=10;
parameter Real T_High=74;
parameter Real T_Low=72;
Boolean upperLimit "Output of hysteresis block";
Real T(start=T0);
equation
upperLimit =not pre(upperLimit) and T > T_High or pre(upperLimit) and T >= T_Low;
if upperLimit then
der(T)=-T+50;
else
der(T)=-T+80;
end if;
end thermostat1;
The result of the simulation then looks like:
More general information can be found e.g. at http://book.xogeny.com/behavior/discrete/decay/

Related

What is the meaning of "Algebraic loop involving integers or booleans" in the error message

I'm making the PI controller using the Dymola Platform and i met the error message like below
And here's some of my code that consist of valve which calculate the disp and PI controller which control the amount of the disp.
They are communicating each other using the flag
//PI controller///
if flag_input==1 then //flag_input==1 : Stop control / flag_input==0 : Restart control//
control:=0;
else
control:=(P_term+I_term)/unit;
end if;
if error<0 then // error<0 : flag to Valve to restart calculating the disp//
flag_output:=1;
else
flag_output:=0;
end if;
//Valve//
if (26/5)*(thetta/(2*pi))*0.001>0.026 and flag_input==0 then
//restart calculating the disp when received flag==1 from the PI controller//
disp:=0.026;
flag:=1;
elseif (26/5)*(thetta/(2*pi))*0.001<0 and flag_input==0 then
disp:=0;
flag:=1;
else
disp:=(26/5)*(thetta/(2*pi))*0.001;
flag:=0;
end if;
Can someone tell me what is the meaning of algebraic loop error and figure out the problem?
From your code snippet it's hard to tell where exactly the problem is.
Dymola tells you that you created a large algebraic loop over all the variables listed at the top under Unknowns and the equations listed below in the section Equations.
This can happen easily when you create if statements with variables which depend on each other. Often you just have to use pre() at the right place to break the loop.
Let`s use another small example to explain the problem.
For some reason we try to count the full milliseconds, which have passed in the current simulation and stop, once we reach 100.
model count_ms
Integer y(start=0);
equation
if y >= 100 then
y = 100;
else
y = integer(1000*time);
end if;
end count_ms;
This code will produce a similar error as yours:
An algebraic loop involving Integers or Booleans has been detected.
Unknowns: y
Equations: y = (if y >= 100 then 100 else integer(1000*time));
From the error message we see that y can not be solved, due to the equation resulting from the if statement. The equation is not solvable, as y depends on itself. To solve such problems pre was introduced, which gives you access to the value of a variable had when the event was triggered.
To fix the code above, we simply have to use pre when we check for y
if pre(y) >= 100 then
and the model simulates as expected.

Modelica - freezing a specific time value during simulation

I am having a problem that could be easily solved in a causal environment like Fortran, but has proved difficult in Modelica, considering my limited knowledge
Consider a volume with an inlet and outlet. The inlet mass flow rate is specified, while the outlet mass flow is calculated based on pressure in the volume. When pressure in the volume goes above a set point, the outlet area starts to increase linearly from its initial value to a max value and remains fixed afterwards. In other words:
A = min( const * (t - t*) + A_0, A_max)
if p > p_set
where t* = the time at which pressure in the volume exceeds the set pressure.
The question is: there's a function to capture t* during the simulation? OR how could the model be programmed to do it? I have tried a number of ways, but models are never closed. Thoughts are welcome and appreciated!
Happy holidays/New Year!
Mohammad
You may find the sample and hold example in my book useful. It uses sampling based on time whereas you probably want it based on your pressure value. But the principle is the same. That will allow you to record the time at which your event occurred.
Addressing your specific case, the following (untested) code is probably pretty close to what you want:
...
Modelica.SIunits.Time t_star=-1;
equation
when p >= p_set then
t_star = time;
end when;
A = if t_star<0 then A_max else min(const*(t - t_star) + A_0, A_max);

Detecting change in RealInput variable in Dymola

I need to detect whenever there is a change in a RealInput value X. I habe tried to check
if X == pre(X), but only receive an error and a warning that Real cannot be compared for equality. I also thought about using the derivative of X, but there is no explicit expression for this.
Other thoughts of mine have been to try to sample the continuous input into discrete variables that I can compare. Could this work in some way?
Try the change() operator. It is described in $3.7.3.1 of the Modelica Specification. According to the specification, it will be expanded to X<>pre(X), so that might work as well.
The change() operator is only practically useful for non-Real signals. The reason is that <> is not defined for Real types. Instead, you'll need to create a model that checks to see whether the signal deviates from the last recorded value by more than a given "epsilon". I haven't tested it, but the code would look something like this:
model DetectChange
parameter Real eps;
input Real signal;
output Boolean change;
protected
Real last_value;
initial algorithm
last_value = signal;
algorithm
when pre(change) then
last_value := signal;
end when;
change := abs(signal-last_value)>=eps;
end DetectChange;
Again, I haven't tested this. But it gives you some idea.

Confused by when clauses in algorithm section

model try
Real x(start = 1);
algorithm
when x >= 7 then
reinit(x, 5);
end when;
equation
der(x) = 1 ;
end try;
The when statement should be triggered whenever the guard condition is changed from false to true.
But it is not the case in OpenModelica. The example try in OpenModelica showes that when is triggered only once. I was wondering whether it is the bug of OpenModelica or some misunderstanding from my side.
You are correct. I am pretty sure this would be a bug in OpenModelica. The model works as you would expect in Dymola 2013.
My guess is that it is related to the fact that your when condition involves x and the statements inside end up changing x (the same variable). It may be that it somehow fails to notice the reinit in the monitor function used to determine the point at which the when clause should trigger.

event location questions in MATLAB

Suppose in matlab the following:
[t, x, te, xe, ie] = ode15s(#myfunc, [tStart tFinal], x0, odeset('Events', #events));
Question 1
1a) The function events is called only after a successful step of the solver. Is this true?
1b) Just after the solver has made a successful step, is it possible that the last call of myfunc not be the call that lead to the successful step?
1c) If the events function contains multiple terminal events and upon a successful step it is detected that two of them (not just one) have occured, what would be the behavior of the solver?
Question 2
Suppose that myfunc contains the following code
if (check(x) > 2)
dx(3) = x(1)*x(2);
else
dx(3) = x(2)^2;
end
where check is some function of x.
One way to solve this problem is not use an events function. In my experience the ode solver can solve such problems that way.
The other way to solve this problem is use an events function to locate check(x) - 2 == 0, one terminal event for direction = 1 and another one for direction = -1. After the solver stops on either of the events a global variable eg myvar is set appropriately to distinguish between the two events, and then the simulation continues from where it stopped. In that case the code in myfunc will be
if (myvar == 1)
dx(3) = x(1)*x(2);
else
dx(3) = x(2)^2;
end
Both way yield correct results in simple cases. However I am trying to solve a very complex problem (additional events than the above and discontinous right-hand parts of the differential equations that are proven to be solvable at some cases) and I am trying to find out if the first way would yield different results than the second one.
One might tell that the ode would either fail to return a solution before tFinal or return a correct solution, but due to the discontinuity of the right-hand part the solver might not return a solution while a solution exists.
So in some sense, the question is: what is the practical-theoretical difference between using the first way and the second way?
Since I've spent some effort on these questions, I'm posting back some feedback.
Question 1
1a) Yes this is true. For reference see for example the ode15s.m matlab solver. However note that before the solver continues solving, the events function may be called several times for the sake of a more accurate te value.
1b) Yes this is also true.
1c) In this case the solver would terminate returning an ie vector containing the two (or even more) indexes of the events that stopped the solver. In that case, the te vector would contain equal elements (te(1) == te(2) will always return true). This is the only way to distiguish "double events" (meaning events that simultaneously stopped the solver after the same successful step) from "fake" events that are recorded when the ode solver continues solving after a terminal event (to understand better what I'm saying also read ode solver event location index in MATLAB ).
Tracing the odezero function will make 1c answer very clear.
Question 2
Now this is a tricky answer. **In general* both ways return correct results. However (and most naturally) they are not bound to return the exact solution points at the exact time points with the exact number of steps.
The notable difference between the two ways is that in the second one, we have a branch change only when a check(x)-2 sign change occurs using only the currently active branch. For example, suppose that the currently active branch is the first one. When the solver notices a sign change in check(x) - 2 after a successful step that was produced using only that branch, only then changes to the second branch. In simple words, both successful and unsuccessful steps are calculated using the very same branch before a use of the other branch can occur. However if we use the first way we may notice a use of the non-active branch during (for example) an unsucessful step.
With these in mind comes the verdict; the most general and strictly correct way to choose is the second one (using events). The first way should also return correct results. HOWEVER, due to the difference between the two ways, the first one could fail in very specific/extreme problems. I'm very tempted to provide information about my case, in which ONLY the second way could be safely used, but it truly is a long way to go.