Setting Stop Conditions for Iteration Loop in Matlab - matlab

I am trying to solve some equations using a while loop. I have a known and fixed output. Workflow is as follows:
P = 100; %Desired output
x = 1; %Initial guess
while abs(something) > 1e-6
x1 = (25 * x)/2
x2 = 10x - x1
x3 = 20x - (x - x1 - x2)*2
x4 = (x - x1 - x2 -x3)*12
x5 = (x - x1 - x2 -x3) * 10 + x4
P1 = 2005x3
P2 = 1500x5
Pnew = P1 + P2
end
I was hoping to calculate x1, x2, ..., x5 and stop looping when the condition P = Pnew is reached. Due to my modest knowledge of MATLAB any help would be appreciated.
Many thanks in advance.
APPENDIX: Perhaps i didn't explained well. My goal was to stop looping when the condition P = Pnew is achieved. I have a known value P and initial value of x. Pnew should be generated through a given series of equations. When the condition is met x, x1, x2, ..., x5 will have their values. So x is not only the initial value for calculating other unknowns (x1, x2, ..., x5). I tried to modify it but got NaN Pnew, P1, error and inf for P2, x, ...
P = 100; %Desired output
x = 1; %Initial guess
Pnew = P + 1
while abs(P - Pnew) > 1e-6
x1 = (25 * x)/2;
x2 = 10*x - x1;
x3 = 20*x - (x - x1 - x2)*2;
x4 = (x - x1 - x2 -x3)*12;
x5 = (x - x1 - x2 -x3) * 10 + x4
P1 = 2005 * x3;
P2 = 150 * x5;
Pnew = P1 - P2;
error = abs(P - Pnew);
x_new = x - .001 * error;
x = x_new;
end

Your code will error out if you don't use * to multiply. I have fixed the code below for you. The something you are looking for is P - Pnew. This is because you are trying to find the difference and making sure it is over 1e-6 to continue the loop.
Since you need Pnew, you should also do an initial calculation for it. You should note that your calculation doesn't actually make Pnew converge to P.
P = 100; %Desired output
x = 1; %Initial guess
x1 = ( 25 * x ) / 2
x2 = 10 * x - x1
x3 = 20 * x - ( x - x1 - x2 ) * 2
x4 = ( x - x1 - x2 -x3 ) * 12
x5 = ( x - x1 - x2 -x3 ) * 10 + x4
P1 = 2005 * x3
P2 = 1500 * x5
Pnew = P1 + P2
while abs( P - Pnew ) > 1e-6
x1 = ( 25 * x ) / 2
x2 = 10 * x - x1
x3 = 20 * x - ( x - x1 - x2 ) * 2
x4 = ( x - x1 - x2 -x3 ) * 12
x5 = ( x - x1 - x2 -x3 ) * 10 + x4
P1 = 2005 * x3
P2 = 1500 * x5
Pnew = P1 + P2
end
You should probably also put ; to terminate the line to suppress the output of the calculation.
A do-while loop here would work, but Matlab doesn't have one. You can use encapsulation to hide the code duplication or use a for loop as follows as well.
P = 100; %Desired output
x = 1; %Initial guess
for i = 1:Inf
x1 = ( 25 * x ) / 2
x2 = 10 * x - x1
x3 = 20 * x - ( x - x1 - x2 ) * 2
x4 = ( x - x1 - x2 -x3 ) * 12
x5 = ( x - x1 - x2 -x3 ) * 10 + x4
P1 = 2005 * x3
P2 = 1500 * x5
Pnew = P1 + P2
if abs( P - Pnew ) < 1e-6
break;
end
end
To set a predefined iteration termination in case you have an infinite loop, you can replace i = 1:Inf with i = 1:iterMax where iterMax is the number of max iterations.

Usually in numeric calculations one does not test for equality as the computers cannot distinguish all real numbers. Your condition is actually satisfying for something == P - Pnew
In code it would look like this
P = 100; % Desired output
x = 1; % Initial guess
Pnew = P + 1; % Something far off, just to get through the first check
MAX_ITERATION_COUNT = 10000; % a reasonable upper bound to your loop
loopCount = 0;
while abs(P - Pnew) > 1e-6 && loopCount < MAX_ITERATION_COUNT
loopCount = loopCount + 1;
x1 = (25 * x) / 2;
x2 = 10 * x - x1;
x3 = 20 * x - (x - x1 - x2) * 2;
x4 = (x - x1 - x2 - x3) * 12;
x5 = (x - x1 - x2 - x3) * 10 + x4;
P1 = 2005 * x3;
P2 = 1500 * x5;
Pnew = P1 + P2;
end
This should work for your problem.
EDIT: I added a loop counter in case you're loop does not finish regularly.

Related

Optimisation using Golden Search Method with Matlab

