What I want to model is a periodic time-varing real variable, the following code can not be simulated. Does somebody have suggestion?
class try
discrete Real x(start = 1);
algorithm
when sample(0,4) then
x := 1; // reinit(x, 1) also does not work
end when;
equation
der(x) = 1;
end try;
All the error message is listed as follows:
Translation 18:32:29 0:0-0:0 Internal error Transformation Module failed!
Translation 18:32:29 0:0-0:0 Internal error BackendDAETransform.reduceIndexDummyDer failed!
Translation 18:32:29 0:0-0:0 Internal error BackendDAETransform.selectDummyState: no state to select
Symbolic 18:32:29 10:3-10:13 Model is structurally singular, error found sorting equations 0.0 = 1.0;
for variables
The problem is that if you want the variable x to be continue between the sampling time istants you have to remove the discrete keyword, this will work fine:
class try
Real x(start = 1);
algorithm
when sample(0,4) then
reinit(x, 1);
end when;
equation
der(x) = 1;
end try;
Ciao,
Marco
Related
The following model in Dymola gives an error,
model Test1
Real outvar;
Real outvarc;
Real internal;
parameter Real Tp=0.1;
equation
when Clock(Tp) then
internal = time;
end when;
outvar = hold(outvarc);
algorithm
if (firstTick(internal)) then
outvarc := 1;
else
outvarc := previous(outvarc);
outvarc := outvarc + 1;
end if;
end Test1;
If I modify the variable internal as follows then the model works.
model Test2
Real outvar;
Real outvarc;
Boolean internal(start=true);
parameter Real Tp=0.1;
equation
when Clock(Tp) then
internal = false;
end when;
outvar = hold(outvarc);
algorithm
if (firstTick(internal)) then
outvarc := 1;
else
outvarc := previous(outvarc);
outvarc := outvarc + 1;
end if;
end Test2;
Is there any explanation why model Test1 is giving an error?
It fails in Dymola 2022x and earlier.
In Dymola 2023 and later it gives the warning:
The sub clock, BaseClock_0.SubClock_1, includes pre, time, or
non-clocked when, but no solver method is specified. This is not
correct according to the specification and it could indicate that it
was clocked by mistake. The warning can be disabled by setting
Advanced.Translation.WarnForMissingSolverMethod=false;
That suggests that the simplest solution would be:
when Clock(Tp) then
internal = sample(time);
end when;
Basically time is not a clocked variable. (Yes, I'm aware that time in clocked partitions is messier than this suggests.)
Here is a suggestion for a little more compact code of the overall model. It gives a bit different results as it uses the "discrete time" internal to make equations discrete/clocked automatically, but I guess the would be the use-case anyways (otherwise sampling time does not make a lot of sense).
model Test3
parameter Real Tp=0.1;
discrete Real internal; // "discrete" is optional in Dymola, but helps understanding
discrete Real outvarc(start=1, fixed=true); // setting an initial value
Real outvar;
equation
internal = sample(time, Clock(Tp)); // sampling time with a locally defined clock and store it to "internal"
outvarc = previous(outvarc)+internal; // using a sampled/clocked variable (internal) makes the equation discrete
outvar = hold(outvarc); // converting to a continuous variable from a clocked one
end Test3;
Suggestions for further improvements welcome...
I have a contrived Modelica model in which a have a state machine variable manipulated by multiple when statements:
model WhenExample
type State = enumeration(first, second, third);
State state;
initial equation
state = State.first;
equation
when sample(0, 1) then
state = State.second;
end when;
when sample(0, 3) then
state = State.third;
end when;
end WhenExample;
When compiling under OpenModelica OMC, I get the following error:
[1] 16:46:39 Symbolic Error
Too many equations, over-determined system. The model has 2 equation(s) and 1 variable(s).
This kinda makes sense as I do have two equations for my single state variable. However, those equations only apply at discrete points in time, right?
Do I need to make sure all "manipulations" of a particular variable happen only in a single when statement?
See Modelica Spec, section 8.5 Events and Synchronization:
https://www.modelica.org/documents/ModelicaSpec33Revision1.pdf
Just before section 8.6 there is an example that should help you.
Some code based on that is given below:
model WhenExample
parameter Integer multiplySample = 3;
Boolean fastSample, slowSample;
Integer ticks(start=0);
type State = enumeration(first, second, third);
State state(start = State.first);
equation
fastSample = sample(0,1);
algorithm
when fastSample then
ticks := if pre(ticks) < multiplySample then pre(ticks)+1 else 0;
slowSample := pre(ticks) == 0;
state := State.second;
end when;
when slowSample then
state := State.third;
end when;
end WhenExample;
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.
I'm trying to simulate Coulomb friction in Modelica. The basic concept is to check if relative velocity speed between to surfaces is less than a constant and the external force which tried to slid surfaces against each other is less than maximum static friction force (normalForce * staticFrictionCoefficient) then the friction force is equal to negative of the external shear force. otherwise, the friction force is equal to the kinetic friction force (normalForce * kineticFrictionCoefficient)in the opposite direction of the sliding direction.
I implemented this concept in Modelica as below:
function coulombFriction
input Real relVel;
input Real shearForce;
input Real normalForce;
input Real statfricco;
input Real kinfricco;
output Real fricForce;
algorithm
if relVel==0 and abs(shearForce)<statfricco*normalForce then
fricForce:=shearForce;
else
fricForce:=kinfricco*normalForce*sign(relVel);
end if;
end coulombFriction;
but when I call this function from a model as below:
model fricexample_1
extends coulombFriction;
//parameters
parameter Real kco=0.3;
parameter Real sco=0.4;
parameter Real nfo=1.0;
Real sfo;
Real ffo;
Real x;
Real v;
initial equation
x=0;
v=0;
equation
v=der(x);
der(v)=sfo-ffo;
sfo=time;
ffo=coulombFriction(relVel=v, shearForce=sfo, normalForce=nfo, statfricco=sco, kinfricco=kco);
end fricexample_1;
I see the error:
Translation Error
post-optimization module findZeroCrossings (simulation) failed.
If I remove the abs function from the defined function, it solves the compiling problem, but the model is wrong! I would appreciate if you could help me know:
how can I solve this problem?
how to model friction otherwise?
You can use noEvent on the conditions that might generate events in the function. Note that you don't need to extend the model with the function.
It should actually not work (to extend a model from a function), but it seems we don't check for it.
The model that compiles for me is below:
package Friction
function coulombFriction
input Real relVel;
input Real shearForce;
input Real normalForce;
input Real statfricco;
input Real kinfricco;
output Real fricForce;
algorithm
if noEvent(relVel==0) and noEvent(abs(shearForce)<statfricco*normalForce) then
fricForce:=shearForce;
else
fricForce:=kinfricco*normalForce*sign(relVel);
end if;
end coulombFriction;
model fricexample_1
//parameters
parameter Real kco=0.3;
parameter Real sco=0.4;
parameter Real nfo=1.0;
Real sfo;
Real ffo;
Real x;
Real v;
initial equation
x = 0;
v = 0;
equation
v = der(x);
der(v) = sfo-ffo;
sfo = time;
ffo = coulombFriction(relVel=v, shearForce=sfo, normalForce=nfo, statfricco=sco, kinfricco=kco);
end fricexample_1;
end Friction;
Your model does work with the 1.11 release. The issue is the extends coulombFriction; statement. Once you removed it, it should work fine even without the noEvent calls:
package Friction
function coulombFriction
input Real relVel;
input Real shearForce;
input Real normalForce;
input Real statfricco;
input Real kinfricco;
output Real fricForce;
algorithm
if relVel==0 and abs(shearForce)<statfricco*normalForce then
fricForce:=shearForce;
else
fricForce:=kinfricco*normalForce*sign(relVel);
end if;
end coulombFriction;
model fricexample_1
parameter Real kco=0.3;
parameter Real sco=0.4;
parameter Real nfo=1.0;
Real sfo;
Real ffo;
Real x;
Real v;
initial equation
x = 0;
v = 0;
equation
v = der(x);
der(v) = sfo-ffo;
sfo = time;
ffo = coulombFriction(relVel=v, shearForce=sfo, normalForce=nfo, statfricco=sco, kinfricco=kco);
end fricexample_1;
end Friction;
I'd recommend to reuse the friction state machine available in the Modelica Standard Library. An example, that works in OpenModelica and other tools, is given by https://github.com/dzimmer/ZimmersModelicaTutorial/blob/master/Tutorial2015/BaseComponents/Friction/IdealDryFriction.mo.
Actually, the model I have developed above for Columb friction is wrong. Thanks to this post I could find the correct version:
package friction1D
final constant Real eps=1.e-15 "Biggest number such that 1.0 + eps = 1.0";
function sgn
input Real inputVar;
output Real outputVar;
algorithm
if noEvent(inputVar < 0) then
outputVar := -1;
else
outputVar := 1;
end if;
end sgn;
function coulombFriction
input Real relVel;
input Real shearForce;
input Real normalForce;
input Real statfricco;
input Real kinfricco;
output Real fricForce;
algorithm
if noEvent(abs(relVel) < eps) and noEvent(abs(shearForce) < statfricco * normalForce) then
fricForce := shearForce;
else
fricForce := kinfricco * normalForce * sgn(relVel);
end if;
end coulombFriction;
model fricexample_1
//parameters
parameter Real kco = 0.3;
parameter Real sco = 0.4;
parameter Real nfo = 1.0;
parameter Real mass = 1.0;
Real sfo;
Real ffo;
Real x;
Real v;
initial equation
x = 0;
v = 0;
algorithm
sfo := 0.7 * sin(time);
ffo := coulombFriction(relVel = v, shearForce = sfo, normalForce = nfo, statfricco = sco, kinfricco = kco);
equation
v = der(x);
mass * der(v) = sfo - ffo;
annotation(
experiment(StartTime = 0, StopTime = 10, Tolerance = 1e-8, Interval = 0.02),
__OpenModelica_simulationFlags(lv = "LOG_STATS", outputFormat = "mat", s = "dassl"));
end fricexample_1;
end friction1D;
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.