Matlab: Using sym in limit - matlab

Say I have the following symbolic function:
syms f(t)
f(t)=sin(t)/t
I want to get the limit using another symbolic function. I tried:
syms lim(x)
lim(x)=limit(f(t),t,x)
But when I tried to use lim(0) I got this error:
Error using symengine (line 59)
Division by zero.
Can this be fixed?

Take a look at lim(x). For some reason the limit is gone. I don't really understand what is going wrong there. If you use an anonymous function instead of a function handle, the evaluation of limit is postponed until x has a value and it works.
>> lim=#(x)limit(f(t),t,x)
lim =
#(x)limit(f(t),t,x)
>> lim(0)
ans =
1

Matlab does not have delayed assignments as discussed here. Therefore, when lim is created, the call to limit is immediately evaluated with x replacing t:
>> syms t x f(t) lim(x)
>> f(t) = sin(t)/t
f(t) =
sin(t)/t
>> lim(x) = limit(f(t),t,x)
lim(x) =
sin(x)/x
And when you evaluate lim(0), you get sin(0)/0, which throws the error.

Related

Error using integral: A and B must be floating-point scalars

I want to evaluate the simple example of integral
a = max(solve(x^3 - 2*x^2 + x ==0 , x));
fun = #(x) exp(-x.^2).*log(x).^2;
q = integral(fun,0,a)
and the error is
Error using integral (line 85)
A and B must be floating-point scalars.
Any tips? The lower limit of my integral must be a function, not a number.
The Matlab command solve returns symbolic result. integral accepts only numeric input. Use double to convert symbolic to numeric. As your code is written now, already max should throw an error due to symbolic input. The following works.
syms x;
a = max(double(solve(x^3 - 2*x^2 + x)));
fun = #(x) exp(-x.^2).*log(x).^2;
q = integral(fun,0,a)
Output: 1.9331.
the lower limit of my integral must be a function, not a number
integral is a numeric integration routine; the limits of integration must be numeric.
Check values of a by mouse over in breakpoint or removing the ; from the end of the line so it prints a. Based on the error, a is not a scalar float. You might need another max() or double() statement to transform the vector to a single value.
Solve Help : http://www.mathworks.com/help/symbolic/solve.html
Integral Help : http://www.mathworks.com/help/ref/integral.html

Derivative of Anonymous Function

I have the following anonymous function:
f = #(x)x^2+2*x+1
I'm using this so that I use it in the following way:
f(0) = 1
But what if I want to find the derivative of such a function while still keeping it's anonymous function capability? I've tried doing the following but it doesn't work:
f1 = #(x)diff(f(x))
but this just returns
[]
Any thoughts on how to accomplish this?
Of course I could manually do this in 3 seconds but that's not the point...
If you have symbolic math toolbox, you can use symbolic functions to achieve the desired as follows:
syms x
myFun=x^2+2*x+1;
f=symfun(myFun,x);
f1=symfun(diff(f),x);
%Check the values
f(2)
f1(2)
You should get 9 and 6 as answers.
When you do diff of a vector of n elements it just outputs another vector of n-1 elements with the consecutive differences.. so when you put a 1 element vector you get an empty one.
A way to go would be to decide an epsilon and use the Newton's difference quotient:
epsilon = 1e-10;
f = #(x) x^2+2*x+1;
f1 = #(x) (f(x+epsilon) - f(x)) / epsilon;
or just do the math and write down the formula:
f1 = #(x) 2*x+2;
http://en.wikipedia.org/wiki/Numerical_differentiation
#jollypianoman this works to me. Actually you need to say that the symfun has to be evaluate using eval command, then you get all the features of an anonymous function. the best is to read the example below...
clear
N0=1;N1=5;
N=#(t) N0+N1*sin(t);
syms t
Ndot=symfun(diff(N(t)),t);
Ndot_t=#(t) eval(Ndot);
Ndot_t(0)
ans = 5
Ndot_t(1)
ans = 2.7015
[tstop] = fsolve(Ndot_t,pi/3)
tstop =
1.5708
cheers,
AP

Evaluate Matlab symbolic function

