issue generating triangular wave function in Modelica - modelica

I'm trying to create a model where one Modelica variable is a triangular wave of another variable. First I tried the floor() function as below:
model test1
final constant Real pi=2*Modelica.Math.asin(1.0);
parameter Real b = 1;
parameter Real a = 1;
Real x,p,u;
equation
if sign(sin(x*pi/b))>=0 then
p=a*(x-b*floor(x/b));
else
p=a*(b-(x-b*floor(x/b)));
end if;
x=time;
u = floor(x/b);
end test1
(x=time; is arbitrary so the model compiles)
but the result is weird, as you can see below
zoom in:
somehow 0.005 seconds before the next step floor function behaves unexpectedly and becomes a linear function ending by the next value.
then I tried the ceil() function. everything seemed right till I realised the same problem happens with ceil() function at other values (e.g. x=13)
I would appreciate if you could:
help me understand why this "glitch" happens and if it is intentional by design or a bug?
how I can fix this?
are there any alternatives to create a triangular wave function?
P.S. I am using this "wave function" to model the interaction between two jagged bodies"

If you are allowed to utilize the Modelica Standard Library, you can build up a parametrized, time-based zigzag signal using the CombiTimeTable block with linear interpolation and periodic extrapolation. For example,
model Test4
parameter Real a=2 "Amplitude";
parameter Real b=3 "Period";
Real y=zigzag.y[1] "Zigzag";
Modelica.Blocks.Sources.CombiTimeTable zigzag(
table=[0,0;b/4,a;b/4,a;b/2,0;b/2,0;3*b/4,-a;3*b/4,-a;b,0],
extrapolation=Modelica.Blocks.Types.Extrapolation.Periodic)
annotation(Placement(transformation(extent={{-80,60},{-60,80}})));
Modelica.Blocks.Sources.Trapezoid trapezoid(
amplitude=2*a,
rising=b/2,
width=0,
falling=b/2,
period=b,
offset=-a)
annotation(Placement(transformation(extent={{-80,25},{-60,45}})));
annotation(uses(Modelica(version="3.2.2")));
end Test4;

I don't have an explanation for the glitches in your simulation.
However, I would take another approach to the sawtooth function: I see it as an integrator integrating +1 and -1 upwards and downwards. The integration time determines the amplitude and period of the sawtooth function.
The pictures below show an implementation using MSL blocks and one using code. The simulation results below are the same for both implementations.
Best regards,
Rene Just Nielsen
Block diagram:
Code:
model test3
parameter Real a=2 "amplitude";
parameter Real b=3 "period";
Real u, y;
initial equation
u = 1;
y = 0;
equation
4*a/b*u = der(y);
when y > a then
u = -1;
elsewhen y < -a then
u = 1;
end when;
end test3;
Simulation result:

The problem I guess is due to floating point representation and events not occurring at exact times.
Consider x-floor(x) and 1-(x-floor(x)) at time=0.99, they are 0.99 and 0.01; at time=1.00 they are 0.0 and 1.0, which causes your problems.
For a=b=1, you can use the following equation for p:
p=min(mod(x,2),2-mod(x,2));. You can even add noEvent to it, and you can consider the signal continuous (but not differentiable).
model test
parameter Real b = 1;
parameter Real a = 3;
Real x, p;
equation
p = 2*a*min(1 / b * mod(x, b ),1 - 1/b * mod(x, b));
x = time;
end test;