% Power output
power_output = MF_t.*difference.*e;
% POWER OUTPUT OPTIMIZATION USING - GOLDEN SEARCH METHOD
x_lower = 0.2;
x_upper = 1.4;
h = (x_upper - x_lower);
r = (sqrt(5) - 1)*0.5;
x2 = x_lower + (1+r)*h;
x3 = x_upper - (1+r)*h;
tol = 0.05;
count = 1;
while h>-tol
f2 = -power_output(x2)
f3 = -power_output(x3)
if f3<f2
x_lower = x2;
x_upper = x_upper;
h = (x_upper - x_lower);
x2 = x3;
x3 = x_upper - (1-r)*h;
elseif f2<f3
x_lower = x_lower;
x_upper = x3;
h = (x_upper - x_lower);
x3 = x2;
x2 = x_lower + (1-r)*h;
else
x_lower = x2;
x_upper = x3;
h = (x_upper - x_lower);
x2 = x_lower + (1+r)*h;
x3 = x_upper - (1+r)*h;
end
interval = x_upper - x_lower;
count = count + 1
if count > 100
break
end
end
answer = (x_upper + x_lower)/2
value = fanswer
Im trying to run this code, it's telling me that there is an error as my arrays f2 and f3 as "Array indices must be positive integers or logical values". I'm wondering would anyone know if taking the absolute values of my arrays will make my optimisation incorrect
The error message is quite informative in this case. You are trying to access the x2th element of f2. A quick calculation shows that on the first iteration x2 = 2.14. It is not possible to take the 2.14th element of f2 because this is is not an integer, and taking the absolute value will not help.
x2 is not an index, it is a value. On each iteration, the Golden Ratio search requires you to actually evaluate power_output with whatever variable set to x2. So, it looks like you need to do this calculation power_output = MF_t.*difference.*e with x=x2.

How to bound sum of 3 variables in matlab

