I try to compile the following code with Dymola:
class abc
import Modelica.SIunits;
parameter SIunits.Time delta_t=0.5;
constant Real a[:]={4,2,6,-1,3,5,7,4,-3,-6};
Real x;
Integer j(start=1);
Integer k=size(a, 1);
algorithm
when {(sample(0, delta_t) and j < k),j == 1} then
x := a[j];
j := j + 1;
end when;
end abc;
and for time = 0 the variable j starts with 2. But it should start with j = 1.
Does anybody have an idea for this problem?
Keep in mind that sample(x,y) means that sample is true at x+i*y where i starts at zero. Which is to say that sample(0, ...) becomes true at time=0.
Since j starts at 1 and k is presumably more than 1, it doesn't seem unexpected to me that sample(0, delta_t) and j<k should become true at the start of the simulation.
I suspect what you want is:
class abc
import Modelica.SIunits;
parameter SIunits.Time delta_t=0.5;
constant Real a[:]={4,2,6,-1,3,5,7,4,-3,-6};
Real x;
Integer j(start=1);
Integer k=size(a, 1);
algorithm
when {(sample(delta_t, delta_t) and j < k),j == 1} then
x := a[pre(j)];
j := pre(j) + 1;
end when;
end abc;
I don't really see the point of the j==1 condition. It is true at the outset which means it doesn't "become" true then. And since j is never decremented, I don't see why it should ever return to the value 1 once it increments for the first time.
Note that I added a pre around the right-hand side values for j. If this were in an
equation section, I'm pretty sure the pre would be required. Since it is an algorithm section, it is mainly to document the intent of the code. It also makes the code robust to switching from equation to algorithm section.
Of course, there is an event at time = 0 triggered by the expression sample(0, delta_t) and j<k which becomes true.
But in older versions of Dymola there is an bug with the initialization of discrete variables. For instance even if you remove sample(0.0, delta_t) and j<k in dymola74, j will become 2 at time=0. The issue was that the pre values of when clauses, where not initialized correct. As far as I know this is corrected at least in the version FD1 2013.
Related
The following Matlab code is meant to find the machine value of epsilon.
e = 1;
while (1+e>1)
if e+1 <= 1
e = 2*e;
else e = e/2;
end
end
e = 2*e
While the value of epsilon is correctly approximated, modifying the code leads to unexpected results. For example, if the while loop condition is modified, as shown below, to e>0 the program either crashes or outputs 0 rather than an approximation for epsilon even though adding a constant doesn't change the inequality. Could someone explain why this is happening?
e = 1;
while (e>0)
if e+1 <= 1
e = 2*e;
else e = e/2;
end
end
e=2*e
The concept of “epsilon” is that there is a minimal value that must be added to 1 to obtain a different value. If e is smaller than epsilon, then 1+e==1. Floating-point numbers cannot represent values in between 1 and 1 + epsilon.
So replacing the condition in the while loop, 1+e>1, with e>0, though mathematically equivalent, breaks the concept we are trying to define: epsilon as the smallest value to add to 1 to get a value larger from 1. Note that you can represent values very close to 0, such as 10-300, but you cannot represent values that close to 1. Epsilon is about 10-16. This means that the two inequalities are not the same when working with floating-point numbers.
Note that the statement if e+1 <= 1 is only reached when 1+e>1, and so will always be false. You can simplify the code by removing this if statement and keeping only the code in the else clause:
e = 1;
while 1+e > 1
e = e/2;
end
e = 2*e
I'm trying to implement a DFT on my own because the FFT example in OpenModelica is not working for me and I can't figure out why.
But I'm already stuck sampling a sine function and assigning the sampled values to a buffer array.
This is why I tried to make it even simpler and just assign a counter variable "iTick" to the array which still doesn't work.
See the basic example.
Can anyone tell me why this is not working and how I can actually assign a value to the array when using the sample() function ??
block DFT
import Modelica.Constants.pi;
parameter Integer N = 360 "Total number of samples";
Integer iTick;
Real y_buf[N];
algorithm
when sample(0, 0.1) then
iTick :=iTick + 1;
if iTick >= 1 and iTick <= N then
y_buf[iTick] := iTick;
end if;
end when;
end DFT;
[358] 14:56:15 Symbolisch Warnung
The linear system:
1 : $PRE.y_buf[2] = y_buf[2]
2 : y_buf[2] = $PRE.y_buf[2]
[
-1.0 , 1.0 ;
1.0 , -1.0
]
*
[
y_buf[2] ;
$PRE.y_buf[2]
]
=
[
0.0 ;
0.0
]
might be structurally or numerically singular for variable $PRE.y_buf[2] since U(2,2) = 0.0. It might be hard to solve. Compilation continues anyway.
[359] 14:56:15 Symbolisch Warnung
The linear system:
1 : $PRE.y_buf[1] = y_buf[1]
2 : y_buf[1] = $PRE.y_buf[1]
[
-1.0 , 1.0 ;
1.0 , -1.0
]
*
[
y_buf[1] ;
$PRE.y_buf[1]
]
=
[
0.0 ;
0.0
]
might be structurally or numerically singular for variable $PRE.y_buf[1] since U(2,2) = 0.0. It might be hard to solve. Compilation continues anyway.
[360] 14:56:15 Übersetzung Warnung
Assuming fixed start value for the following 2 variables:
y_buf[360]:DISCRETE(fixed = false ) type: Real [360]
iTick:DISCRETE(fixed = false ) type: Integer
After a long search and try and error I found out that the magic word "discrete" solves my problem! I can't yet explain why, but see below the working example:
model Test
import Modelica.Constants.pi;
parameter Integer N = 360 "Total number of samples";
Integer iTick(start=0, fixed=true);
discrete Real y_buf[N](start=fill(0,N), fixed=fill(true, N));
algorithm
when sample(0, 0.1) then
iTick :=iTick + 1;
if iTick >= 1 and iTick <= N then
y_buf[iTick] := iTick;
end if;
end when;
end Test;
Hopefully this is a help to someone!
Your "Symbolisch Warnung" disappears once you initialize iTick and y_buf. However, the code still does not work. OpenModelica simulates it, but the items of y_buf are never updated.
This issue might be related to this question where the delay operator is not working in algorithm sections. Therefore, I suggest a similar workaround: Try to avoid the algorithm section. With an equation section and proper initialization, your minimal example could look as follows:
block DFT
import Modelica.Constants.pi;
parameter Integer N = 360 "Total number of samples";
Integer iTick(start=0, fixed=true);
Real y_buf[N](start=fill(0, N), fixed=fill(true, N));
equation
when sample(0, 0.1) then
iTick = pre(iTick) + 1;
end when;
for i in 1:N loop
when iTick >= i then
y_buf[i] = iTick;
end when;
end for;
end DFT;
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 am trying to write a MATLAB function that accepts non-integer, n, and then returns the factorial of it, n!. I am supposed to use a for loop. I tried with
"for n >= 0"
but this did not work. Is there a way how I can fix this?
I wrote this code over here but this doesn't give me the correct answer..
function fact = fac(n);
for fact = n
if n >=0
factorial(n)
disp(n)
elseif n < 0
disp('Cannot take negative integers')
break
end
end
Any kind of help will be highly appreciated.
You need to read the docs and I would highly recommend doing a basic tutorial. The docs state
for index = values
statements
end
So your first idea of for n >= 0 is completely wrong because a for doesn't allow for the >. That would be the way you would write a while loop.
Your next idea of for fact = n does fit the pattern of for index = values, however, your values is a single number, n, and so this loop will only have one single iteration which is obviously not what you want.
If you wanted to loop from 1 to n you need to create a vector, (i.e. the values from the docs) that contains all the numbers from 1 to n. In MATLAB you can do this easily like this: values = 1:n. Now you can call for fact = values and you will iterate all the way from 1 to n. However, it is very strange practice to use this intermediary variable values, I was just using it to illustrate what the docs are talking about. The correct standard syntax is
for fact = 1:n
Now, for a factorial (although technically you'll get the same thing), it is clearer to actually loop from n down to 1. So we can do that by declaring a step size of -1:
for fact = n:-1:1
So now we can find the factorial like so:
function output = fac(n)
output = n;
for iter = n-1:-1:2 %// note there is really no need to go to 1 since multiplying by 1 doesn't change the value. Also start at n-1 since we initialized output to be n already
output = output*iter;
end
end
Calling the builtin factorial function inside your own function really defeats the purpose of this exercise. Lastly I see that you have added a little error check to make sure you don't get negative numbers, that is good however the check should not be inside the loop!
function output = fac(n)
if n < 0
error('Input n must be greater than zero'); %// I use error rather than disp here as it gives clearer feedback to the user
else if n == 0
output = 1; %// by definition
else
output = n;
for iter = n-1:-1:2
output = output*iter;
end
end
end
I don't get the point, what you are trying to do with "for". What I think, what you want to do is:
function fact = fac(n);
if n >= 0
n = floor(n);
fact = factorial(n);
disp(fact)
elseif n < 0
disp('Cannot take negative integers')
return
end
end
Depending on your preferences you can replace floor(round towards minus infinity) by round(round towards nearest integer) or ceil(round towards plus infinity). Any round operation is necessary to ensure n is an integer.
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.