My first advise would be to remove the sign-function, since there is no benefit of doing sign(foo)>=0 compared to foo>=0.
Interesting enough that seems to fix the problem in Dymola - and I assume also in OpenModelica:
model test1 "almost original"
final constant Real pi=2*Modelica.Math.asin(1.0);
parameter Real b = 1;
parameter Real a = 1;
Real x,p,u;
equation
if sin(x*pi/b)>=0 then
p=a*(x-b*floor(x/b));
else
p=a*(b-(x-b*floor(x/b)));
end if;
x=time;
u = floor(x/b);
end test1;
Now I only have to explain that - and the reason is that sin(x*pi/b) is slightly out of sync with the floor-function, but if you use sin(x*pi/b)>=0 that is within the root-finding epsilon and nothing strange happen.
When you use sign(sin(x*pi/b))>=0 that is no longer possible, instead of having sin(x*pi/b) an epsilon below zero it is now -1, and instead of epsilon above zero it is 1.
The real solution is thus slightly more complicated:
model test2 "working"
parameter Real b = 1;
parameter Real a = 1;
Real x,p,u;
Real phase=mod(x,b*2);
equation
if phase<b then
p=a/b*phase;
else
p=a-a/b*(phase-b);
end if;
x=time;
u = floor(x/b);
end test2;
which was improved based on a suggested solution:
model test3 "almost working"
parameter Real b = 1;
parameter Real a = 1;
Real x,p,u;
equation
if mod(x,2*b)<b then
p=a/b*mod(x,b);
else
p=a-a/b*mod(x,b);
end if;
x=time;
u = floor(x/b);
end test3;
The key point in this solution, test2, is that there is only one problematic event generating expression mod(x,2*b) - and the < will not get out of sync with this.
In practice test3 will almost certainly also work, but in unlikely cases the event generation might get out of sync between mod(x,2*b) and mod(x,b); with unknown consequences.
Note that all three examples are now modified to generate output that looks similar.

Related

Why the initialization setting in the dsin.txt file is different from the Model in Dymola?

I build a simple model in Dymola, I choose to use i_R1 to set the intializaiton condition, as shown in the follwing code and screenshot.
model circuit1
Real i_gen(unit="A") "Current of the generator";
Real i_R1(start=1,fixed=true,unit="A") "Current of R1";
Real i_R2(unit="A") "Current of R2";
Real i_C(unit="A") "Current of the capacitor";
Real i_D(unit="A") "Current of the diode";
Real u_1(unit="V") "Voltage of generator";
Real u_2(unit="V") "Output voltage";
// Voltage generator
constant Real PI = 3.1415926536;
parameter Real U0( unit="V") = 5;
parameter Real frec( unit="Hz") = 100;
parameter Real w( unit="rad/s") = 2*PI*frec;
parameter Real phi( unit="rad") = 0;
// Resistors
parameter Real R1( unit="Ohm") = 100;
parameter Real R2( unit="Ohm") = 100;
// Capacitor
parameter Real C( unit="F") = 1e-6;
// Diode
parameter Real Is( unit="A") = 1e-9;
parameter Real Vt( unit="V") = 0.025;
equation
// Node equations
i_gen = i_R1;
i_R1 = i_D + i_R2 + i_C;
// Constitutive relationships
u_1 = U0 * sin( w * time + phi);
u_1 - u_2 = i_R1 * R1;
i_D = Is * ( exp(u_2 / Vt) - 1);
u_2 = i_R2 * R2;
C * der(u_2) = i_C;
end circuit1;
But after translation, in the dsin.txt, it shows that i_R1 is a free variable, but u_2 is fixed.
My question is:
Why Dymola sets u_2 as fixed instead of i_R1?
The first column in dsin.txt is now primarily used for continue simulation in Dymola, and is otherwise sort of ignored.
If you want to know which values are relevant for starting the simulation, i.e. parameters and variables with fixed=true you should instead look at the 6th column and x&8, that shows that i_R1, U0, freq, phi, R1, R2, C, Is, and Vt will influence a normal simulation.
For continue simulation it is instead x&16 that matters, so u_2 instead of i_R1.
The x above is the value in the 6th column, and &8 represents bitwise and. In Modelica you could do mod(div(x, 8),2)==1 to test the numbers.
Better read Hans Olsson's answer, he knows better, still here is what I wrote:
I didn't implement it, so take everything with a grain of salt:
dsmodel.mof for the posted example, contains the following code:
// Initial Section
u_1 := U0*sin(w*time+phi);
u_2 := u_1-i_R1*R1;
Using the values from the example results in u_1 = 0 and u_2=-100. So it seems the fixed start value for i_R1 is used to compute the initial value u_2 using the above equations.
This should be the reason for the fixed statements in the model and dsin.txt being different in dsin.txt compared to the original Modelica code. Basically information from the model is used to compute the initial value of the state (u_2) from the start value from an auxiliary variable (i_R1). In the executed code, the state is being initialized.
Speculation: u_2 is unknown when creating dsin.txt, so it is set to zero and computed later. This should correspond to the first case described in dsin.txt in
"Initial values are calculated according to the following procedure:"
which is when all states are fixed.
I think it is a bug: even though it is signed as fixed, the voltage u_2 starts at -100V instead of 0V when I simulate it, and i_R1 starts at 1A.
Speculation: Perhaps the sorting algorithms are allowed during translation to set fixed initial values to more meaningful variables, as long as the condition given by the Modelica code (i_R1=1, in your case) is met. If that's the case, it would still count as a bug for me, but it might explain what's going on.

