plot matlab function handle that outputs vector - matlab

So I have a matlab function I wrote that takes in a number and returns an array of numbers (transposed). I need to plot this function. I was trying to use fplot but it was giving me errors:
Error in fplot (line 105)
x = xmin+minstep; y(2,:) = feval(fun,x,args{4:end});
Am I using the wrong plot function?
the function solves an equation of motion problem. I have this diff eq:
Mx'' + Cx'+ Kx = 0
where M, C, and K are 4x4 matrices and my function solves the general solution and outputs a vector of 4 values.

I fixed my problem by changing my function to accept an array of t values and then I used the plot function instead of fplot

Related

fplot not plotting an exponential function

I'm trying to plot this function 0.5*sinc(n/2)*e^(0.5*j*n*pi*t) using this code:
n = 1;
x2t = #(t) 0.5*sinc(n/2)* exp(sqrt(-1)*n*pi*0.5*t);
fplot(x2t);
but I only get blank results, what's the problem?
Your function produces a complex result, and fplot does not plot that properly. Instead, you could plot the real and imaginary components separately:
n = 1;
x2t = #(t) 0.5*sin(n/2)/(n/2) * exp(1i*n*pi*0.5*t);
fplot(#(t)real(x2t(t)));
hold on
fplot(#(t)imag(x2t(t)));
Notice that I replaced sinc(n/2) with sin(n/2)/(n/2), since I don't have the sinc function in my version of MATLAB. I also replaced sqrt(-1) with the simpler 1i.

Plot log(n over k)

I've never used Matlab before and I really don't know how to fix the code. I need to plot log(1000 over k) with k going from 1 to 1000.
y = #(x) log(nchoosek(1000,x));
fplot(y,[1 1000]);
Error:
Warning: Function behaves unexpectedly on array inputs. To improve performance, properly
vectorize your function to return an output with the same size and shape as the input
arguments.
In matlab.graphics.function.FunctionLine>getFunction
In matlab.graphics.function.FunctionLine/updateFunction
In matlab.graphics.function.FunctionLine/set.Function_I
In matlab.graphics.function.FunctionLine/set.Function
In matlab.graphics.function.FunctionLine
In fplot>singleFplot (line 241)
In fplot>#(f)singleFplot(cax,{f},limits,extraOpts,args) (line 196)
In fplot>vectorizeFplot (line 196)
In fplot (line 166)
In P1 (line 5)
There are several problems with the code:
nchoosek does not vectorize on the second input, that is, it does not accept an array as input. fplot works faster for vectorized functions. Otherwise it can be used, but it issues a warning.
The result of nchoosek is close to overflowing for such large values of the first input. For example, nchoosek(1000,500) gives 2.702882409454366e+299, and issues a warning.
nchoosek expects integer inputs. fplot uses in general non-integer values within the specified limits, and so nchoosek issues an error.
You can solve these three issues exploiting the relationship between the factorial and the gamma function and the fact that Matlab has gammaln, which directly computes the logarithm of the gamma function:
n = 1000;
y = #(x) gammaln(n+1)-gammaln(x+1)-gammaln(n-x+1);
fplot(y,[1 1000]);
Note that you get a plot with y values for all x in the specified range, but actually the binomial coefficient is only defined for non-negative integers.
OK, since you've gotten spoilers for your homework exercise anyway now, I'll post an answer that I think is easier to understand.
The multiplicative formula for the binomial coefficient says that
n over k = producti=1 to k( (n+1-i)/i )
(sorry, no way to write proper formulas on SO, see the Wikipedia link if that was not clear).
To compute the logarithm of a product, we can compute the sum of the logarithms:
log(product(xi)) = sum(log(xi))
Thus, we can compute the values of (n+1-i)/i for all i, take the logarithm, and then sum up the first k values to get the result for a given k.
This code accomplishes that using cumsum, the cumulative sum. Its output at array element k is the sum over all input array elements from 1 to k.
n = 1000;
i = 1:1000;
f = (n+1-i)./i;
f = cumsum(log(f));
plot(i,f)
Note also ./, the element-wise division. / performs a matrix division in MATLAB, and is not what you need here.
syms function type reproduces exactly what you want
syms x
y = log(nchoosek(1000,x));
fplot(y,[1 1000]);
This solution uses arrayfun to deal with the fact that nchoosek(n,k) requires k to be a scalar. This approach requires no toolboxes.
Also, this uses plot instead of fplot since this clever answer already addresses how to do with fplot.
% MATLAB R2017a
n = 1000;
fh=#(k) log(nchoosek(n,k));
K = 1:1000;
V = arrayfun(fh,K); % calls fh on each element of K and return all results in vector V
plot(K,V)
Note that for some values of k greater than or equal to 500, you will receive the warning
Warning: Result may not be exact. Coefficient is greater than 9.007199e+15 and is only accurate to 15 digits
because nchoosek(1000,500) = 2.7029e+299. As pointed out by #Luis Mendo, this is due to realmax = 1.7977e+308 which is the largest real floating-point supported. See here for more info.

How to use lsqcurvefit to fit a rational function?

I want to fit a rational function using the curve fitting technique in MATLAB.
I am trying to use lsqcurvefit to reproduce a rational function M, which takes 5 inputs, with the data outputted from the exact function C. I think I am close to getting the plots; however, when I use lsqcurvefit, I keep getting an error saying:
LSQCURVEFIT requires the following inputs to be of data type double: 'YDATA'.
Below is my code:
% Define range for k
k= linspace(1E-10,1.5,100);
% Exact Function C(k)
C= #(k)(0.5*((1i*k+0.135).* (1i*k+0.651)))./((1i*k+0.0965).* (1i*k+0.4555));
% Cget function used to extract real and imaginary numbers and stacks the result
Cget= #(k)[real(C(k)); imag(C(k))];
%Call function Cget(k) to get stacked real and imaginary values
realimag =Cget(k);
% Create an initial guess
x0=[1,1];
% Define parameters
a1=0.2; a2=0.7; b1=0.1; b2=0.5;
% Define approximated function
M= #(a1,a2,b1,b2,k)(0.5*((1i*k+a1).* (1i*k+a2)))./((1i*k+b1).* (1i*k+b2));
Mget1= #(a1,a2,b1,b2,k)[real(M(a1,a2,b1,b2,k)); imag(M(a1,a2,b1,b2,k))];
T=Mget1(a1,a2,b1,b2,k);
%Find best fit curve
x=lsqcurvefit(M,x0,k,C)
How can I fit reproduce M, given the exact function C?
The variable C should be entered as a double array so that the function should get the input range and use it in the calculation.
% Exact Function C(k)- Bessel Function
C0 = (0.5*((1i*k+0.135).* (1i*k+0.651)))./((1i*k+0.0965).* (1i*k+0.4555));
and parameters of x could be entered as an array with 4 values.
M = #(x,k)(0.5*((1i*k+x(1)).* (1i*k+x(2))))./((1i*k+x(3)).* (1i*k+x(4)));
and x0 should have 4 values.
x0 = [1,1,1,1];
%Find best fit curve
x = lsqcurvefit(M,x0,k,C0)

Symbolic multiplication of functions

I get an error when trying to multiply a symbolic function and a symbolic integral:
eta02=vpa(-i*omega2/((i*alpha2*lambda_0)^(2/3)),prec); %whatever
eta_inf2=vpa(vpa(((i*alpha2*lambda_0)^(1/3))*YMAX,prec)+eta02,prec); %whatever
%%
syms lu
syms x
myairyf(lu)= airy(lu);
mybairyf(lu)=airy(2,lu);
Gi2(x)=-(mybairyf*int(myairyf,lu,[eta_inf2,(x)])-myairyf*int(mybairyf,lu,[eta02,(x)]));
Error using sym/subsindex (line 769)
Invalid indexing or function definition. When defining a function, ensure that the arguments are symbolic variables and the body of the
function is a SYM expression. When indexing, the input must be numeric, logical, or ':'.
How can this be done? Additionally, how could I plot Gi2(x), given that it's symbolic?
By using the symfun function.
Gi2 = sumfun(-(mybairyf*int(myairyf,lu,[eta_inf2,(x)])-myairyf*int(mybairyf,lu,[eta02,(x)])), x);
Now Gi2(val) will evaluate the function for the value ´val´
Plotting then can be done by evaluating this function for the values you want to plot for, storing them in a vector, and plot the x and y values.
xvals = linspace(0,10,100);
yvals = Gi2(xvals);
figure
plot(xvals,vals)

Plot symbolic derivative of a built-in MATLAB function

I am trying to compute the second derivative of the airy function. Only its first derivative is a predefined function in MATLAB (airy(1,x))
Is there a way to compute its symbolic derivative? without resorting to finite differences, etc
I tried this
syms x
aiprime = #(x) airy(1,x);
aisecond = diff(airy(1,x));
plot(-10:0.01:10,aiprime,aisecond)
But didn't work.
Error using plot
Invalid second data argument
The problem is your plot statement. You specify the desired x-data, but did not evaluate your function in these points:
syms x
aiprime(x) = airy(1,x); % I would define it as a symbolic function instead of a function handle, although it works too.
aisecond(x) = diff(airy(1,x)); % Define as a function, to be able to evaluate the function easily
xs = -10:0.01:10; % define your desired x points
plot(xs,aiprime(xs),xs, aisecond(xs)) % evaluate your functions and plot data