testing value of iteration in matlab for loop fails? - matlab

I'm trying to test the value of an iteration variable in a for loop and I'm not getting what I expect so I'm assuming that I'm misunderstanding something about the way matlab works and/or I'm doing something horribly wrong....
Can someone explain why the if statement in this code doesn't test true when x hits 0.2?:
start = -1;
stop = 1;
interval = 0.01;
for x = start:interval:stop
if x == 0.20
disp('it worked')
end
end
But this code does test true:
start = 0;
stop = 1;
interval = 0.01;
for x = start:interval:stop
if x == 0.20
disp('it worked')
end
end
I tried a bunch of different starting values and they seem to be random as to whether they work or not....Why should changing the starting value change the output?
I also see a similar inconsistency if I change the tested value (ie. 0.2 to 0.8 or something else)
What am I missing?

You are testing a floating point number with ==. Note that -1+120*.01==0.2 is false since they are not equal in the floating point representation. 0.01*20==0.2 happens to be true. Instead, use a tolerance e.g. if abs(x-0.20)<1e-10.

Related

issue generating triangular wave function in 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.

Stopping criteria matlab iteration

I want to add an While-loop to my matlab-code so that it will stop when the iteration is good enough. With some kind of tolerance, eg. 1e-6.
This is my code now. So i need to add some kind of stopping criteria, i have tried several times now but it won't work... I appreciate all of ur help!
x(1)=1;
iterations = 0;
tolerance = 1e-6;
% Here should the while be....
for i=1:N
x(i+1)=x(i);
for j=1:N
x(i+1)=F(x(i),x(i+1));
end
end
iter= iter + 1;
Well, somehow you need to compute the 'error' you are doing in each iteration. In your case it would be something like this:
iter = 0;
tolerance = 1e-6;
error=1;
x=F(x);
while(error>tolerance)
x2=x;
x=F(x);
error = x-x2;
iter= iter + 1;
end
Note how at the beginning the error is set to 1 so we make sure it goes inside the loop. We also compute the first instance of x outside the loop. F(x) will be your function to evaluate, change it for whatever you need.
Inside the loop assign the old value of x to x2, then compute the new x and finally compute the error. Here I compute the error as x-x2 but you might need to compute this error in another way.
The loop will exit whenever the error is lower than the tolerance.

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.

why am I getting imaginary numbers instead of a simple answer

this is just part of the code that matters and needs to be fixed. I don't know what i'm doing wrong here. all the variables are simple numbers, it's true that one is needed for that other, but there shouldn't be anything wrong with that. the answer for which I'm getting imaginary numbers is supposed to be part of a loop, so it's important I get it right. please ignore the variables that are not needed, as i just wrote a part of the code
the answer i get is:
KrInitialFirstPart = 0.000000000000000e+00 - 1.466747615972368e+05i
clear all;
clc;
% the initial position components
rInitial= 10; %kpc
zInitial= 0; %kpc
% the initial velocity components
vrInitial= 0; %km/s
vzInitial= 150; %tangential velocity component
vtInitial= 150; %not used
% the height
h= rInitial*vzInitial; %angulan momentum constant
tInitial=0;
Dt=1e-3;
e=0.99;
pc=11613.5;
KrInitialFirstPart= -4*pi*pc*sqrt( 1-(e^2) / (e^3) )*rInitial
format long
Here
sqrt( 1-(e^2) / (e^3) )
you have here
e=0.99;
so e < 1 and so e^3 is less than e^2.
Therefore
(e^2)/(e^3) > 1.
The division operation binds tighter than (i.e is evaluated ahead of) the subtraction so you are taking a square root of a negative number. Hence the imaginary component in your result.
Perhaps you require
sqrt( (1-(e^2)) / (e^3) )
which is guaranteed to yield a real number result since
1 - e^2 > 0
for your specified e

Recursive Binomial Tree Code, can't do more than 5 steps... why?

function [y]=AmericanPutClassic (St,t)
% S0 = 100;
K = 100;
r = 0.05;
sigma = 0.3;
T = 2;
nsteps = 5;
% St
dt = T / nsteps;
u=exp(sigma*sqrt(dt));
d=1/u;
Pu=(exp(r*dt)-d)/(u-d);
Pd=1-Pu;
if t==T
y=max(K-St,0);
return
elseif t<T
upPrice=AmericanPutClassic(St*u,t+dt);
downPrice=AmericanPutClassic(St*d,t+dt);
PrevPrice=(Pu*upPrice+Pd*downPrice)*exp(-r*dt);
if max(K-St,0) > PrevPrice
y=max(K-St,0);
else
y=PrevPrice;
end
return
end
end
I think my code does the job, but when I make 'nsteps' higher than 5, it crushes... I keep getting different errors... now it just says there is problem with my code when its higher than 5... before it would say:
"??? Maximum recursion limit of 500 reached. Use set(0,'RecursionLimit',N)
to change the limit. Be aware that exceeding your available stack space can
crash MATLAB and/or your computer."
Can anybody spot the problem?
I start by calling AmericanPutClassic(100,0)...
I don't know what you're trying to do but this problem has been described so many time on SO it's not funny anymore.
Let's paint a picture:
you start off with
dt = T / nsteps;
which is my first red flag.
then you do:
if t==T
where t = t + dt
Why is that wrong? Because of this wonderful thing called quantization. In other words there will be a time when because of super small micro difference, the result will not be correct. The bigger nsteps is, the worse this will be.
And then to add insult to injury, you put this line in
elseif t<T ... end
which means your code will skip everything, and you'll return nothing, causing your code to crash.
How does one solve this? If you can move integers around instead of floating values, you'll be in a better position. So instead of dt, you can have currentStep, such that:
function [y]=AmericanPutClassic (St, currentStep)
if nargin < 2
currentStep = 0;
end
...
if currentStep>=nsteps % if t==T
...
else
...
upPrice=AmericanPutClassic(St*u,currentStep+1);
...
end