How can i use a while loop in matlab? - matlab

I have a problem using a while loop. My main objective is to simulate a Fanno flow problem for a case where the length of the tube is longer than required. This means we have to change the Mach number in the middle. My code is the following.
clc
clear all
close all
P1=1;
T1=273;
Cf=0.005;
Dh=0.15;
G=1.4;
M1=3.0;
Lxstar=0;
M2=1;
Lx=0;
My=0;
Lystar=0;
tol=.001;
L = 6.0;
error=0;
fp = ((1-M1^2)/(G*M1^2))+((G+1)/(2*G))*log(((G+1)*M1^2)/(2*(1+(M1^2*(G-1)/(2)))))
Lstar=(fp*Dh)./(4*Cf)
while Lstar<L
Mx=(M1+M2)./2
fp1=((1-Mx^2)/(G*Mx^2))+((G+1)/(2*G))*log(((G+1)*Mx^2)/(2*(1+(Mx^2*(G-1)/(2)))))
Lxstar= (fp1*Dh)./(4*Cf)
Lx= Lstar-Lxstar
My=((sqrt((2+(G-1)*Mx.^2)/(2*G*Mx.^2-(G-1)))));
fp2=((1-My^2)/(G*My^2))+((G+1)/(2*G))*log(((G+1)*My^2)/(2*(1+(My^2*(G-1)/(2)))))
Lystar=(fp2*Dh)./(4*Cf)
error= Lx+Lystar-L
if error<=tol
break
else
Diff=Lx+Lystar
if Diff<L
Mx=Mx+.01
else
Mx=Mx-.01
end
end
end
When I run it goes smoothly - it does everything I want but once it changes the Mx it runs again with the Mx=M1+M2/2 instead of the corrected Mx = Mx+.01 or Mx= Mx-.01

This line: Mx=(M1+M2)./2 is executed on every loop iteration, even after you assign the new value to Mx. You need to move it out of the loop, like this:
Mx=(M1+M2)./2
while Lstar<L
%other code here...
end
Then when you assign the new value to Mx, it won't be immediately overwritten with the old value.

Related

Create an array that grows at a regular interval on Matlab

