Assume that A, B and C are positive constants. I need to solve the following equation in symbolic form as W(A,B,C).
solve(x-(exp(log(2)*x*A)-B)*C==0)
Any help is appreciated.
Since the equation mixes polynomials and transcendentals, my first thought was simply that it may not have an analytical solution. However, the form reminded me of the Lambert W function (Wikipedia and Mathworks blog post), so I tried the variable substitution u = x/c+b which yields the simplified problem
solve(u == alpha * exp(beta * u) , u);
where alpha = exp(-log(2)*a*b*c) and beta = log(2)*a*c. Running this through Matlab gives me
>> syms alpha beta u
>> solve(u == alpha * exp(beta * u) , u)
ans =
-lambertw(0, -alpha*beta)/beta
which indeed showcases a Lambert W function call. With this knowledge, we can get the solution in terms of xsol like so:
syms a b c alpha beta x u xsol usol
usol = solve(u == alpha * exp(beta*u),u);
log2 = log(sym(2));
xsol = subs(c*(usol-b),[alpha,beta],[exp(-log2*a*b*c),log2*a*c]);
Let's make sure the Symbolic Engine didn't make a mistake by checking the analytical solution against a numeric one:
anum = rand();
bnum = rand();
cnum = rand();
xana = double(subs(xsol,[a,b,c],[anum,bnum,cnum]));
xnum = vpasolve(x-(exp(log2*x*anum)-bnum)*cnum,x);
fprintf('%15.10e\n%15.10e\n%15.10e\n',xana,xnum,xana-xnum);
which displays
8.0171933677e-02
8.0171933677e-02
1.7453177064e-19
Note: certain combinations of a, b, and c may result in an equation with no real solution. In such situations, the analytical solution may give a complex number whose veracity should be highly questioned.
Related
MATLAB gives me the same expression back.
Here's my code
syms tau alpha phi
f = sign(alpha*cos(phi))*(abs(alpha*cos(phi)) - 2.5*(alpha*cos(phi))^2);
F=f*sin(phi);
int(F,phi, [pi/2, acos(tau/alpha)])
I did plug in the values of variables tau and alpha but it still gives me the same expression back. Anyone know how to solve it? Or some other numerical method which could give me answer in these symbols? Will wolfram-mathematica help?
Mathematica
Integrate[(Sign[alpha*Cos[phi]]*(Abs[alpha*Cos[phi]] - 5/2*
(alpha*Cos[phi])^2))*Sin[phi], {phi, Pi/2, ArcCos[tau/alpha]}]
(* ConditionalExpression[-(tau^2/(2 alpha)) + (5 alpha^3 Abs[tau]^3)/
(6 Abs[alpha]^4), ArcCos[tau/alpha] \[Element] Reals] *)
Thus the result is the expression inside the ConditionalExpression if the ArcCos[tau/alpha] is an element of the reals.
If you could specify something like -1<=tau/alpha<=1 && 0<=tau then it can provide an even simpler result, (tau^2 (-3 + 5 tau))/(6 alpha)
Please verify this before you depend on it.
Something like
syms tau alpha phi
f = sign(alpha*cos(phi))*(abs(alpha*cos(phi)) - 2.5*(alpha*cos(phi))^2);
will just generate another symbolic variable. Your goal however is to specify a symbolic function and for that you have to specify the function arguments:
syms tau alpha phi
f(tau,alpha,phi) = sign(alpha*cos(phi))*(abs(alpha*cos(phi)) - 2.5*(alpha*cos(phi))^2);
F(tau,alpha,phi) =f*sin(phi);
Then you can calculate the integral with
R = int(F,phi, [pi/2, acos(tau/alpha)])
Since your integral is dependent on tau and alpha, R is again a symbolic function R(tau,alpha).
Alternatively you could just specify the arguments at the end, e.g.
syms tau alpha phi
f = sign(alpha*cos(phi))*(abs(alpha*cos(phi)) - 2.5*(alpha*cos(phi))^2);
F=f*sin(phi);
R(tau,alpha) = int(F,phi, [pi/2, acos(tau/alpha)])
But I personally find that less clean.
Note that you could also write F directly as
F(tau,alpha,phi) = sin(phi)*(sign(alpha*cos(phi))*(abs(alpha*cos(phi)) - 2.5*(alpha*cos(phi))^2));
I have an equation of the form c = integral of f(t)dt limiting from a constant to a variable (I don't want to show the full equation because it is very long and complex). Is there any way to calculate in MATLAB what the value of that variable is (there are no other variables and the equation is too difficult to solve by hand)?
Assume your limit is from cons to t and g(t) as your function with variable t. Now,
syms t
f(t) = int(g(t),t);
This will give you the indefinite integral. Now f(t) will be
f(t) = f(t)+f(cons);
You have the value of f(t)=c. So just solve the equation
S = solve(f(t)==c,t,'Real',true);
eval(S) will give the answer i think
This is an extremely unclear question - if you do not want to post the full equation, post an example instead
I am assuming this is what you intend: you have an integrand f(x), which you know, and has been integrated to give some constant c which you know, over the limits of x = 0, to x = y, for example, where y may change, and you desire to find y
My advice would be to integrate f(x) manually, fill in the first limit, and subtract that portion from c. Next you could employ some technique such as the Newton-Ralphson method to iteratively search for the root to your equation, which should be in x only
You could use a function handle and the quad function for the integral
myFunc = #(t) exp(t*3); % or whatever
t0 = 0;
t1 = 3;
L = 50;
f = #(b) quad(#(t) myFunc(t,b),t0,t1);
bsolve = fzero(f,2);
Hope it help !
I've read up on fsolve and solve, and tried various methods of curve fitting/regression but I feel I need a bit of guidance here before I spend more time trying to make something work that might be the wrong approach.
I have a series of equations I am trying to fit to a data set (x) separately:
for example:
(a+b*c)*d = x
a*(1+b*c)*d = x
x = 1.9248
3.0137
4.0855
5.0097
5.7226
6.2064
6.4655
6.5108
6.3543
6.0065
c= 0.0200
0.2200
0.4200
0.6200
0.8200
1.0200
1.2200
1.4200
1.6200
1.8200
d = 1.2849
2.2245
3.6431
5.6553
8.3327
11.6542
15.4421
19.2852
22.4525
23.8003
I know c, d and x - they are observations. My unknowns are a and b, and should be constant.
I could do it manually for each x observation but there must be an automatic and far superior way or at least another approach.
Very grateful if I could receive some guidance. Thanks for the time!
Given your two example equations; let y=x./d, then
y = a+b*c
y = a+a*b*c
The first case is just a line, for which you can obtain a least squares fit (values for a and b) with polyfit(). In the second case, you can just say k=a*b (since these are both fitted anyway), then rewrite it as:
y = a+k*c
Which is exactly the same line as the first problem, except now b = k/a. In fact, b=b1/a is the solution to the second problem where b1 is the fit from the first problem. In short, to solve them both, you need one call to polyfit() and a couple of divisions.
Will that work for you?
I see two different equations to fit here. To spell out the code:
For (a+b*c)*d = x
p = polyfit(c, x./d, 1);
a = p(2);
b = p(1);
For a*(1+b*c)*d = x
p = polyfit(c, x./d, 1);
a = p(2);
b = p(1) / a;
No need for polyfit; this is just a linear least squares problem, which is best solved with MATLAB's slash operator:
>> ab = [ones(size(c)) c] \ (x./d)
ans =
1.411437211703194e+000 % 'a'
-7.329687661579296e-001 % 'b'
Faster, cleaner, more educative :)
And, as Emmet already said, your second equation is nothing more than a different form of your first equation, the difference being that the b in your first equation, is equal to a*b in your second one.
I'm working with MATLAB's symbolic toolbox, and I'm having some issues pulling out the coefficients of derivatives. Maybe MATLAB can't do what I am looking for. Anyway, code that reproduces the issue I'm having is shown below:
clear ; close all; clc;
syms a b t
x = sym('x(t)');
y = sym('y(t)');
syms a b;
ra = a*cos(x);
radot = diff(ra, t);
xdot = diff(x,t);
ydot = diff(y,t);
% This one works as expected
works = coeffs(radot(1), xdot)
% This doesn't work as expected
fails = coeffs(radot(1), ydot)
Comments in the above code sections highlight what works and what does not work as expected. Specifically, the outputs are:
radot =
-a*sin(x(t))*diff(x(t), t)
works =
-a*sin(x(t))
fails =
-a*sin(x(t))*diff(x(t), t)
Does anyone know why this happens or whether I'm doing something wrong?
The result of the last line is constant with respect to ydot, and therefore the whole expression is seen as a single coefficient (a constant).
What is your expected result for coeffs(radot(1), ydot)?
It looks like you may be using coeffs for something that it wasn't meant for. Look at the help. It's designed to give the coefficients of a polynomial, not wether a differential equation is a function of one variable or another.
If you happen to be trying to take the derivative with respect to xdot and ydot, you can do this
syms z; % Subsitution variable for diff(x(t), t) and diff(y(t), t)
diff(subs(radot(1),xdot,z),z)
diff(subs(radot(1),ydot,z),z)
which returns
ans =
-a*sin(x(t))
ans =
0
I have all the data and an ODE system of three equations which has 9 unknown coefficients (a1, a2,..., a9).
dS/dt = a1*S+a2*D+a3*F
dD/dt = a4*S+a5*D+a6*F
dF/dt = a7*S+a8*D+a9*F
t = [1 2 3 4 5]
S = [17710 18445 20298 22369 24221]
D = [1357.33 1431.92 1448.94 1388.33 1468.95]
F = [104188 104792 112097 123492 140051]
How to find these coefficients (a1,..., a9) of an ODE using Matlab?
I can't spend too much time on this, but basically you need to use math to reduce the equation to something more meaningful:
your equation is of the order
dx/dt = A*x
ergo the solution is
x(t-t0) = exp(A*(t-t0)) * x(t0)
Thus
exp(A*(t-t0)) = x(t-t0) * Pseudo(x(t0))
Pseudo is the Moore-Penrose Pseudo-Inverse.
EDIT: Had a second look at my solution, and I didn't calculate the pseudo-inverse properly.
Basically, Pseudo(x(t0)) = x(t0)'*inv(x(t0)*x(t0)'), as x(t0) * Pseudo(x(t0)) equals the identity matrix
Now what you need to do is assume each time step (1 to 2, 2 to 3, 3 to 4) is an experiment (therefore t-t0=1), so the solution would be to:
1- Build your pseudo inverse:
xt = [S;D;F];
xt0 = xt(:,1:4);
xInv = xt0'*inv(xt0*xt0');
2- Get exponential result
xt1 = xt(:,2:5);
expA = xt1 * xInv;
3- Get the logarithm of the matrix:
A = logm(expA);
And since t-t0= 1, A is our solution.
And a simple proof to check
[t, y] = ode45(#(t,x) A*x,[1 5], xt(1:3,1));
plot (t,y,1:5, xt,'x')
You have a linear, coupled system of ordinary differential equations,
y' = Ay with y = [S(t); D(t); F(t)]
and you're trying to solve the inverse problem,
A = unknown
Interesting!
First line of attack
For given A, it is possible to solve such systems analytically (read the wiki for example).
The general solution for 3x3 design matrices A take the form
[S(t) D(t) T(t)].' = c1*V1*exp(r1*t) + c2*V2*exp(r2*t) + c3*V3*exp(r3*t)
with V and r the eigenvectors and eigenvalues of A, respectively, and c scalars that are usually determined by the problem's initial values.
Therefore, there would seem to be two steps to solve this problem:
Find vectors c*V and scalars r that best-fit your data
reconstruct A from the eigenvalues and eigenvectors.
However, going down this road is treaturous. You'd have to solve the non-linear least-squares problem for the sum-of-exponentials equation you have (using lsqcurvefit, for example). That would give you vectors c*V and scalars r. You'd then have to unravel the constants c somehow, and reconstruct the matrix A with V and r.
So, you'd have to solve for c (3 values), V (9 values), and r (3 values) to build the 3x3 matrix A (9 values) -- that seems too complicated to me.
Simpler method
There is a simpler way; use brute-force:
function test
% find
[A, fval] = fminsearch(#objFcn, 10*randn(3))
end
function objVal = objFcn(A)
% time span to be integrated over
tspan = [1 2 3 4 5];
% your desired data
S = [17710 18445 20298 22369 24221 ];
D = [1357.33 1431.92 1448.94 1388.33 1468.95 ];
F = [104188 104792 112097 123492 140051 ];
y_desired = [S; D; F].';
% solve the ODE
y0 = y_desired(1,:);
[~,y_real] = ode45(#(~,y) A*y, tspan, y0);
% objective function value: sum of squared quotients
objVal = sum((1 - y_real(:)./y_desired(:)).^2);
end
So far so good.
However, I tried both the complicated way and the brute-force approach above, but I found it very difficult to get the squared error anywhere near satisfyingly small.
The best solution I could find, after numerous attempts:
A =
1.216731997197118e+000 2.298119167536851e-001 -2.050312097914556e-001
-1.357306715497143e-001 -1.395572220988427e-001 2.607184719979916e-002
5.837808840775175e+000 -2.885686207763313e+001 -6.048741083713445e-001
fval =
3.868360951628554e-004
Which isn't bad at all :) But I would've liked a solution that was less difficult to find...