I have a problem with symbolic functions. I am creating function of my own whose first argument is a string. Then I am converting that string to symbolic function:
f = syms(func)
Lets say my string is sin(x). So now I want to calculate it using subs.
a = subs(f, 1)
The result is sin(1) instead of number.
For 0 it works and calculates correctly. What should I do to get the actual result, not only sin(1) or sin(2), etc.?
You can use also use eval() to evaluate the function that you get by subs() function
f=sin(x);
a=eval(subs(f,1));
disp(a);
a =
0.8415
syms x
f = sin(x) ;
then if you want to assign a value to x , e.g. pi/2 you can do the following:
subs(f,x,pi/2)
ans =
1
You can evaluate functions efficiently by using matlabFunction.
syms s t
x =[ 2 - 5*t - 2*s, 9*s + 12*t - 5, 7*s + 2*t - 1];
x=matlabFunction(x);
then you can type x in the command window and make sure that the following appears:
x
x =
#(s,t)[s.*-2.0-t.*5.0+2.0,s.*9.0+t.*1.2e1-5.0,s.*7.0+t.*2.0-1.0]
you can see that your function is now defined by s and t. You can call this function by writing x(1,2) where s=1 and t=1. It should generate a value for you.
Here are some things to consider: I don't know which is more accurate between this method and subs. The precision of different methods can vary. I don't know which would run faster if you were trying to generate enormous matrices. If you are not doing serious research or coding for speed then these things probably do not matter.

Fitting model to data in matlab

i have some experimental data and a theoretical model which i would like to try and fit. i have made a function file with the model - the code is shown below
function [ Q,P ] = RodFit(k,C )
% Function file for the theoretical scattering from a Rod
% R = radius, L = length
R = 10; % radius in Å
L = 1000; % length in Å
Q = 0.001:0.0001:0.5;
fun = #(x) ( (2.*besselj(1,Q.*R.*sin(x)))./...
(Q.*R.*sin(x)).*...
(sin(Q.*L.*cos(x)./2))./...
(Q.*L.*cos(x)./2)...
).^2.*sin(x);
P = (integral(fun,0,pi/2,'ArrayValued',true))*k+C;
end
with Q being the x-values and P being the y-values. I can call the function fine from the matlab command line and it works fine e.g. [Q,P] = RodFit(1,0.001) gives me a result i can plot using plot(Q,P)
But i cannot figure how to best find the fit to some experimental data. Ideally, i would like to use the optimization toolbox and lsqcurvefit since i would then also be able to optimize the R and L parameters. but i do not know how to pass (x,y) data to lsqcurvefit. i have attempted it with the code below but it does not work
File = 30; % the specific observation you want to fit the model to
ydata = DataFiles{1,File}.data(:,2)';
% RAdius = linspace(10,1000,length(ydata));
% LEngth = linspace(100,10000,length(ydata));
Multiplier = linspace(1e-3,1e3,length(ydata));
Constant = linspace(0,1,length(ydata));
xdata = [Multiplier; Constant]; % RAdius; LEngth;
L = lsqcurvefit(#RodFit,[1;0],xdata,ydata);
it gives me the error message:
Error using *
Inner matrix dimensions must agree.
Error in RodFit (line 15)
P = (integral(fun,0,pi/2,'ArrayValued',true))*k+C;
Error in lsqcurvefit (line 199)
initVals.F = feval(funfcn_x_xdata{3},xCurrent,XDATA,varargin{:});
Caused by:
Failure in initial user-supplied objective function evaluation. LSQCURVEFIT cannot continue.
i have tried i) making all vectors/matrices the same length and ii) tried using .* instead. nothing works and i am giving the same error message
Any kind of help would be greatly appreciated, whether it is suggestion regading what method is should use, suggestions to my code or something third.
EDIT TO ANSWER Osmoses:
A really good point but i do not think that is the problem. just checked the size of the all the vectors/matrices and they should be alright
>> size(Q)
ans =
1 1780
>> size(P)
ans =
1 1780
>> size(xdata)
ans =
2 1780
>> size([1;0.001]) - the initial guess/start point for xdata (x0)
ans =
2 1
>> size(ydata)
ans =
1 1780
UPDATE
I think i have identified the problem. the function RodFit works fine when i specify the input directly e.g. [Q,P] = RodFit(1,0.001);.
however, if i define x0 as x0 = [1,0.001] i cannot pass x0 to the function
>> x0 = [1;0.001]
x0 =
1.0000
0.0010
>> RodFit(x0);
Error using *
Inner matrix dimensions must agree.
Error in RodFit (line 15)
P = (integral(fun,0,pi/2,'ArrayValued',true))*k+C;
The same happens if i use x0 = [1,0.001]
clearly, matlab is interpreting x0 as input for k only and attempts to multiplay a vector of length(ydata) and a vector of length(x0) which obviously fails.
So my problem is that i need to code so that lsqcurvefit understands that the first column of xdata and x0 is the k variable and the second column of xdata and x0 is the C variable. According to the documentation - Passing Matrix Arguments - i should be able to pass x0 as a matrix to the solver. The solver should then also pass the xdata in the same format as x0.
Have you tried (that's sometimes the mistake) looking at the orientation of your input data (e.g. if xdata & ydata are both row/column vectors?). Other than that your code looks like it should work.
I have been able to solve some of the problems. One mistake in my code was that the objective function did not use of vector a variables but instead took in two variables - k and C. changing the code to accept a vector solved this problem
function [ Q,P ] = RodFit(X)
% Function file for the theoretical scattering from a Rod
% R = radius, L = length
% Q = 0.001:0.0001:0.5;
Q = linspace(0.11198,4.46904,1780);
fun = #(x) ( (2.*besselj(1,Q.*R.*sin(x)))./...
(Q.*R.*sin(x)).*...
(sin(Q.*L.*cos(x)./2))./...
(Q.*L.*cos(x)./2)...
).^2.*sin(x);
P = (integral(fun,0,pi/2,'ArrayValued',true))*X(1)+X(2);
with the code above, i can define x0 as x0 = [1 0.001];, and pass that into RodFit and get a result. i can also pass xdata into the function and get a result e.g. [Q,P] = RodFit(xdata(2,:));
Notice i have changed the orientation of all vectors so that they are now row-vectors and xdata has size size(xdata) = 1780 2
so i thought i had solved the problem completely but i still run into problems when i run lsqcurvefit. i get the error message
Error using RodFit
Too many input arguments.
Error in lsqcurvefit (line 199)
initVals.F = feval(funfcn_x_xdata{3},xCurrent,XDATA,varargin{:});
Caused by:
Failure in initial user-supplied objective function evaluation. LSQCURVEFIT cannot continue.
i have no idea why - does anyone have any idea about why Rodfit recieves to many input arguments when i call lsqcurvefit but not when i run the function manual using xdata?