How can make the logic avoiding discrete derivative in the when clause in Modelica?

i'm making the logic calculating the p(pressure) of the internal combustion engine.
equations consist of several cases called 'Period' in when clause.
when Period==1 then
p = pre(p) * ( T / pre(T)) ^( Gamma/(Gamma-1));
elsewhen Period==0 or Period==2 or Period==3 then
p = ( m*R_gas*der(T)+m*T*der(R_gas)+R_gas*T*der(m)-V*der(p) ) / der(V);
end when;
the only unknown variable in the code is p and i got the error messages like below
In the message said that equation p is discrete and cannot be differentiated.
But, i thought that it's not discrete equations.
Even Though it is discrete equations, i don't expect the error because der(p) part is only in the second clause.
How can i fix this problem?
Can you explain what behavior you want?
The 1st equation,
when Period==1 then
p = pre(p) * ( T / pre(T)) ^( Gamma/(Gamma-1));
works on its own, but the 2nd equation above for p will only be active when Period becomes 0, 2, or 3. That is just a single point in time, so I cannot understand what der(p) should be in that right-hand-side.
Additionally if an equation involves both p and der(p) the equation is normally solved to compute der(p) based on p, but I'm not sure if that is the goal here.
Added:
Your comments seem to indicate that you want the equation to be valid while Period gets a new value and not only when at an instance. In Modelica when for equations that only should be valid once when the condition becomes true, and if is for equations that are valid while the condition is true.
That would lead to something like:
if Period==1 then
...
else
p = ( m*R_gas*der(T)+m*T*der(R_gas)+R_gas*T*der(m)-V*der(p) ) / der(V);
end if;
However, the first equation is problematic in that case. I guess you want x=T^(Gamma/(Gamma-1))/p to remain constant in that part, and unfortunately writing that directly would lead to changing index which is currently not supported in Modelica.
However, an alternative is to say that it has zero derivative, and that would give something like:
x=T^(Gamma/(Gamma-1))/p;
if Period==1 then
der(x)=0;
else
p = ( m*R_gas*der(T)+m*T*der(R_gas)+R_gas*T*der(m)-V*der(p) ) / der(V);
end if;
But it is not certain that it will work, as I haven't seen the entire model.

Accessing record parameters in Modelica without declaring a record instance

