Is there a way to get the maximum value from a CombiTimeTable (tableOnFile==true) and use it as a parameter?
I want to be able to use the max value in an equation without the need to set the Max Value for each component. Thinking about how others have handled this I'm pretty sure it's not possible, but should be in my opinion.
The Time table Docs doesn't have any indication that what I'd like to do is possible, but maybe someone has an idea how to handle this without setting a parameter for the max value.
There is support for min/max of times, but for x-values I guess you would need to write something like:
block CombiTimeTableWithMax
import Modelica.Blocks.Tables.Internal;
extends Modelica.Blocks.Sources.CombiTimeTable;
// The min/max for time are t_minScaled etc
final parameter Real xMin[nout](each fixed=false),xMax[nout](each fixed=false);
function getMinMax
input Modelica.Blocks.Types.ExternalCombiTimeTable tableID;
input Integer nout;
input Real p_offset[nout];
output Real xMin[nout],xMax[nout];
protected
Real t;
Real x[nout];
algorithm
t:=Internal.getTimeTableTmin(tableID);
x:=p_offset+Internal.getTimeTableValue(tableID, 1:nout, t, t, t);
xMin:=x;
xMax:=x;
while t<Internal.getTimeTableTmax(tableID) loop
t:=Internal.getNextTimeEvent(tableID, t);
x:=p_offset+Internal.getTimeTableValue(tableID, 1:nout, t, t, t);
for i in 1:nout loop
if x[i]<xMin[i] then xMin[i]:=x[i]; end if;
if x[i]>xMax[i] then xMax[i]:=x[i]; end if;
end for;
end while;
end getMinMax;
initial equation
(xMin,xMax)=getMinMax(tableID, nout, p_offset);
annotation (uses(Modelica(version="4.0.0")));
end CombiTimeTableWithMax;
Related
I have this simple procedure in Maple that I want to plot.
test:=proc(n)
local i,t;
for i from 1 to n do
t:=1;
od;
return t;
end:
The procedure itself works fine.
> test(19)
1
When I want to plot I get the following Error:
> plot(test(x),x=1..10)
Error, (in test) final value in for loop must be numeric or character
Please help
Maple's usual evaluation model is that arguments passed to commands are evaluated up front, prior to the computation done within the body of the command's own procedure.
So if you pass test(x) to the plot command then Maple will evaluate that argument test(x) up front, with x being simply a symbolic name.
It's only later in the construction of the plot that the plot command would substitute actual numeric values for that x name.
So, the argument test(x) is evaluated up front. But let's see what happens when we try such an up front evaluation of test(x).
test:=proc(n)
local i,t;
for i from 1 to n do
t:=1;
od;
return t;
end:
test(x);
Error, (in test) final value in for loop
must be numeric or character
We can see that your test procedure is not set up to receive a non-numeric, symbolic name such as x for its own argument.
In other words, the problem lies in what you are passing to the plot command.
This kind of problem is sometimes called "premature evaluation". It's a common Maple usage mistake. There are a few ways to avoid the problem.
One way is to utilize the so-called "operator form" calling sequence of the plot command.
plot(test, 1..10);
Another way is to delay the evaluation of test(x). The following use of so-called unevalution quotes (aka single right ticks, ie. apostrophes) delays the evaluation of test(x). That prevents test(x) from being evaluated until the internal plotting routines substitute the symbolic name x with actual numeric values.
plot('test(x)', x=1..10);
Another technique is to rewrite test so that any call to it will return unevaluated unless its argument is numeric.
test:=proc(n)
local i,t;
if not type(n,numeric) then
return 'procname'(args);
end if;
for i from 1 to n do
t:=1;
od;
return t;
end:
# no longer produces an error
test(x);
test(x)
# the passed argument is numeric
test(19);
1
plot(test(x), x=1..10);
I won't bother showing the actual plots here, as your example produces just the plot of the constant 1 (one).
#acer already talked about the technical problem, but your case may actually have a mathematical problem. Your function has Natural numbers as its domain, i.e. the set of positive integers {1, 2, 3, 4, 5, ...} Not the set of real numbers! How do you interpret doing a for-loop for until a real number for example Pi or sqrt(2) to 5/2? Why am I talking about real numbers? Because in your plot line you used plot( text(x), x = 1..10 ). The x=1..10 in plot is standing for x over the real interval (1, 10), not the integer set {1, 2, ..., 10}! There are two ways to make it meaningful.
Did you mean a function with integer domain? Then your plot should be a set of points. In that case you want a points-plot, you can use plots:-pointplot or adding the option style=point in plot. See their help pages for more details. Here is the simplest edit to your plot-line (keeping the part defininf test the same as in your post).
plot( [ seq( [n, test(n)], n = 1..10 ) ], style = point );
And the plot result is the following.
In your function you want the for loop to be done until an integer in relation with a real number, such as its floor? This is what the for-loop in Maple be default does. See the following example.
t := 0:
for i from 1 by 1 to 5/2 do
t := t + 1:
end do;
As you can see Maple do two steps, one for i=1 and one for i=2, it is treated literally as for i from 1 by 1 to floor(5/2) do, and this default behavior is not for every real number, if you replace 5/2 by sqrt(2) or Pi, Maple instead raise an error message for you. But anyway the fix that #acer provided for your code, plots the function "x -> test(floor(x))" in your case when x comes from rational numbers (and float numbers ^_^). If you change your code instead of returning constant number, you will see it in your plot as well. For example let's try the following.
test := proc(n)
local i,t:
if not type(n, numeric) then
return 'procname'(args):
end if:
t := 0:
for i from 1 to n do
t := t + 1:
end do:
return(t):
end:
plot(test(x), x=1..10);
Here is the plot.
It is indeed "x -> test(floor(x))".
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;
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 would like to use a class function/method in my Modelica model as follows:
optimization Moo(objective=-x(finalTime), startTime = 0, finalTime = 12)
parameter Real e = 0.05;
Real x(start=2, fixed=true, min=0, max=100);
input Real v (min=0, max=1);
function omega
input Real t;
output Real y;
algorithm
y := e;
end omega;
equation
der(x) = v*omega(time);
constraint
v<=1;
end Moo;
I would like the variable e in the function omega to be a variable so that I can easily change its value at a later point in time when I am doing a parameter sweep. Unfortunately, the function omega does not seem to know about the variable e and the JModelica compiler returns the error:
Cannot find class or component declaration for e
I would naïvely expect that since omega and e belong to the same class omega would be able to see e.
Is there a way to achieve this?
Member functions are not supported in Modelica, so a function declared inside a model acts like a standalone function without having access to the surrounding model variables.
Member functions are not allowed due to functions need to be pure, i.e. they are not allowed to have any side effect. This is a fundamental assumption in Modelica that makes it possible for a tool to apply symbolic transformation and rearrange calculations.
You can have something like a member function, if you explicitly pass the needed variables as additional input to the function. See this example:
package MemberFunction
model A
Real x=1;
function get_x = MemberFunction.get(u=x);
end A;
function get
input Real u;
output Real y;
algorithm
y := u;
end get;
model Test
A a;
Real x;
equation
x = a.get_x();
end Test;
end MemberFunction;
I am having issues with a code of mine dealing with decay. The error "Subscript indices must either be real positive integers or logicals" continues to occur no matter how many times I attempt to fix the line of code: M=M(t)+h.*F
Here is the complete code so that it may be easier to solve the issue:
M=10000;
M=#(t) M*exp(-4.5*t);
F=-4.5*M(t);
h=.1;
t(1)=0;
tmax=20;
n=(tmax-t(1))/h;
i=1;
while h<=.5
while i<=n
t=t+h;
M=M(t)+h.*F;
data_out=[t,M];
dlmwrite('single_decay_euler_h.txt',data_out,'delimiter','\t','-append');
i=i+1;
end
h=h+.1;
end
Thanks for any help.
In the start, you're setting M = 5000;. In the following line, you're creating an anonymous function also called M:
M=#(t) M*exp(-4.5*t);
Now, your initial M = 5000 variable has been overwritten, and is substituted by the function:
M(t) = 5000 * exp(-4.5*t); %// Note that the first M is used to get 5000
Thereafter you do F = -4.5*M(t). I don't know what the value t is here, but you're giving F the value -4.5 * 5000 * exp(-4.5*t), for some value of t. You are not creating a function F.
In the first iteration of the loop, M=M(t)+h.*F; is interpreted as:
M = 5000 * exp(-4.5*0) + 0.1*F %// Where F has some value determined by previous
%// the function above and the previous value of t
%// -4.5*0 is because t = 0
M is now no longer a function, but a single scalar value. The next iteration t = 0.1. When you do: M=M(t)+h.*F; now, it interprets both the first and second M as a variable, not a function. t is therefore used as an index, instead of being an input parameter to the function M (since you have overwritten it).
When you are writing M(t), you are trying to access the 0.1'th element of the 1x1 matrix (scalar) M, which obviously isn't possible.
Additional notes:
The outer while loop has no purpose as it stands now, since i isn't reset after the inner loop. When you're finished with the first iteration of the outer loop, i is already >n, so it will never enter the inner loop again.
You shouldn't mix variable and function names (as you do with M. Use different names, always. Unless you have a very good reason not to.
data_out=[t,M]; is a growing vector inside a loop. This is considered very bad practice, ans is very slow. It's better to pre-allocate memory for the vector, for instance using data_out = zeros(k,1), and insert new values using indexes, data_out(ii) = M.
It's recommended not to use i and j as variable names in MATLAB as these also represent the imaginary unit sqrt(-1). This might cause some strange bugs if you're not paying attention to it.
You can almost certainly do what you're trying to do without loops. However, the function you have written is not functioning, and it's not explained all too well what you're trying to do, so it's hard to give advice as to how you can get what you want (but I'll give it a try). I'm skipping the dlmwrite-part, because I don't really understand what you want to output.
M = 5000;
t0 = 0;
tmax = 20;
h = 0.1; %// I prefer leading zeros in decimal numbers
t = t0: h: tmax;
data_out = M .* exp(-4.5 * t);
The problem is caused by M(t) in your code, because t is not an integer or logical (t=1,1.1,1.2,...)
You need to change your code to pass an integer as a subscript. Either multiply t by 10, or don't use the matrix M if you don't need it.