I have been thinking about how to create an array that grows at a regular interval of time (for instance every 5 seconds) on Matlab.
I figured out 2 ways, either using tic/ toc or timer function. Later this program will be complexified. I am not sure which way is the best but so far I am trying with using timer.
Here is what I have tried :
clc;
period=5;%period at which the file should be updated
freq=4;
l=freq*period;
time=[0];
a = timer('ExecutionMode','fixedRate','Period',period,'TimerFcn',{#time_append, time,l,freq},'TasksToExecute',3 );
start(a);
function [time]=time_append(obj,event,time,l,freq)
time_append=zeros(l,1);
last_time=time(end)
for i=1:1:l
time_append(i)=last_time+i/freq;
end
time=[time;time_append];
end
After compiling this code, I only get a time array of length 1 containing the value 0 wheras it should contain values from 0 to 3x5 =15 I think it is a stupid mistake but I can't see why. I have tried the debug mode and it seems that at the end of the line time=[time;time_append], the concatenation works but the time array is reinitialised when we go out of the function. Also I have read that callback function can't have output. Does someone would know how I could proceed? Using globals? Any other suggestion?
Thank you for reading
You can do this by using nested functions. Nested functions allow you to access "uplevel variables", and you can modify those. Here's one way to do it:
function [a, fcn] = buildTimer()
period=5;%period at which the file should be updated
freq=4;
l=freq*period;
time=0;
function time_append(~,~,l,freq)
time_append=zeros(l,1);
last_time=time(end);
for i=1:1:l
time_append(i)=last_time+i/freq;
end
time=[time;time_append];
end
function out = time_get()
out = time;
end
fcn = #time_get;
a = timer('ExecutionMode','fixedRate',...
'Period',period,...
'TimerFcn',{#time_append,l,freq},...
'TasksToExecute',3 );
start(a);
end
Note that the variable time is shared by time_append and time_get. The timer object invokes time_append, and updates time. You need to hand out the function handle time_get to retrieve the current value of time.
>> [a,fcn] = buildTimer; size(fcn()), pause(10); size(fcn())
ans =
21 1
ans =
61 1

Different behaviour of function in a for-loop or when unrolling of the loop is performed

I got an odd behaviour of my functions and since i'm not so used to matlab coding i guess is due to something really easy that i don't get.
I can't understand how this could print something different
fx(Punti(1,:),Punti(2,:))
fx(Punti(2,:),Punti(3,:))
fx(Punti(3,:),Punti(4,:))
fx(Punti(4,:),Punti(5,:))
from this
for i_unic=1:4
fx(Punti(i_unic,:),Punti(i_unic+1,:))
end
Consider fx as a generic function.
Is it possible that fx uses some variables that for some reason are erased at the end of each iteration?
EDIT
-->"Punti" is just matrix containing the points a SCARA robot should follow
-->fx is the function "Retta" and it's the following
function retta(PuntoA,PuntoB,Asse_A,q_ini,rot,contaerro,varargin)
global SCARA40
global inizio XX YY ZZ
global seg_Nsteps
npassi = seg_Nsteps;
ipuntofin = inizio + npassi;
for ipunto = inizio : ipuntofin
P4 = PuntoA + (ipunto-inizio)*(PuntoB-PuntoA)/npassi;
q = kineinversa(Asse_A,P4,q_ini,rot);
Mec = SCARA40.fkine(q);
Pec = Mec(:,4);
if (dot((P4-Pec),(P4-Pec),3)>0.0001)
fprintf(1,'\n P4 Desid. = [%9.1f %9.1f %9.1f %9.1f ] \n',P4);
fprintf(1,'\n P4 Attuato = [%9.1f %9.1f %9.1f %9.1f ] \n',Pec);
contaerro = contaerro + 1;
else
q_ini = q;
end
SCARA40.plot(q);
XX(ipunto) = Pec(1);
YY(ipunto) = Pec(2);
ZZ(ipunto) = Pec(3);
if(nargin>6)
color = varargin{1};
else
color = 'r';
end
plot3(XX,YY,ZZ,color,'LineWidth',1 );
drawnow;
hold on
end
end
the test function with the results
Punti = [ 10,10,0,1 ;10,-10,0,1 ;-10,-10,0,1 ; -10,10,0,1 ] ;
%inizio=1
%retta(Punti(1,:)',Punti(2,:)',Asse_A,q_ini,rot,contaerro)
%inizio=21
%retta(Punti(2,:)',Punti(3,:)',Asse_A,q_ini,rot,contaerro)
%inizio=41
%retta(Punti(3,:)',Punti(4,:)',Asse_A,q_ini,rot,contaerro)
%inizio=61
inizio=1
for i=1:length(Punti)-1
retta(Punti(i,:)',Punti(i+1,:)',Asse_A,q_ini,rot,contaerro)
inizio=inizio+20;
end
the two images have been generated restarting Matlab
Addressing the question in the most general sense (since there is no sample given for the function fx or the function/variable Punti) then the reason you are getting different results is likely that the state of your variables/workspace is different when you test one case versus the other. How could this happen? Here are some obvious ways...
Your functions (or possibly other functions they call) are making use of the random number generator, and the starting state of the RNG is different when you test the loop versus unrolled loop case.
Your functions are sharing global variables that aren't reset to some default value at the start of each test case. You mention in a comment that the functions use global variables, so this is likely your problem.
Your functions aren't really functions, but scripts. Scripts all share a common workspace (the base workspace), whereas a function (and specifically each call to a function) will have its own unique workspace. If fx is actually a script, each call may change any or all of the variables in the base workspace. Furthermore, any other scripts, or anything you type into the command line, can change things as well. The contents of the base workspace may therefore be different when you test the loop versus unrolled loop case.
If I were to hazard a guess, I'd say that if you were to exit and restart MATLAB before each test case (i.e. reset everything to the same default starting state) you would probably get the same exact result for the loop versus unrolled loop case.

Is there an quivalent to 'jump' or 'go to' in Matlab?

I have this code:
values_nodelay = no_of_values(2:2:end)
no_of_values_x1 = (find(u~=[u(2:end), u(end)+1]));
no_of_values_x1 = no_of_values_x1(2:2:end)
l = 1;
delay = 2;
values_delay = [];
while l<=length(values_nodelay)
values_delay_temp = values_nodelay(l)-delay;
if delay>values_delay_temp
end
values_delay = [values_delay, values_delay_temp];
l = l+1;
end
values_delay
I need a goto or jump function to the beginning of while, or an equivalent if anyone
knows an easier way, that if delay > values_delay_temp, it won't become part of the final vector values_delay. Instead, I want to skip it and continue again with the while loop.
Rather than using jumps like continue or break, you could just do this:
if delay<=values_delay_temp
values_delay=[values_delay, values_delay_temp];
end
In other words make the "default" behavior of the loop to do nothing, and then only increment your vector when you hit the right condition. It's much clearer and easier to debug.
Also instead of using vector concatenation like you have, I've found it's more efficient to do values_delay(end+1) = values_delay_temp; if you have to grow a vector in a loop.
The continue statement will stop the execution of a loop for the current iteration and continue with the next iteration, e.g.
while foo
# stuff that will execute for all iterations
if bar
continue
end
# stuff that won't execute if bar is false
end
Although, in your specific case, why don't you just issue
values_delay=[values_delay, values_delay_temp];
and increase the loop counter when
delay <= values_delay_temp
is true?

Conditional IF/ELSE Statement in Matlab

I was trying to make a simple statement with Matlab as follows:
if TF==1
disp('One'), break
else continue
end
... ... ...
... ... ...
But even if TF is not 1, when I run the command, it doesn't CONTINUE to the rest of the script!! Any help would be appreciated-- Thanks
The continue statement has a very different meaning. Within a loop, like a for or while loop, continue instructs to skip the current round and continue with the next iteration in the loop. So if you remove continue, you will see the behavior that you are expecting. Here is an example:
for k = 1 : 10
if k == 4
% skip the calculation in the case where k is 4
continue
end
area = k * k;
disp(area);
end
When the loop iterates at k == 4, the block calculating the area of the corresponding square is skipped. This particular example is not very practical.
However, imagine you have a list of ten file names, and you want to process each file in this loop "for k = 1 : 10". You will have to try and open each file, but then if you find out the file does not exist, an appropriate way to handle it would be to print a little warning and then continue to the next file.

How to make a loop which display the output for my program automatically

In my program , suppose I fix no. of users N=6 .
Threshold value of SIR SIRo=6; Output generated is SIRmean=10 (suppose).
I want to make a loop so that
if SIRmean < SIRo
disp N=6
else
decrease the counter till SIRmean> SIRo
and display the value of N for which this condition holds true.
end
You can use simple for loop with downcounter and break on condition:
N=6;
for k=N:-1:0
SIRmean = calc_SIR_mean(N);
if SIRmean < SIRo
disp(['N=' k])
break;
end
end
Function calc_SIR_mean should return mean value based on number of users (it is not clear from your question how you receive this value).