The code so far:
function [fr]=frictionFactorFn(rho,mu,e,D,L,Q,f0,tol,imax)
format long
CS=(pi*D^(2))/4;%Cross sectional area of pipe
v=Q/CS;%velocity
Re=(rho*v*L)/mu;
iter=1;i=1;fr(1)=f0;
while 1
fr(i+1)=(-1.74*log((1.254/(Re*sqrt(fr(i))))+((e/D)/3.708)))^-2;%substitution for root finding
iter=iter+1;
if abs(fr(i+1)-fr(i))<tol || iter>=imax
break;
end
i=i+1;
end
fprintf('\n The Reynolds number is %f\n',Re);
plot(0:iter-1,fr);
xlabel('Number of iteration'),ylabel('friction factor');
end
It gave me the right converged value of f=0.005408015, but I would like to plot the iteration
Possibly by storing the values of f upon each iteration in an array. In this example the array is called Store_f and is plotted after the while-loop is completed. The variable Index below is used to indicate which cell of array Store_f the value should be saved to.
function [f_vals] = frictionfactorfn()
Index = 1;
while (Condition)
%Calculation code%
Store_f(Index) = f;
Index = Index + 1;
end
disp(num2str(f))
plot(Store_f,'Marker','.');
xlabel('Iteration'); ylabel('Value');
end
Related
Below is a code, which works fine without function/function handles. However, I have to write a function so that I can use optimization function of "lsqcurvefit" in MATLAB and optimize parameters constant(1) and constant(2).
L=zeros(n,length(S)); % Height of elements
L(:,1)=Linitial; % Height of elements for day zero
for jj=1:length(S)
if jj==1
continue
end
for j=1:n % n is 101 (previously defined...)
L(j,jj) = #(constant, i_dt) L(j,jj-1) - (i_dt(j,jj).*constant(1).*((L(j,jj-1)./hs)-1)^constant(2)); %*****
end
end
height_pred = #(constant,i_dt) sum(L); %heigh_pred(1) is known and previously defined
options = optimoptions('lsqcurvefit','FinDiffType','central',...
'TolFun',1e-10);
constant = lsqcurvefit(height_pred,constant0,i_dt,height_meas,lb,ub,options);
When I run above code, I receive the error "Conversion to double from function_handle is not possible" for line with 5 stars (*****).
If I remove function handle and instead write a function at the end of my code like below:
L=zeros(n,length(S)); % Height of elements
L(:,1)=Linitial; % Height of elements for day zero
for jj=1:length(S)
for j=1:n % n is 101 (previously defined...)
L(j,jj) = Nelfun(j,jj);
end
end
height_pred = #(constant,i_dt) sum(L); %heigh_pred(1) is known and previously defined
options = optimoptions('lsqcurvefit','FinDiffType','central',...
'TolFun',1e-10);
constant = lsqcurvefit(height_pred,constant0,i_dt,height_meas,lb,ub,options);
function L = Nelfun(constant,i_dt)
for jj=1:145
if jj==1
L(:,1)=0.0187600000000000;
continue
end
for j=1:101
L(j,jj-1);
L(j,jj) = L(j,jj-1) - (i_dt(j,jj).*constant(1).*((L(j,jj-1)./hs)-1)^constant(2)); %*****
end
end
end
I receive the error
"Index exceeds matrix dimensions" for line with (*****).
Size of matrix i_dt is (101,145), L is (101,145), height_meas(1,145), and height_pred(1,145).
L(j,jj) for jj==1 is known but then should be calculated and optimized for L(:,2) to L(:,145).
***
Thanks to Praveen, "Index exceeds matrix dimensions" issue is resolved, but now I receive the error
"Error using snls (line 183)
Finite difference Jacobian at initial point contains Inf or NaN values. lsqcurvefit cannot continue."
for below code:
lb = [0.000000000001,0.05]; ub = [1,50]; constant0 = [1.06e-09,15.2];
height_pred = #(constant,i_dt) sum(Nelfun(constant,i_dt));
options = optimoptions('lsqcurvefit','FinDiffType','central',...
'TolFun',1e-10);
constant = lsqcurvefit(height_pred,constant0,i_dt,height_meas,lb,ub,options);
function L = Nelfun(constant,i_dt)
L=zeros(size(i_dt));
n=101; % number of nodes
ei=2.05613504572765;
e0=ei.*ones(n,1);
Hsolid=0.613847219422639;
hs = Hsolid./(n-1);
for JJ=1:size(i_dt,2)
if JJ==1
for j=1:n
Linitial0=hs.*(1+e0);
Linitial0(1)=0;
end
L(:,JJ) = Linitial0;
continue
end
for J=1:size(i_dt,1)
L(J,JJ) = L(J,JJ-1) - (i_dt(J,JJ).*constant(1).*((L(J,JJ-1)./hs)-1)^constant(2));
end
end
end
In the first case, you can't make an array of function handles. you can use cell arrays but I can't understand why you need it.
Let's work your second case.
%I don't know what is hs, I assume it a scalar
hs=myhs;
%call the Nelfun in your function handle
height_pred = #(constant,i_dt) Nelfun(constant,i_dt,hs);
options = optimoptions('lsqcurvefit','FinDiffType','central',...
'TolFun',1e-10);
% Constant0 should be 2 element array
constant0=[0,0];
constant = lsqcurvefit(height_pred,constant0,i_dt,height_meas,lb,ub,options);
function L = Nelfun(constant,i_dt,hs)% why hs is not passed
L=zeros(size(i_dt)); % Always initialize before filling it up
for jj=1:size(i_dt,2) %use adaptive indexing
if jj==1
L(:,jj)=0.0187600000000000;
continue
end
for j=1:size(i_dt,1) %use adaptive indexing
L(j,jj) = L(j,jj-1) - (i_dt(j,jj).*constant(1).*((L(j,jj-1)./hs)-1)^constant(2));
end
end
I have created this code to generate a 1 set of lottery numbers, but I am trying to make it so that the user can enter how many sets they want (input n), and it will print out as one long matrix of size nX6? I was messing around with a few options from online suggestions, but to no avail. I put the initial for i=1:1:n at the beginning, but I do not know how to store each run into a growing matrix. Right now it still generates just 1 set.
function lottery(n)
for i=1:1:n
xlow=1;
xhigh=69;
m=5;
i=1;
while (i<=m)
lottonum(i)=floor(xlow+rand*(xhigh-xlow+1));
flag=0;
for j=1:i-1
if (lottonum(i)==lottonum(j))
flag=1;
end
end
if flag==0
i=i+1;
end
end
ylow=1;
yhigh=26;
m=1;
lottonum1=floor(ylow+rand*(yhigh-ylow+1));
z = horzcat(lottonum, lottonum1);
end
disp('The lotto numbers picked are')
fprintf('%g ',z)
disp (' ')
The problem is that you are not storing or displaying the newly generated numbers, only the last set. To solve this, initialize z with NaNs or zeros, and later index z to store each set in a row of z, by using z(i,:) = lottonum.
However, you are using i as iterator in the while loop already, so you should use another variable, e.g. k.
You can also set z as an output of the function, so you can use this matrix in some other part of a program.
function z = lottery(n)
% init z
z = NaN(n,6);
for k = 1:n
xlow=1;
xhigh=69;
m=5;
i=1;
while (i<=m)
lottonum(i)=floor(xlow+rand*(xhigh-xlow+1));
flag=0;
for j=1:i-1
if (lottonum(i)==lottonum(j))
flag=1;
end
end
if flag==0
i=i+1;
end
end
ylow=1;
yhigh=26;
lottonum1 = floor(ylow+rand*(yhigh-ylow+1));
z(k,:) = horzcat(lottonum, lottonum1); % put the numbers in a row of z
end
disp('The lotto numbers picked are')
disp(z) % prettier display than fprintf in this case.
disp (' ')
end
The nice answer from rinkert corrected your basic mistakes (like trying to modify your loop iterator i from within the loop => does not work), and answered your question on how to store all your results.
This left you with a working code, however, I'd like to propose to you a different way to look at it.
The porposed architecture is to divide the tasks into separate functions:
One function draw_numbers which can draw N numbers randomly (and does only that)
One function draw_lottery which call the previous function as many times as it needs (your n), collect the results and display them.
draw_lottery
This architecture has the benefit to greatly simplify your main function. It can now be as simple as:
function Draws = draw_lottery(n)
% define your draw parameters
xmin = 1 ; % minimum number drawn
xmax = 69 ; % maximum number drawn
nballs = 5 ; % number of number to draw
% pre allocate results
Draws = zeros( n , nballs) ;
for iDraw=1:1:n
% draw "nballs" numbers
thisDraw = draw_numbers(xmin,xmax,nballs) ;
% add them to the result matrix
Draws(iDraw,:) = thisDraw ;
end
disp('The lotto numbers picked are:')
disp (Draws)
disp (' ')
end
draw_numbers
Instead of using a intricated set of if conditions and several iterators (i/m/k) to branch the program flow, I made the function recursive. It means the function may have to call itself a number of time until a condition is satisfied. In our case the condition is to have a set of nballs unique numbers.
The function:
(1) draws N integer numbers randomly, using randi.
(2) remove duplicate numbers (if any). Using unique.
(3) count how many unique numbers are left Nu
(4a) if Nu = N => exit function
(4b) if Nu < N => Call itself again, sending the existing Nu numbers and asking to draw an additional N-Nu numbers to add to the collection. Then back to step (2).
in code, it looks like that:
function draw = draw_numbers(xmin,xmax,nballs,drawn_set)
% check if we received a partial set
if nargin == 4
% if yes, adjust the number of balls to draw
n2draw = nballs - numel(drawn_set) ;
else
% if not, make a full draw
drawn_set = [] ;
n2draw = nballs ;
end
% draw "nballs" numbers between "xmin" and "xmax"
% and concatenate these new numbers with the partial set
d = [drawn_set , randi([xmin xmax],1,n2draw)] ;
% Remove duplicate
drawn_set = unique(d) ;
% check if we have some more balls to draw
if numel(drawn_set) < nballs
% draw some more balls
draw = draw_numbers(xmin,xmax,nballs,drawn_set) ;
else
% we're good to go, assign output and exit funtion
draw = drawn_set ;
end
end
You can have both functions into the same file if you want.
I encourage you to look at the documentation of a couple of Matlab built-in functions used:
randi
unique
I want to compute the number of operations of jacobi iteration in matlab
I do not know how to do it !!!
Can you help me ?
Thanks
Here is my code for newton method :
b=zeros(30,1);
b(6)=2;
alpha=1;
A=zeros(30,30);
A(1,1)=-(2+alpha);
A(1,2)=1;
for ii=2:29
A(ii,ii-1)=1
A(ii,ii)=-(2+alpha)
A(ii,ii+1)=1
end
A(30,29)=1;
A(30,30)=-(2+alpha);
D=diag(diag(A));
R=A-D;
x=zeros(30,1);
for ii=1:100
xk= inv(D)*(b-R*x);
if(norm(xk-x,1)<=10^-5)
break;
end
x=xk;
end
ii
You have counted it, actually.
In case of code
for ii=1:N
%% Code
end
the ii variable works like the counter.
Reading the code step-by-step you:
Define anonymous temporary array, say forII with elements 1 to N with default step of 1.
For each iteration the appropriate element of original forII is assigned to ii
%% Code is executed
New value of ii scalar is assigned.
This behaviour allows:
Use counter=1:N as true counter.
Loop easily over elements of any array, for example for foo='Hello World!'.
Use predefined indices, array elements, etc. for ii=A.
When the for loop is terminated by break or return prompt the elements in queue are not assigned and ii keeps the last assigned value.
You can try
kk=0;
for ii=1:N
kk=kk+1;
if ii==5
break
end
end
disp(['kk = ' num2str(kk) '; ii = ' num2str(ii)]);
kk=0;
for ii='Hello World!'
kk=kk+1;
if ii=='r'
break
end
end
disp(['kk = ' num2str(kk) '; ii = ' num2str(ii)]);
I am trying to plot some functions and display a legend. My code can be found below:
%% DATCOM spanloading method
tol = Input.tol;
iteration = 0;
difference =0;
AVL_step = 0.25;
Interp_step =0.1;
AVLruns = 3;
Angle = ((1:AVLruns)*AVL_step)+AOA;
while sum(difference < 0) <= fix(tol*Input.Surface.Nspan) && iteration < 100
iteration = iteration +1;
if iteration <= AVLruns
AOA = AOA + AVL_step;
[Yle_wing,Spanloading] = obj.AVLspanloading(Input,CLa,AOA); % Creates spanloading with AVL
Scalefunc = 1/(max(Yle_wing)-min(Yle_wing)); % Scale function
Ynorm= ((Yle_wing - min(Yle_wing)) .* Scalefunc)'; % Normalize semi-span from 0 to 1
if length(YClmax) ~= length(Ynorm) && iteration ==1
Clmax_dist= interp1(YClmax,Clmax_dist,Ynorm,'linear');
end
difference = (Clmax_dist - Spanloading); % Difference between resampled CL3d and Cl2d
cl_matrix(iteration,:) = Spanloading;
else
AOA = AOA + Interp_step;
for QQ = 1:Input.Surface.Nspan
CL3d = interp1(Angle,cl_matrix(:,QQ)',AOA,'linear','extrap');
Spanloading(:,QQ) = CL3d;
end
difference = (Clmax_dist - Spanloading);
end
figure(1)
pl = plot(Yle_wing,Clmax_dist,'r');
legendStrs = {'2D Clmax'};
set(pl,'linewidth',1.5);
hold on
if iteration <= AVLruns
plot(Yle_wing,Spanloading,'g--o')
legendStrs = [legendStrs, {'Spanloading by AVL'}];
else
plot(Yle_wing,Spanloading)
legendStrs = [legendStrs, {'Spanloading by extrapolation'}];
end
xlabel('2y/b')
ylabel('Local Cl')
title('DATCOM SPANLOADING METHOD')
legend('boxon')
legend(legendStrs,'Location','SouthWest');
end
if iteration >= 100
disp('Spanloading did not converge, while loop terminated by reaching maximum iteration count')
end
Here, I create a plot in the same figure using the hold on statement and with an if statement. Running my code will run both conditions of the if statement. Hence, multiple lines will be plotted in this Figure.
Therefore, I want to make a legend for all three plot commands. However, I don't seem to understand how to create the legend for a plot function within an if statement since the following makes my second plot green, and the rest of the plots red.
How would I go about?
Edit: I've incorporated my whole while loop
You can pass a cell array as an input to legend. Maintain a cell array of strings and add relevant strings to it right after your plot statements.
pl = plot(Yle_wing,Clmax_dist,'r');
legendStrs = {'2D Clmax'};
Then later in the if else block
if iteration <= AVLruns
plot(Yle_wing,Spanloading,'g--o')
legendStrs = [legendStrs, {'Spanloading by AVL'}];
set(pl,'linewidth',1.5);
else
plot(Yle_wing,Spanloading)
legendStrs = [legendStrs, {'Spanloading by extrapolation'}];
end
This will keep the number of legend strings equal to the number of lines you have on your plot. Then, at last
legend(legendStrs,'Location','SouthWest');
I am new to matlab and I have couple of questions about it. First one, "Your function should terminate the sequence when either the value of ... or..." I use || in the code but it does not work as expected while && gives me the correct answer. Second question, how could the code be to display only the final answer?
Problem: calculate X which is represented by the sequence below
X = 1 - 1/2^2 + 1/3^2 - 1/4^2 +....
Requirement: Your function should terminate the sequence when either the value of 1/k^2 is less than 0.0001 or k is equal to k_max.
input k
Initialize x = 0
for loop i from 1 to k
if 1/i^2<0.0001 && i >= 100
break
end
Calculate X = (-1)^(i+1)./i^2 + X
end
You can use the break function as follows, where END_CONDITION is the condition you want to end your loop in.
if END_CONDITION
disp(X);
break;
end
To display the final answer, you can use the disp function. Eg. if your variable you want to print is called A then you use the following code.
disp(A)
Collectively this is your code. Since k_max terminates at the end of the for loop, we don't have to add any conditions to break out of the loop.
X = 0;
for i = 1:k
if 1/i^2<0.0001 || i==100
break;
end
X = (-1)^(i+1)./i^2 + X;
end
disp(X);