I am trying to find out the root of an equation constraint using Newton's Method (open to any other method). The equation constraint is dependent on the roots of a quadratic equation which has one unknown term. The equation descriptions (quadratic and constraint) are shown below. The roots of the quadratic equation are assumed to be p1 and p2.
x^2 + x*(c1*unknown/2 + C1*c2)/(c1*c2*c3*unknown/2) + 1/(c1*c2*c3*u/2) = 0
with constraint
(1/(p2-p1))*(exp(-0.3*p2) - 1)*(c1*c2 - p2) - (exp(-0.3*p1) - 1)*(c1*c2 - p1) - 0.04 = 0
I am wondering if there are any other approximation methods to solve this problem if Newton's Method is not going to do so.
Matlab Code
p0=10*10^6;
Cc=0.65*10^-6;Rp=100*10^3;Cp=55*10^-9; z1=1/(Cp*Rp);
N = 100;error = 0.02;
syms 'x'
a = 1;
b = ((Cc*(x/2+Rp))/(Cc*Cp*Rp*x/2));
c = 1/(Cc*Cp*Rp*x/2);
poles1 = (-b + sqrt(b^2 - 4*a*c))/(2*a);
poles2 = (-b - sqrt(b^2 - 4*a*c))/(2*a);
p1_subterm = (exp(-0.3*poles1) - 1)*(z1 - poles1);
p2_subterm = (exp(-0.3*poles2) - 1)*(z1- poles2);
f(x) = (1/(poles2 - poles1))*p2_subterm - p2_subterm - 0.04;
df = diff(f);
while i <= N
p = p0-(f(p0)/df(p0))
if (abs(p - p0)/abs(p)) < error
fprintf('Solution is %f \n', double(p))
return
end
i = i + 1;
p0 = p;
end
fprintf('Solution did not converge within %d iterations \n', N)
I don't think your code for f(x) corresponds to the equation listed above: In the MATLAB code 1/(poles2-poles1) multiplies both the exp((...)poles2) and the exp((...)poles1) terms and you have 1/(c1*c2) - poles1 instead of c1*c2 - poles1.
I have not checked through the poles1 and poles2 terms as I find the 10 sets of parenthesis intimidating. It would suggest making your code more readable by breaking up each of those equations in to a number of shorter, clearer lines.
Noting that we can multiply the quadratic by c1*c2*c3*unknown,
(c1*c2*c3*unknown)*x^2 + x*2*(c1*unknown/2 + C1*c2) + 2 = 0
then you can write the poles and f code as
% Here unknown is x
syms 'x'
a = c1*c2*c3*x;
b = c1*x + 2*c1*c2;
c = 2;
poles1 = (-b + sqrt(b^2 - 4*a*c))/(2*a);
poles2 = (-b - sqrt(b^2 - 4*a*c))/(2*a);
p1_subterm = (exp(-0.3*poles1) - 1)*(c1*c2 - poles1);
p2_subterm = (exp(-0.3*poles2) - 1)*(c1*c2 - poles2);
f(x) = (1/(poles2 - poles1))*p2_subterm - p2_subterm - 0.04;
Related
I have created a program in Matlab to try to find the root of f(x) = exp(2x) + 3x - 4 (the function "fopg1" in my code). My code is as follows:
format long
tic;
for dum=1:1000;
x(1) = 0.5;
x(2) = 0.4;
err_tol = 1e-8;
iteration(1) = 1;
n = 3;
while err_estimate > err_tol
iteration(n) = n;
x(n) = x(n-1) - fopg1(x(n-2)) * ((x(n-1) - x(n-2)) / (fopg1(x(n-1)) - fopg1(x(n-2))));
err_estimate(n) = abs(x(n) - x(n-1));
n = n + 1;
end
%end
time = toc;
avgtime = time/1000;
A = [iteration' x' err_estimate' tbd'];
f = '%2i %13.9f %13.9f %7.3f'; compose(f,A)
Unfortunately this does not converge. I feel like it should. Is there a flaw in my program or does it in fact not converge? Thanks in advance.
Maarten
I answered a very similar question here a few days ago. Using the same code, without an iterations limit and with an increased tolerance (1e-8 as per your example), I detect the expected convergence of exp(2x) + 3x - 4 using the secant method:
clear();
clc();
com = Inf;
i = 2;
err_tol = 1e-8;
f = #(x) exp(2*x) + 3*x - 4;
x(1) = 0.5;
x(2) = 0.4;
while (abs(com) > err_tol)
com = f(x(i)) * (x(i) - x(i-1)) / (f(x(i)) - f(x(i-1)));
x(i+1)= x(i) - com;
i = i + 1;
n = n - 1;
end
display(['Root X = ' num2str(x(end))]);
The message I receive is: Root X = 0.47369. It shouldn't be hard for you to implement your additional data within this code.
I have a mathematical function E which I want to minimize. I get from solving this 16 possible solutions x1, x2, ..., x16, only two of which that actually minimize the function (located at a minimum). Using a for loop, I can then plug all of these 16 solutions into the original function, and select the solutions I need by applying some criteria via if statements (plotting E vs E(x) if x is real and positive, if first derivative of E is below a threshold, and if the second derivative of E is positive).
That way I only plot the solutions I'm interested in. However, I would now like to extract the relevant x that I plot. Here's a sample MATLAB code that plots the way I just described. I want to extract the thetas that I actually end up plotting. How to do that?
format long
theta_s = 0.77944100;
sigma = 0.50659500;
Delta = 0.52687700;
%% Defining the coefficients of the 4th degree polynomial
alpha = cos(2*theta_s);
beta = sin(2*theta_s);
gamma = 2*Delta^2/sigma^2;
a = -gamma^2 - beta^2*Delta^2 - alpha^2*Delta^2 + 2*alpha*Delta*gamma;
b = 2*alpha*gamma - 2*Delta*gamma - 2*alpha^2*Delta + 2*alpha*Delta^2 -...
2*beta^2*Delta;
c = 2*gamma^2 - 2*alpha*Delta*gamma - 2*gamma - alpha^2 + 4*alpha*Delta +...
beta^2*Delta^2 - beta^2 - Delta^2;
d = -2*alpha*gamma + 2*Delta*gamma + 2*alpha + 2*beta^2*Delta - 2*Delta;
e = beta^2 - gamma^2 + 2*gamma - 1;
%% Solve the polynomial numerically.
P = [a b c d e];
R = roots(P);
%% Solve r = cos(2x) for x: x = n*pi +- 1/2 * acos(r). Using n = 0 and 1.
theta = [1/2.*acos(R) -1/2.*acos(R) pi+1/2.*acos(R) pi-1/2.*acos(R)];
figure;
hold on;
x = 0:1/1000:2*pi;
y_1 = sigma*cos(x - theta_s) + sqrt(1 + Delta*cos(2*x));
y_2 = sigma*cos(x - theta_s) - sqrt(1 + Delta*cos(2*x));
plot(x,y_1,'black');
plot(x,y_2,'black');
grid on;
%% Plot theta if real, if positive, if 1st derivative is ~zero, and if 2nd derivative is positive
for j=1:numel(theta);
A = isreal(theta(j));
x_j = theta(j);
y_j = sigma*cos(x_j - theta_s) + sqrt(1 + Delta*cos(2*x_j));
FirstDer = sigma* sin(theta(j) - theta_s) + Delta*sin(2*theta(j))/...
sqrt(1 + Delta*cos(2*theta(j)));
SecDer = -sigma*cos(theta(j)-theta_s) - 2*Delta*cos(2*theta(j))/...
(1 + Delta*cos(2*theta(j)))^(1/2) - Delta^2 * (sin(2*theta(j)))^2/...
(1 + Delta*cos(2*theta(j)))^(3/2);
if A == 1 && x_j>=0 && FirstDer < 1E-7 && SecDer > 0
plot(x_j,y_j,['o','blue'])
end
end
After you finish all plotting, get the axes handle:
ax = gca;
then write:
X = get(ax.Children,{'XData'});
And X will be cell array of all the x-axis values from all lines in the graph. One cell for each line.
For the code above:
X =
[1.961054062875753]
[4.514533853417446]
[1x6284 double]
[1x6284 double]
(First, the code all worked. Thanks for the effort there.)
There are options here. A are couple below
Record the values as you generate them
Within the "success" if statement, simply record the values. See edits to your code below.
This would always be the preferred option for me, it just seems much more efficient.
xyResults = zeros(0,2); %%% INITIALIZE HERE
for j=1:numel(theta);
A = isreal(theta(j));
x_j = theta(j);
y_j = sigma*cos(x_j - theta_s) + sqrt(1 + Delta*cos(2*x_j));
FirstDer = sigma* sin(theta(j) - theta_s) + Delta*sin(2*theta(j))/...
sqrt(1 + Delta*cos(2*theta(j)));
SecDer = -sigma*cos(theta(j)-theta_s) - 2*Delta*cos(2*theta(j))/...
(1 + Delta*cos(2*theta(j)))^(1/2) - Delta^2 * (sin(2*theta(j)))^2/...
(1 + Delta*cos(2*theta(j)))^(3/2);
if A == 1 && x_j>=0 && FirstDer < 1E-7 && SecDer > 0
xyResults(end+1,:) = [x_j y_j]; %%%% RECORD HERE
plot(x_j,y_j,['o','blue'])
end
end
Get the result from the graphics objects
You can get the data you want from the actual graphics objects. This would be the option if there was just no way to capture the data as it was generated.
%First find the objects witht the data you want
% (Ideally you could record handles to the lines as you generated
% them above. But then you could also simply record the answer, so
% let's assume that direct record is not possible.)
% (BTW, 'findobj' is an underused, powerful function.)
h = findobj(0,'Marker','o','Color','b','type','line')
%Then get the `xdata` filed from each
capturedXdata = get(h,'XData');
capturedXdata =
2×1 cell array
[1.96105406287575]
[4.51453385341745]
%Then get the `ydata` filed from each
capturedYdata = get(h,'YData');
capturedYdata =
2×1 cell array
[1.96105406287575]
[4.51453385341745]
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I'm working on a project for school that basically involves iteratively solving a cubic equation. I'm using MATLAB for it, but I've never really done much with MATLAB so I'm having some trouble with the logic of it.
Here's my code:
% Redlich/Kwong EOS
sigma = 1;
epsilon = 0;
omega = 0.08664;
psi = 0.42748;
beta = #(Psat_RK) omega*PsatRK/Pc/Tr(1); % Pc is in bar, may need a unit conversion later
alpha = (Tr(1))^(-1/2);
q = psi*alpha/omega/Tr(1);
A = #(beta) (sigma + epsilon - 1)*beta - 1;
B = #(beta) (sigma*epsilon - sigma - epsilon)*(beta^2) + (q - sigma - epsilon)*beta;
C = #(beta) -(sigma*epsilon*(1+beta) + q)*(beta^2);
Q = #(A,B) ((A^2) - 3*B)/9;
R = #(A,B,C) (2*(A^3) - 9*A*B + 27*C)/54;
M = #(R,Q) R^2 - Q^3;
if M > 0
Z_single = ((-R+(M^0.5))^(1/3)) + ((-R-(M^0.5))^(1/3)) - (A/3);
I = (1/(sigma-epsilon))*log((Z_single+sigma*beta)/(Z_single+epsilon*beta));
end
if M < 0
theta = acos(R/(Q^(1/3)));
Z(1) = -2*(Q^0.5)*(cos(theta/3)) - (A/3);
Z(2) = -2*(Q^0.5)*(cos((theta + 2*pi)/3)) - (A/3);
Z(3) = -2*(Q^0.5)*(cos((theta - 2*pi)/3)) - (A/3);
Z_liquid = min(Z)
Z_vapor = max(Z)
I_liquid = (1/(sigma-epsilon))*log((Z_liquid+sigma*beta)/(Z_liquid+epsilon*beta));
I_vapor = (1/(sigma-epsilon))*log((Z_vapor+sigma*beta)/(Z_vapor+epsilon*beta));
end
ln_phi_liquid = Z_liquid - 1 - log(Z_liquid - beta) - q*I_liquid;
ln_phi_vapor = Z_vapor - 1 - log(Z_vapor - beta) - q*I_vapor;
objfun = (ln_phi_liquid - ln_phi_vapor);
Psat_RK_solved = fsolve(objfun,10);
Basically, I'm trying to iterate on the value of Psat_RK until the objfun equals 0. I can post more details of the math if needed, but I figured this would be enough to get started. Thanks.
Edit: Sorry, forgot to actually mention the problem.
Here's the error I'm getting.
Undefined operator '>' for input arguments of type 'function_handle'.
Error in Proj2 (line 73)
if M > 0
I can't figure out how to establish in this line that M is being calculated off an anonymous function.
EDIT:
sigma = 1;
epsilon = 0;
omega = 0.08664;
psi = 0.42748;
beta = #(Psat_RK) omega*PsatRK/Pc/Tr(1); % Pc is in bar, may need a unit conversion later
alpha = (Tr(1))^(-1/2);
q = psi*alpha/omega/Tr(1);
A = #(Psat_RK) (sigma + epsilon - 1)*beta(Psat_RK) - 1;
B = #(Psat_RK) (sigma*epsilon - sigma - epsilon)*(beta(Psat_RK)^2) + (q - sigma - epsilon)*beta(Psat_RK);
C = #(Psat_RK) -(sigma*epsilon*(1+beta(Psat_RK)) + q)*(beta(Psat_RK)^2);
Q = #(Psat_RK) ((A(Psat_RK)^2) - 3*B(Psat_RK))/9;
R = #(Psat_RK) (2*(A(Psat_RK)^3) - 9*A(Psat_RK)*B(Psat_RK) + 27*C(Psat_RK))/54;
M = #(Psat_RK) R(Psat_RK)^2 - Q(Psat_RK)^3;
if M(Psat_RK) > 0
Z_single = ((-R+(M^0.5))^(1/3)) + ((-R-(M^0.5))^(1/3)) - (A/3);
I = (1/(sigma-epsilon))*log((Z_single+sigma*beta)/(Z_single+epsilon*beta));
end
if M(Psat_RK) < 0
theta = acos(R/(Q^(1/3)));
Z(1) = -2*(Q^0.5)*(cos(theta/3)) - (A/3);
Z(2) = -2*(Q^0.5)*(cos((theta + 2*pi)/3)) - (A/3);
Z(3) = -2*(Q^0.5)*(cos((theta - 2*pi)/3)) - (A/3);
Z_liquid = min(Z)
Z_vapor = max(Z)
I_liquid = (1/(sigma-epsilon))*log((Z_liquid+sigma*beta)/(Z_liquid+epsilon*beta));
I_vapor = (1/(sigma-epsilon))*log((Z_vapor+sigma*beta)/(Z_vapor+epsilon*beta));
end
ln_phi_liquid = Z_liquid - 1 - log(Z_liquid - beta) - q*I_liquid;
ln_phi_vapor = Z_vapor - 1 - log(Z_vapor - beta) - q*I_vapor;
objfun = (ln_phi_liquid - ln_phi_vapor);
Psat_RK_solved = fsolve(objfun,10);
I know the code needs some work further down, but the code below shouldn't affect why it hangs at the first if statement, right? The error is:
Undefined function or variable 'Psat_RK'.
Error in Proj2 (line 122)
if M(Psat_RK) > 0
It looks like you are trying to use anonymous functions incorrectly.
If we take a look at one of them:
Q = #(A,B) ((A^2) - 3*B)/9;
To MATLAB, this is the equivalent of this function:
function C = Q(A, B)
C = ((A^2) - 3*B) / 9;
end
Q is the name of the function and doesn't represent a value. If, however, you pass Q the two arguments that it needs (A and B), then it will yield a value.
Obviously, you would want to call this in the following way:
value = Q(a,b);
If you look at your own code, you try to use Q directly as if it were a value rather than a function handle.
Z(1) = -2*(Q^0.5)*(cos(theta/3)) - (A/3);
If we break down this single line a little more, we realize that A (one of the inputs to Q) is also an anonymous function. Same actually goes for B.
Then further down the rabbit hole, A and B depend upon the output of the anonymous function beta which is finally defined at the top.
beta = #(Psat_RK) omega*PsatRK/Pc/Tr(1);
So assuming we have a value for Psat_RK, this whole chain would look like this.
betaValue = beta(Psat_RK);
aValue = A(betaValue);
bValue = B(betaValue);
qValue = A(aValue, bValue);
Now you can use qValue as a value and the statement above would become
Z(1) = -2 * (qValue ^ 0.5) * (cos(theta / 3)) - (aValue / 3);
If you wanted to simplify this, you could redefine Q to be:
Q = #(Psat_RK)(A(beta(Psat_RK))^2 - 3 * B(beta(Psat_RK))) / 9;
This applies to all anonymous functions you have defined (including M which is giving you your first error).
Summary
Anonymous functions are useful for a number of things and functional programmers love them. For your case, I would probably recommend that you just write a simple function that is a function of Psat_RK and create a single anonymous function for that and pass it to fsolve.
fsolve(#objectiveFUnction, x0);
function value = objectiveFunction(Psat_RK)
% Do all your calculations here to get objfun given Psat_RK
% No anonymous functions needed here!
end
Addendum
If we wanted to convert all of your anonymous functions to be a function of Psat_RK they would look like this.
A = #(Psat_RK) (sigma + epsilon - 1) * beta(Psat_RK) - 1;
B = #(Psat_RK) (sigma * epsilon - sigma - epsilon)*(beta(Psat_RK)^2) + (q - sigma - epsilon)*beta(Psat_RK);
C = #(Psat_RK) -(sigma*epsilon*(1+beta(Psat_RK)) + q)*(beta(Psat_RK)^2);
Q = #(Psat_RK) ((A(Psat_RK)^2) - 3*B(Psat_RK))/9;
R = #(Psat_RK) (2*(A(Psat_RK)^3) - 9*A(Psat_RK)*B(Psat_RK) + 27*C(Psat_RK))/54;
M = #(Psat_RK) R(Psat_RK)^2 - Q(Psat_RK)^3;
Example
Here is how I would write this as a separate function without all of those anonymous functions.
objectiveFunction.m
function value = objectiveFunction(psat)
% Redlich/Kwong EOS
sigma = 1;
epsilon = 0;
omega = 0.08664;
psi = 0.42748;
% Pc is in bar, may need a unit conversion later
beta = omega * psat / Pc / Tr(1); % NOT SURE WHAT Tr or Pc ARE
alpha = (Tr(1))^(-1/2);
q = psi*alpha/omega/Tr(1);
A = (sigma + epsilon - 1)*beta - 1;
B = (sigma*epsilon - sigma - epsilon)*(beta^2) + (q - sigma - epsilon)*beta;
C = beta -(sigma*epsilon*(1+beta) + q)*(beta^2);
Q = ((A^2) - 3*B)/9;
R = (2*(A^3) - 9*A*B + 27*C)/54;
M = R^2 - Q^3;
if M > 0
Z_single = ((-R+(M^0.5))^(1/3)) + ((-R-(M^0.5))^(1/3)) - (A/3);
I = (1/(sigma-epsilon))*log((Z_single+sigma*beta)/(Z_single+epsilon*beta));
end
if M < 0
theta = acos(R/(Q^(1/3)));
Z(1) = -2*(Q^0.5)*(cos(theta/3)) - (A/3);
Z(2) = -2*(Q^0.5)*(cos((theta + 2*pi)/3)) - (A/3);
Z(3) = -2*(Q^0.5)*(cos((theta - 2*pi)/3)) - (A/3);
Z_liquid = min(Z);
Z_vapor = max(Z);
I_liquid = (1/(sigma-epsilon))*log((Z_liquid+sigma*beta)/(Z_liquid+epsilon*beta));
I_vapor = (1/(sigma-epsilon))*log((Z_vapor+sigma*beta)/(Z_vapor+epsilon*beta));
end
ln_phi_liquid = Z_liquid - 1 - log(Z_liquid - beta) - q*I_liquid;
ln_phi_vapor = Z_vapor - 1 - log(Z_vapor - beta) - q*I_vapor;
value = (ln_phi_liquid - ln_phi_vapor);
end
Then from the MATLAB command window, you could type the following to get your solution.
Psat_RK_solved = fsolve(#objectiveFunction, 10);
This way, the only anonymous function is the one that you use to point fsolve to your actual objective function.
Hi I am very new to MATLAB. I was trying to solve these equations to either get an analytical solution or solve them numerically. For the analytical solution, I get the following error:
Warning: Cannot solve symbolically. Returning a numeric approximation instead.
In solve (line 305)
Here is my code:
syms A B Ph Pl
delta = 0.1;
mu = 0.02;
sigma = 0.2;
w = 1;
k = 3;
l = 2;
beta = (0.5 - mu/sigma^2) + ((mu/sigma^2 - 0.5)^2 + 2*delta/sigma^2)^0.5;
alpha = -((0.5 - mu/sigma^2) - ((mu/sigma^2 - 0.5)^2 + 2*delta/sigma^2)^0.5);
eqn1 = (A*(Ph^(-alpha)) + (Ph/delta-mu)) -(B*Ph^beta)-k;
eqn2 = (A*Pl^(-alpha) + Pl/(delta-mu) -w/delta) - B*Pl^beta + l;
eqn3 = -alpha*A*(Ph^(-alpha-1)) + 1/(delta-mu) - (beta*B*Ph^(beta-1));
eqn4 = alpha*A*Pl^(-alpha-1)- (beta*B*Pl^(beta-1));
sol = solve([eqn1==0, eqn2==0, eqn3==0, eqn4==0], [A, B, Ph, Pl]);
Matlab is telling you it can't find an analytic solution, but it is definitely finding numerical solutions when I run it, however, they're all complex. Type:
sol.A
in your command window to see what A looks like, same with B, Ph and Pl.
My question today is related to this previous question. I am following this research paper. I am trying to duplicate figure 8 located on page 20. I have a screenshot:
I'm confused on how to plot the left figure this in MATLAB because now a instead of having time varying we have the treatment varying. Here's what I have from the previous question:
function dX = CompetitionModel(~,X)
bs = 8e-3;
bl = 4e-3;
bh = 6.4e-3;
N = sum(X);
K = 1e8;
m1 = 2e-5;
m2 = 9e-9;
p = 5e-13;
I = 1e-3;
T = 1e-3; % Treatment
a = 0;
dX = [X(1) * (bs * (1 - N/K) - I - T - m1) - p * X(1) * (X(2) + X(3));
X(2) * (bl * (1 - N/K) - I - a*T - m2) + m1 * X(1) + p * X(2) * (X(1) - X(3));
X(3) * (bh * (1 - N/K) - I - a*T) + m2 * X(2) + p * X(3) * (X(1) + X(2))];
end
To plot my equations in the previous question, I typed the following in the command window:
>> [t,Y] = ode45(#CompetitionModel, [0 4.5e4], [1e4 0 0]);
>> plot(t,X(:,1), t,X(:,2), t,X(:,3))
In my function file, I have Treatment already defined. I'm guessing that it shouldn't be anymore. So what can I do so that I have Treatment varying instead of time? I hope my question makes sense.
You still solve the equation in regards to the time - but solely plot the value at the time t = 1 month.
To vary the treatment you need an additional loop around the ode45 call and pass the current treatment-value to the function dX
for treatment = 10^-4:10^-5:10^-3
[t,Y] = ode45(#CompetitionModel, [0 4.5e4], [1e4 0 0], [] , treatment);
plot(treatment,Y(end,1), 'x')
plot(treatment,Y(end,2), 'kx')
plot(treatment,Y(end,3), 'rx')
hold on
end
the function dX now has to be changed to accept the treatment input:
function dX = CompetitionModel(~,X, T)
Finally, comment your old treatment assignment in the function dX: %T = 1e-3; % Treatment