I want summation of 3 variables to always equal to a number, in this case 1, but I don't know how to make it happen. For example in the following problem I am trying to find maximum value of "resourceOut/maximumTime" which is a function of x1, x2, x3 but while finding the maximum I want x1, x2, x3 to be equal to 1. (xi is the inital guess value for x1, x2 and R can be any positive number.
function Resource(xi,R)
x = fminsearch(#relations, xi);
x(1)
x(2)
function goldenRatio = relations(xi)
x1 = xi(1);
x3 = xi(2);
x2 = 1 - x1 - x3;
x3 = 1 - x1 - x2;
x1 = 1 - x2 - x3;
R1 = R * x1 * 0.1;
R2 = R * x2 * 0.25;
R3 = R * x3 * 0.50;
T1 = ((((R1)^2)*100)^0.45+1800);
T2 = ((((R2)^2)*100)^0.45+1800);
T3 = ((((R3)^2)*100)^0.45+1800);
elapsedTimes =[T1 T2 T3];
resourceOut = R1 + R2 + R3;
maximumTime = max(elapsedTimes);
goldenRatio = -resourceOut/maximumTime;
end
end

The Fastest Method of Solving System of Non-linear Equations in MATLAB

Assume we have three equations:
eq1 = x1 + (x1 - x2) * t - X == 0;
eq2 = z1 + (z1 - z2) * t - Z == 0;
eq3 = ((X-x1)/a)^2 + ((Z-z1)/b)^2 - 1 == 0;
while six of known variables are:
a = 42 ;
b = 12 ;
x1 = 316190;
z1 = 234070;
x2 = 316190;
z2 = 234070;
So we are looking for three unknown variables that are:
X , Z and t
I wrote two method to solve it. But, since I need to run these code for 5.7 million data, it become really slow.
Method one (using "solve"):
tic
S = solve( eq1 , eq2 , eq3 , X , Z , t ,...
'ReturnConditions', true, 'Real', true);
toc
X = double(S.X(1))
Z = double(S.Z(1))
t = double(S.t(1))
results of method one:
X = 316190;
Z = 234060;
t = -2.9280;
Elapsed time is 0.770429 seconds.
Method two (using "fsolve"):
coeffs = [a,b,x1,x2,z1,z2]; % Known parameters
x0 = [ x2 ; z2 ; 1 ].'; % Initial values for iterations
f_d = #(x0) myfunc(x0,coeffs); % f_d considers x0 as variables
options = optimoptions('fsolve','Display','none');
tic
M = fsolve(f_d,x0,options);
toc
results of method two:
X = 316190; % X = M(1)
Z = 234060; % Z = M(2)
t = -2.9280; % t = M(3)
Elapsed time is 0.014 seconds.
Although, the second method is faster, but it still needs to be improved. Please let me know if you have a better solution for that. Thanks
* extra information:
if you are interested to know what those 3 equations are, the first two are equations of a line in 2D and the third equation is an ellipse equation. I need to find the intersection of the line with the ellipse. Obviously, we have two points as result. But, let's forget about the second answer for simplicity.
My suggestion it's to use the second approce,which it's the recommended by matlab for nonlinear equation system.
Declare a M-function
function Y=mysistem(X)
%X(1) = X
%X(2) = t
%X(3) = Z
a = 42 ;
b = 12 ;
x1 = 316190;
z1 = 234070;
x2 = 316190;
z2 = 234070;
Y(1,1) = x1 + (x1 - x2) * X(2) - X(1);
Y(2,1) = z1 + (z1 - z2) * X(2) - X(3);
Y(3,1) = ((X-x1)/a)^2 + ((Z-z1)/b)^2 - 1;
end
Then for solving use
x0 = [ x2 , z2 , 1 ];
M = fsolve(#mysistem,x0,options);
If you may want to reduce the default precision by changing StepTolerance (default 1e-6).
Also for more increare you may want to use the jacobian matrix for greater efficencies.
For more reference take a look in official documentation:
fsolve Nonlinear Equations with Analytic Jacobian
Basically giving the solver the Jacobian matrix of the system(and special options) you can increase method efficency.

Matlab error in ode45 or fourth-order Runge-Kutta method to solve a system of coupled ODEs

I am a beginner at Matlab programming and with the Runge-Kutta method as well.
I'm trying to solve a system of coupled ODEs using a 4th-order Runge-Kutta method for my project work.
here is my problem...
G = 1.4;
g = 1.4;
k = 0;
z = 0;
b = 0.166667;
syms n;
x2 = symfun(sym('x2(n)'),[n]);
x1 = symfun(sym('x1(n)'),[n]);
x3 = symfun(sym('x3(n)'),[n]);
x4 = symfun(sym('x4(n)'),[n]);
x5 = symfun(sym('x5(n)'),[n]);
k1 = [x2 * x1 *n *(1 - z * x2)*(x1 - n) - 2 * x3 * n *(1 - z * x2) - x4^2 * x2 *(1 - z * x2)- G *x3 *x2 ]./ [( G * x3 - (x1 - n)^2 * x2 *(1 - z * x2)) * n];
k2 = [x2 * (1 - z * x2)*(x1 * x2 * ( x1 - 2 *n)*( x1 - n) + 2* x3 * n + x4^2 * x2 ) ]./ [( G * x3 - (x1 - n)^2 * x2 *(1 - z * x2)) * n * (x1 - n)];
k3 = [x3 * x2 * (2 * n * x1 - n)^2 * ( 1 - z * x2) + G * x1 * (x1 - 2 *n)* (x1 - n) + x4^2 * G]./ [( G * x3 - (x1 - n)^2 * x2 *(1 - z * x2)) * n * (x1 - n)];
k4 = [x4 * ( x1 + n)] ./ [n * (x1- n)];
k5 = - [x5] ./ [n * (x1- n)];
f = #(n,x) [k1; k2; k3; k4; k5];
[n,xa] = ode45(f,[0 1],[1-b 1/b 1-b 0.01 0.02]);
errors are
Error using odearguments (line 93)
#(N,X)[K1;K2;K3;K4;K5] returns a vector of length 1, but the length
of initial conditions vector is 5. The vector returned by
#(N,X)[K1;K2;K3;K4;K5] and the initial conditions vector must have
the same number of elements.
Error in ode45 (line 114)
[neq, tspan, ntspan, next, t0, tfinal, tdir, y0, f0, odeArgs,
odeFcn, ...
Please guide me how can I solve the above problem with fourth-order Runge-Kutta method...
The error stems from using symbolic functions (mixed with a function handle) with a numeric solver.
You need to create numeric functions for ode45 to function properly (I also replaced all of the [ and ] with ( and ) for grouping):
G = 1.4;
g = 1.4;
k = 0;
z = 0;
b = 0.166667;
k1 = #(n,x) (x(2) * x(1)*n *(1 - z * x(2))*(x(1) - n) - 2 * x(3) * n *(1 - z * x(2)) - x(4)^2 * x(2) *(1 - z * x(2))- G *x(3) *x(2)) ./ (( G * x(3) - (x(1) - n)^2 * x(2) *(1 - z * x(2))) * n);
k2 = #(n,x) (x(2) * (1 - z * x(2))*(x(1) * x(2) * ( x(1) - 2 *n)*( x(1) - n) + 2* x(3) * n + x(4)^2 * x(2) )) ./ (( G * x(3) - (x(1) - n)^2 * x(2) *(1 - z * x(2))) * n * (x(1) - n));
k3 = #(n,x) (x(3) * x(2) * (2 * n * x(1) - n)^2 * ( 1 - z * x(2)) + G * x(1) * (x(1) - 2 *n)* (x(1) - n) + x(4)^2 * G)./ (( G * x(3) - (x(1) - n)^2 * x(2) *(1 - z * x(2))) * n * (x(1) - n));
k4 = #(n,x) (x(4) * (x(1) + n)) ./ (n * (x(1)- n));
k5 = #(n,x) - x(5) ./ (n * (x(1)- n));
f = #(n,x) [k1(n,x); k2(n,x); k3(n,x); k4(n,x); k5(n,x)];
[n,xa] = ode45(f,[0 1],[1-b 1/b 1-b 0.01 0.02]);
This runs for my install of Matlab.
However, the output is all NaNs since the function produce Infs; I may have introduced errors by replacing the brackets, but I don't know what the actual equations are so I'm going to leave that to you. :)
In general, you consult first the documentation. If not available, use the search engine of you choice, for instance https://www.google.de/search?q=matlab+ode45+example to find as first result https://de.mathworks.com/help/matlab/ref/ode45.html
There you find a multidimensional example
function dy = rigid(t,y)
dy = zeros(3,1); % a column vector
dy(1) = y(2) * y(3);
dy(2) = -y(1) * y(3);
dy(3) = -0.51 * y(1) * y(2);
end
options = odeset('RelTol',1e-4,'AbsTol',[1e-4 1e-4 1e-5]);
[T,Y] = ode45(#rigid,[0 12],[0 1 1],options);
plot(T,Y(:,1),'-',T,Y(:,2),'-.',T,Y(:,3),'.')
that could be used as a blueprint. In the related page https://de.mathworks.com/help/matlab/math/ordinary-differential-equations.html they use a different syntax closer to yours for the van der Pol Equation in the first example
function dydt = vdp1(t,y)
dydt = [y(2); (1-y(1)^2)*y(2)-y(1)];
end
[t,y] = ode45(#vdp1,[0 20],[2; 0]);
plot(t,y(:,1),'-',t,y(:,2),'--')
title('Solution of van der Pol Equation, \mu = 1');
xlabel('time t');
ylabel('solution y');
legend('y_1','y_2')
Following these examples, rewrite your code as
G = 1.4;
g = 1.4;
k = 0;
z = 0;
b = 0.166667;
function dotx = dxdn(n,x)
t1 = n*(x1-n)
t2 = x(2)*(1 - z * x(2))
den123 = ( G * x(3) - (x(1) - n)^2 * t2)
k1 = ( x(1)*t1*t2 - 2 * x(3) * n *(1 - z * x(2)) - x(4)^2 * t2- G *x(3) *x(2) ) / (den123*n);
k2 = ( t2*(x(1) * x(2) * ( x(1) - 2 *n)*( x(1) - n) + 2* x(3) * n + x(4)^2 * x(2) ) ) / (den123 * t1);
k3 = ( x(3) * (2 * n * x(1) - n)^2 * t2 + G * x(1) * (x(1) - 2 *n)* (x(1) - n) + x(4)^2 * G ) / (den123*t1);
k4 = ( x(4) * ( x(1) + n) ) / t1;
k5 = - x(5) / t1;
dotx = [k1; k2; k3; k4; k5];
end
[n,xa] = ode45(#dxdn,[0.001 1],[1-b; 1/b; 1-b; 0.01; 0.02]);
Because of the division by zero at n=0 you can not start the iteration in that singularity. In the code above, this is mitigated by starting with some (very) small positive n, you can also try starting with n=1e-8 or smaller. The slope will be very large in all components, so the integration may be slow, and the result might be not overly exact close to zero. For the correct handling of singular ODE ask in the math.stackexchange forum.

Interpolating data between two known functions matlab

I have two lines y1 = -a1*x1 + c1 for theta =30 and y1 = -a2*x1 + c2 for theta = 45
is it possible to interpolate a equation for y1 for theta between 30 and 45 in matlab ? The lines are almost parallel to each other. Anyone has an easy way of doing this?
You can interpolate the coeff a and c:
w = (theta - 30) / (45 - 30 ); % w = 0 for theta = 30 and w = 1 for theta = 45
aTheta = a2 * w + a1 * ( 1 - w );
cTheat = c2 * w + c1 * ( 1 - w );
yTheta = -aTheta * x + cTheta * y;
x = 1:10;
a30 = 1;
a45 = 1.1;
c30 = 0;
c45 = 3;
y30 = -a1*x + c1;
y45 = -a2*x + c2;
Now to find y40 we can just interpolate the curve parameters (i.e. slope (a) and offset (c))
a40 = interp1([30,45], [a30, a45], 40);
c40 = interp1([30,45], [c30, c45], 40);
And now our interpolated y40 is
y40 = -a40*x + c40;
plot(x,y30,x,y45,x,y40);