why isn't the result a scalar?

i'm stuck with this error:
In an assignment A(I) = B, the number of elements in B and I must be the same.
yres(1)=((u - uc).^2) + ((y - yc).^2) -(d.^2);
i don't understand, why this won't get a skalar?since the elements are all scalar. what should be changed to get a scalar?
best regards
edit: thanks sloede, all inputs are scalar, but i still get this error
In an assignment A(I) = B, the number of elements in B and I must be the
same.
Error in myfun (line 7)
yres(1)=sqrt(((u - uc).^2) + ((y - yc).^2) ) -d;
Error in fsolve (line 241)
fuser = feval(funfcn{3},x,varargin{:});
Error in modfsolve (line 26)
x= fsolve(#myfun,x0,options,uc,d,spacing_amplitude,spacing_width);
Caused by:
Failure in initial user-supplied objective function evaluation. FSOLVE
cannot continue.*
The "." before an operator means that the following operation should be applied element-wise and not on the vector as a whole. Thus
a = b.^2
will give you as a result all elements of b squared and saved back to a. Therefore, in your code statement above, if any of u, uc, y, yc, d are not scalar but a vector, your result will be a vector as well.
Otherwise there seems to be nothing wrong with your code.
read the documentation of fsolve: http://www.mathworks.nl/help/toolbox/optim/ug/fsolve.html
it states:
fun
The nonlinear system of equations to solve. fun is a function that accepts a vector x and returns a vector F, the nonlinear equations evaluated at x.
Obviously your function myfun doesn't handle vector input.
You can solve this by adding the following construction inside your function (and of course change it to your needs/your parameters):
function out = myfun(in)
if ~isscalar(in)
% assuming it's a matrix or vector
out = reshape(arrayfun(#myfun,in(:)),size(in));
else
% your actual function execution statements
out = dostuffon(in);
end
end
or properly vectorize your function (if that's possible)