I am trying the find the inverse Laplace voltage of a circuit, but when I compute it MATLAB output contains sinh and cosh. Is there a way to make MATLAB compute it?
Here is my code:
syms s
F=((s^2)+12*s+20)/(s*((s^2)+10*s+4))
f=ilaplace(F)
f=vpa(f,5)
The expression for f contains the t symbol, you have to substitute a value for t before you can compute the output at that time t; the error message directs you precisely to that solution. I chose t = 5, you can change that as you wish.
syms s
F = (s^2 + 12*s + 20) / (s*(s^2 + 10*s + 4));
f = ilaplace(F);
% 5 - 4*exp(-5*t)*(cosh(21^(1/2)*t) + (3*21^(1/2)*sinh(21^(1/2)*t))/14)
f = subs(f, 5);
double(f)
ans =
4.5083
Related
This question is connected to this one. Suppose again the following code:
syms x
f = 1/(x^2+4*x+9)
Now taylor allows the function f to be expanded about infinity:
ts = taylor(f,x,inf,'Order',100)
But the following code
c = coeffs(ts)
produces errors, because the series does not contain positive powers of x (it contains negative powers of x).
In such a case, what code should be used?
Since the Taylor Expansion around infinity was likely performed with the substitution y = 1/x and expanded around 0, I would explicitly make that substitution to make the power positive for use on coeffs:
syms x y
f = 1/(x^2+4x+9);
ts = taylor(f,x,inf,'Order',100);
[c,ty] = coeffs(subs(ts,x,1/y),y);
tx = subs(ty,y,1/x);
The output from taylor is not a multivariate polynomial, so coeffs won't work in this case. One thing you can try is using collect (you may get the same or similar result from using simplify):
syms x
f = 1/(x^2 + 4*x + 9);
ts = series(f,x,Inf,'Order',5) % 4-th order Puiseux series of f about 0
c = collect(ts)
which returns
ts =
1/x^2 - 4/x^3 + 7/x^4 + 8/x^5 - 95/x^6
c =
(x^4 - 4*x^3 + 7*x^2 + 8*x - 95)/x^6
Then you can use numden to extract the numerator and denominator from either c or ts:
[n,d] = numden(ts)
which returns the following polynomials:
n =
x^4 - 4*x^3 + 7*x^2 + 8*x - 95
d =
x^6
coeffs can then be used on the numerator. You may find other functions listed here helpful as well.
I am having difficulty in finding roots of a nonlinear equation. I have tried Matlab and Maple both, and both give me the same error which is
Error, (in RootFinding:-NextZero) can only handle isolated zeros
The equation goes like
-100 + 0.1335600000e-5*H + (1/20)*H*arcsinh(2003.40/H)
The variable is H in the equation.
How do I find the roots (or the approximate roots) of this equation?
Matlab Code:
The function file:
function hor_force = horizontal(XY, XZ, Lo, EAo, qc, VA)
syms H
equation = (-1*ZZ) + (H/qc)*(cosh((qc/H)*(XZ- XB))) - H/qc + ZB;
hor_force = `solve(equation);`
The main file:
EAo = 7.5*10^7;
Lo = 100.17;
VA = 2002;
XY = 0;
ZY = 0;
XB = 50;
ZB = -2;
XZ = 100;
ZZ = 0;
ql = 40;
Error which Matlab shows:
Error using sym/solve (line 22)
Error using maplemex
Error, (in RootFinding:-NextZero) can only handle isolated zeros
Error in horizontal (line 8)
hor_force = solve(equation);
Error in main (line 34)
h = horizontal(XY, XZ, Lo, EAo, ql, VA)
http://postimg.org/image/gm93z3b7z/
You don't need the symbolic toolbox for this:
First, create an anonymous function that can take vectors at input (use .* and ./:
equation = #(H) ((-1*ZZ) + (H./qc).*(cosh((qc./H).*(XZ- XB))) - H./qc + ZB);
Second, create a vector that you afterwards insert into the equation to find approximately when the sign of the function changes. In the end, use fzero with x0 as the second input parameter.
H = linspace(1,1e6,1e4);
x0 = H(find(diff(sign(equation(H))))); %// Approximation of when the line crosses zero
x = fzero(equation, x0) %// Use fzero to find the crossing point, using the initial guess x0
x =
2.5013e+04
equation(x)
ans =
0
To verify:
You might want to check out this question for more information about how to find roots of non-polynomials.
In Maple, using the expression from your question,
restart:
ee := -100 + 0.1335600000e-5*H + (1/20)*H*arcsinh(2003.40/H):
Student:-Calculus1:-Roots(ee, -1e6..1e6);
[ 5 ]
[-1.240222868 10 , -21763.54830, 18502.23816]
#plot(ee, H=-1e6..1e6, view=-1..1);
This post updates my question in Solve finds wrong solution?
Given the "simple" function in x:
f = (x + 3/10)^(1/2) - (9*(x + 3/10)^5)/5 - (x + 3/10)^6 + (x - 1)/(2*(x + 3/10)^(1/2));
Find the zeros by the call
solve(f,x)
This yields 3 zeros:
ans =
0.42846617518653978966562924618638
0.15249587894102346284238111155954
0.12068186494007759990714181154349
A simple look at the plot shows that the third root is nonsense:
I have a serious problem because I need to retrieve the smallest zero from the above vector. Calling min(ans) returns a wrong zero. What can I do to workaround?
This is a non-polynomial equation, and it will probably fallback to a numeric solver (non-symbolic). So there might be numerical errors, or the numeric algorithm might get stuck and report false solutions, I'm not sure...
What you can do is substitute the solutions back into the equation, and reject ones that are above some specified threshold:
% define function
syms x real
syms f(x)
xx = x+3/10;
f(x) = sqrt(xx) - 9/5*xx^5 - xx^6 + (x - 1)/(2*sqrt(xx));
pretty(f)
% find roots
sol = solve(f==0, x, 'Real',true)
% filter bad solutions
err = subs(f, x, sol)
sol = sol(abs(err) < 1e-9); % this test removes the 2nd solution
% plot
h = ezplot(f, [0.1 0.5]);
line(xlim(), [0 0], 'Color','r', 'LineStyle',':')
xlabel('x'), ylabel('f(x)')
% programmatically insert data tooltips
xd = get(h, 'XData'); yd = get(h ,'YData');
[~,idx] = min(abs(bsxfun(#minus, xd, double(sol))), [], 2);
dcm = datacursormode(gcf);
pos = [xd(idx) ; yd(idx)].';
for i=1:numel(idx)
dtip = createDatatip(dcm, h);
set(get(dtip,'DataCursor'), 'DataIndex',idx(i), 'TargetPoint',pos(i,:))
set(dtip, 'Position',pos(i,:))
end
We are left only with the two desired solutions (one is rejected by our test):
/ 3 \5
9 | x + -- |
/ 3 \ \ 10 / / 3 \6 x - 1
sqrt| x + -- | - ------------- - | x + -- | + ----------------
\ 10 / 5 \ 10 / / 3 \
2 sqrt| x + -- |
\ 10 /
sol =
0.42846617518653978966562924618638
0.12068186494007759990714181154349 % <== this one is dropped
0.15249587894102346284238111155954
err(x) =
-9.1835496157991211560057541970488e-41
-0.058517436737550288309001512815475 % <==
1.8367099231598242312011508394098e-40
I also tried using MATLAB's numeric solvers, which were able to find the two solutions given reasonable starting points:
fzero function (a derivative-free root-finding algorithm)
fsolve function (from the Optimization Toolbox)
(See this related question)
fcn = matlabFunction(f); % convert symbolic f to a regular function handle
opts = optimset('Display','off', 'TolFun',1e-9, 'TolX',1e-6);
% FZERO
sol2(1) = fzero(fcn, 0.1, opts);
sol2(2) = fzero(fcn, 0.5, opts);
disp(sol2) % [0.1525, 0.4285]
% FSOLVE
sol3(1) = fsolve(fcn, 0.0, opts);
sol3(2) = fsolve(fcn, 1.0, opts);
disp(sol3) % [0.1525, 0.4285]
For comparison, I tried solving the equation directly into MuPAD, as well as in Mathematica.
Mathematica 9.0
MuPAD (R2014a)
Of course we can always directly call MuPAD from inside MATLAB:
% f is the same symbolic function we've built above
>> sol = evalin(symengine, ['numeric::solve(' char(f) ' = 0, x, AllRealRoots)'])
sol =
[ 0.15249587894102346284238111155954, 0.42846617518653978966562924618638]
The above call is equivalent to searching the entire range x = -infinity .. infinity (which can be slow!). We should assist numeric::solve by providing a specific search ranges when possible:
>> sol = feval(symengine, 'numeric::solve', f==0, 'x = 0 .. 1', 'AllRealRoots')
sol =
[ 0.15249587894102346284238111155954, 0.42846617518653978966562924618638]
One workaround could be taking min(ans), and then checking that f(min(ans))==0. If not, then use the next-smallest value.
I'm trying build a matlab function that will evaluate a function and vector that are sent in as parameters. I'm having a hard time trying to figure out how to send in the function so that it can be evaluated in the matlab function. I figured out how to do it without the function but I'm a little lost trying to evaluate it within a matlab function. Below is my code...
This is what I'm trying to do...
x = [x1 x2]';
f = x(x1)^2 + 2 * (x2)^2
x = [5 10];
f = (5)^2 + 2 * (10)^2 % which I would like to return 225, not a column vector
This is what I have and what I have tried...
x = [5 10]';
% without using a matlab function
% k = 1
% f = x(k)^2 + 2 * x(k + 1)^2; % returns the correct answer of 225
f = x^2 + 2 * x^2 % complains about the scalar 2
f = x.^2 + 2 * x.^2 % returns a column vector [75; 300]
function [value] = evalFunction(f,x)
value = f(x);
I've tried...
f = #(x) x.^2 + 2 * (x+1).^2;
value = evalFunction(#f,x) %Error: "f" was previously used as a variable
So I tried...
f = #(x) x.^2 + 2 * (x+1).^2;
value = evalFunction(f,x) %value = [97;342]
I'm new to matlab so any help is appreciated. I've been doing some research and found some stuff here on stackoverflow but can't seem to get it to work. I've seen there are other ways to do this, but I will eventually be adding more code to the matlab evalFunction function so I'd like to do it this way. Thanks!
Anonymous functions and function handles plus array indexing. Taking x as a 2-element vector, define and use your function like:
f = #(x) x(1).^2 + 2 * x(2).^2;
value = evalFunction(f,x) % but you can just do f(x) if that is all you need
However, if evalFunction does nothing other than evaluate f at x, then you don't need it at all. Just do f(x).
Alternately,
f = #(x1,x2) x1.^2 + 2*x2.^2;
value = evalFunction(f,x1,x2); % here your function will call it by f(x1,x2)
You are probably coming at this from a C background - in Matlab, x+1 is the entire vector x with 1 added - not the element offset by 1.
The function you need is
f = #(x)x(1).^2 + 2 * (x(2)).^2;
or, to be a little more "matlab-like":
f = #(x) [1 2] * x(1:2)'.^2;
Which performs the element-wise square of the first two elements of x as a column vector, and then does the matrix multiplication with [1 2], resulting in
1 * x(1) .^2 + 2 * x(2) .^2;
Which seems to be what you were asking for.
caveat: did not have opportunity to test this...
I would like to create a function that finds the parameters p and q of Bass diffusion model, given the data of two time periods.
The model (equation) is the following:
n(T) = p*m + (q-p)*n(T-1) + q/m*n(T-1)^2
where
n(T) = number of addoptions occuring in period T
n(T-1) = number of cumulative adoptions that occured before T
p = coefficient of innovation
q = coefficient of imitation
m = number of eventual adopters
for example if m = 3.000.000
and the data for the years below is the following:
2000: n(T) = 820, n(T-1) = 0
2005: n(T) = 25000, n(T-1) = 18000
then the following equation system has to be solved (in order to determine the values of p and q):
p*m + (q-p)*0 + q/3.000.000 * 0^2 == 820
p*m + (q-p)*18000 + q/3.000.000 * 18000^2 == 25000
By following Matlab documentation I tried to create a function Bass:
function F = Bass(m, p, q, cummulativeAdoptersBefore)
F = [p*m + (q-p)*cummulativeAdoptersBefore(1) + q/m*cummulativeAdoptersBefore(1).^2;
p*m + (q-p)*cummulativeAdoptersBefore(2) + q/m*cummulativeAdoptersBefore(2).^2];
end
Which should be used in fsolve(#Bass,x0,options) but in this case m, p, q, cummulativeAdoptersBefore(1), and cummulativeAdoptersBefore(2) should be given in x0 and all variables would be considered as unknown instead of just the latter two.
Does anyone know how to solve the system of equations such as above?
Thank you!
fsolve() seeks to minimize the function you supply as argument. Thus, you have to change your equations to
p*m + (q-p)*0 + q/3.000.000 * 0^2 - 820 == 0
p*m + (q-p)*18000 + q/3.000.000 * 18000^2 - 25000 == 0
and in Matlab syntax
function F = Bass(m, p, q, cumulativeAdoptersBefore, cumulativeAdoptersAfter)
F = [p*m + (q-p)*cumulativeAdoptersBefore(1) ...
+ q/m *cumulativeAdoptersBefore(1).^2
- cumulativeAdoptersAfter(1);
p*m + (q-p)*cumulativeAdoptersBefore(2) ...
+ q/m *cumulativeAdoptersBefore(2).^2
- cumulativeAdoptersAfter(2)];
end
Note: There is a typo in your Bass function (multiplication instead of sum).
Now you have a function, which takes more parameters than there are unkowns.
One option is to create an anonymous function, which only takes the unknowns as arguments and to fix the other parameters via a closure.
To fit the unkowns p and q, you could use something like
cumulativeAdoptersBefore = [0, 1800];
cumulativeAdoptersAfter = [820, 25000];
m = 3e6;
x = [0, 0]; %# Probably, this is no good starting guess.
xopt = fsolve(#(x) Bass(m, x(1), x(2), cumulativeAdoptersBefore, cumulativeAdoptersAfter), x0);
So fsolve() sees a function taking only a single argument (a vector with two elements) and it also returns a vector value.