In Modelica, I'm able to access the contents of a record instance like so:
model Unnamed1
record Example
parameter Real x = 5;
end Example;
Example ex;
Real test;
equation
test = ex.x;
end Unnamed1;
However, I'd like to access the contents of the record without declaring an instance of the record, like so:
model Unnamed1
record Example
parameter Real x = 5;
end Example;
Real test;
equation
test = Example().x;
end Unnamed1;
...but this doesn't work. Is there some way to achieve what I'm trying to do?
Yes, it is possible without having an actual instance in the model but it requires some extra code.
model Unnamed1
record Example
parameter Real x = 5;
end Example;
function getX
input Example r;
output Real x;
algorithm
x:=r.x;
end getX;
Real test;
equation
test = getX(Example());
end Unnamed1;
(I'm aware that it is cheating by having the instance in the function, but....)
Another option is
for r in {Example()} loop
test=r.x;
end for;
(allowed according to https://github.com/modelica/ModelicaSpecification/issues/1521 )
This is not possible (even from a grammar point of view). The right hand side of dot (.) needs to be a class or component reference. You can only access constants/parameters in packages via the dot notation.
package X
constant Real x = 1;
end X;
model M
Real x = X.x
end M;

Dynamically switching connect in Modelica

Assume I have a large connector involving all kinds of base types (Real, Integer, String, Boolean). How can I switch connections based on state events?
I would like to do something like this:
model switch
input ComplicatedConnector icon[2];
output ComplicatedConnector ocon;
input Real x;
equation
if x >= 0 then
connect(ocon, icon[1]);
else
connect(ocon, icon[2]);
end if;
end switch;
This does not work. How can it be properly expressed in Modelica?
Answer based on comment by Adrian Pop.
model switch
input ComplicatedConnector icon[2];
output ComplicatedConnector ocon;
input Real x;
ComplicatedConnector con;
initial equation
con = icon[1];
equation
connect(ocon, con);
when x >= 0 then
con := icon[1];
end when;
when x < 0 then
con := icon[2];
end when;
end switch;
Update: The model above is wrong because ocon outputs the initial value of icon[1] forever if no event occurs which is not what you would expect from a switch. Note that this is not due to a wrong answer but due to my false interpretation of the answer. The following model is based on the answer by Michael Tiller.
model switch
input ComplicatedConnector icon[2];
output ComplicatedConnector ocon;
input Real x;
Integer k;
initial equation
k = 1;
equation
ocon = icon[k];
when x >= 0 then
k := 1;
elsewhen x < 0 then
k := 2;
end when;
end switch;
Is not possible. You can only switch them based on a parameter known at compile time (also known as structural parameter). The condition in the if equation containing connects needs to be a parameter expression.
Note that connect statements are equations. You can expand them out yourself. They exist mainly to avoid "bookkeeping" errors for generating boilerplate equations. So what I suggest you do is simply take your switch model and expand each connect into equations. The it should work.

Modelica: Calculating a variable using both der() and explicit declaration

I apologize for the poor title, but I found it hard to describe the problem in a comprehensible way.
What I want to do is to solve an ODE, but I don't want to start integrating at time = 0. I want the initial value, i.e. the starting point of the integration, to be accessible for changes until the integration starts. I'll try to illustrate this with a piece of code:
model testModel "A test"
parameter Real startTime = 10 "Starting time of integration";
parameter Real a = 0.1 "Some constant";
Real x;
input Real x_init = 3;
initial equation
x = x_init;
equation
if time <= startTime then
x = x_init;
else
der(x) = -a*x;
end if;
end testModel;
Notice that x_init is declared as input, and can be changed continuously. This code yields an error message, and as far as I can tell, this is due to the fact that I have declared x as both der(x) = and x =. The error message is:
Error: Singular inconsistent scalar system for der(x) = ( -(if time <= 10 then x-x_init else a*x))/((if time <= 10 then 0.0 else 1.0)) = -1e-011/0
I thought about writing
der(x) = 0
instead of
x = init_x
in the if-statement, which will avoid the error message. The problem in such an approach, however, is that I lose the ability to modify the x_init, i.e. the starting point of the integration, before the integration starts. Lets say, for instance, that x_init changes from 3 to 4 at time = 7.
Is there a work-around to perform what I want? Thanks.
(I'm gonna use this to simulate several submodels as part of a network, but the submodels are not going to be initiated at the same time, hence the startTime-variable and the ability to change the initial condition before integration.)
Suggested solution: I've tried out the following:
when time >= startTime
reinit(x,x_init);
end when;
in combination with the der(x) = 0 alternative. This seems to work. Other suggestions are welcome.
If your input is differentiable, this should work:
model testModel "A test"
parameter Real startTime = 10 "Starting time of integration";
parameter Real a = 0.1 "Some constant";
Real x;
input Real x_init = 3;
initial equation
x = x_init;
equation
if time <= startTime then
der(x) = der(x_init);
else
der(x) = -a*x;
end if;
end testModel;
Otherwise, I suspect the best you could do would be to have your x variable be a very fast first-order tracker before startTime.
The fundamental issue here is that you are trying to model a variable index DAE. None of the Modelica tools I'm aware of support variable index systems like this.