Curve fitting in matlab - matlab

For example i have 5 point like this,
(1,1) (2,-1) (3,2) (4,-2) (5,2)
Now,
1) I want a function to interpolation these points in Matlab.
2) I want to Plot this function.
3) Read a number from input and write F(x) to output.
How can I do this??

To fit a polynom to given datapoints you can use polyfit(x,y,n) where x is a vector with points for x, y is a vector with points for y and n is the degree of the polynom. See example at Mathworks polyfit documentation
In your case:
x=[1,2,3,4,5];
y=[1,-1,-2,-2,2];
n=3;
p = polyfit(x,y,n)
And then to plot, taken from example
f = polyval(p,x);
plot(x,y,'o',x,f,'-')
Or, to make a prettier plot of the polynomial (instead of above plot)
xx=0:0.1:5;
yy = erf(xx);
f = polyval(p,xx);
plot(x,y,'o',xx,f,'-')

If you are not sure what a good fit would be and want to try out different fit, use the curve fitting toolbox, cftool. You will need to create two vectors with x and y coordinates and then you can play around with cftool.
Another option would be to use interp1 function for interpolation. See matlab documentation for more details.

If you want polynomial interpolation, take a look at the polyfit function. It is used generally for least-squares polynomial approximation, but if you choose the degree+1 to be the same as the number of points you are fitting it will still work for you. For interpolation as you probably know, the degree of the interpolant is equal to the number of points you have -1. So for your example points above you need a degree 4 polynomial. Here is a link to the mathworks documentation
http://www.mathworks.co.uk/help/matlab/ref/polyfit.html
If you split your points into 2 vectors of respective x and y coordinates, you can simply obtain your interpolating polynomial coefficients in a vector b where
b = polyfit(x,y,4)
and based on your data above, your x and y vectors are
x = [1 2 3 4 5];
y = [1 -1 2 -2 2]

Related

Three dimensional plot on matlab

I am trying to do a figure similar to the one attached.
I have exactly a (224x1) vector with dates (x-axis), a (10x1) vector with maturities (y-axis) and a (224x10) matrix with the values (z-axis).
I tried surf(X, Y, Z) but I got an error ("data dimensions must agree").
How can I combine this to make a plot like the one attached?
Thanks, V!
Edit: The second plot is the one I am getting using Luis Mendo's suggestion:
Use
surf(Y,X,Z)
From the documentation (emphasis added):
surf(x,y,Z) and surf(x,y,Z,C), with two vector arguments replacing
the first two matrix arguments, must have length(x) = nand
length(y) = m where [m,n] = size(Z). In this case, the vertices
of the surface patches are the triples (x(j), y(i), Z(i,j)).
Note that x corresponds to the columns of Z and y corresponds to
the rows.
Do
[X,Y]=meshgrid(x,y);
surf(X,Y,Z);
You need to create a meshgrid to be able to plot a surf. X ,Y and Z need to be the same size!

Assume that x, y, and z are Matlab arrays, plot the function e^(-x)sin(x) across the interval [0. 4pi]

x=linspace(0, 2*pi, 100);
y=sin(x);
z=exp(-x);
Given that x, y, and z are already initialized, how do I write a function that plots exp(-x)sin(x) across the interval [0, 4pi] without additional calls to sin or exp? Just need some help getting started.
Thanks to #Rayryeng for getting me started. I believe the following command more closely satisfies the question's specifications.
plot(x+x, z.*z.*y)
Well, you've already created arrays for sin and exp stored in y and z respectively. These arrays were created on the same domain as x. You just need to multiply both arrays together element-wise and plot the graph. It's as simple as doing:
plot(x, z.*y);
Here, .* stands for element-wise multiplication. If you were to do z*y, MATLAB interprets this as matrix multiplication where z and y are interpreted to be matrices. This is obviously not what you want.
However, your array of x only contains points from 0 to 2*pi. If you want to plot this from 0 to 4*pi, you have to modify your call to linspace:
x=linspace(0, 4*pi, 100); %// Change
y=sin(x);
z=exp(-x);
plot(x, z.*y);
Now, x will contain 100 points between 0 to 4*pi. For more information on basic MATLAB operations, check out this link: http://www.mathworks.com/help/matlab/matlab_prog/array-vs-matrix-operations.html. What you have asked falls into the basic realms of array and matrix operations.
Edit
In the spirit of your question, we can't modify linspace. You did something clever where we can simply scale our values of x by 2 or adding with x so that we have points going from 0 to 2*pi to 0 to 4*pi. Also, if we scale our points by 2, this means that our input argument into the function must also be scaled by 2. So, the final function we need to plot is:
y = exp(-2x)*sin(2x)
Noting your hint, exp(-2x) = exp(-x-x) = exp(-x)exp(-x). Further, note that sin(2x) performs a compression by a factor of 2 (tip of the hat goes to knedlsepp for noticing my blunder). Due to the periodic nature of sin(x), we know that elements will repeat after 2*pi, and so if you want to go to 4*pi, simply subsample y by a factor of 2 and then append these same elements to a new vector. Therefore, our expression for the function simplifies to:
y = exp(-x)exp(-x)sin(2x)
This leads to the answer alluded to knedlsepp:
plot(x+x, z.*z.*[y(1:2:end) y(1:2:end)]);
As such, you should consider changing your edits to match this answer instead. It isn't quite right with respect to the sin(x) part in your code.

Discrete surface integral with cumsum

I have a matrix z(x,y)
This is an NxN abitary pdf constructed from a unique Kernel density estimation (i.e. not a usual pdf and it doesn't have a function). It is multivariate and can't be separated and is discrete data.
I wan't to construct a NxN matrix (F(x,y)) that is the cumulative distribution function in 2 dimensions of this pdf so that I can then randomly sample the F(x,y) = P(x < X ,y < Y);
Analytically I think the CDF of a multivariate function is the surface integral of the pdf.
What I have tried is using the cumsum function in order to calculate the surface integral and tested this with a multivariate normal against the analytical solution and there seems to be some discrepancy between the two:
% multivariate parameters
delta = 100;
mu = [1 1];
Sigma = [0.25 .3; .3 1];
x1 = linspace(-2,4,delta); x2 = linspace(-2,4,delta);
[X1,X2] = meshgrid(x1,x2);
% Calculate Normal multivariate pdf
F = mvnpdf([X1(:) X2(:)],mu,Sigma);
F = reshape(F,length(x2),length(x1));
% My attempt at a numerical surface integral
FN = cumsum(cumsum(F,1),2);
% Normalise the CDF
FN = FN./max(max(FN));
X = [X1(:) X2(:)];
% Analytic solution to a multivariate normal pdf
p = mvncdf(X,mu,Sigma);
p = reshape(p,delta,delta);
% Highlight the difference
dif = p - FN;
error = max(max(sqrt(dif.^2)));
% %% Plot
figure(1)
surf(x1,x2,F);
caxis([min(F(:))-.5*range(F(:)),max(F(:))]);
xlabel('x1'); ylabel('x2'); zlabel('Probability Density');
figure(2)
surf(X1,X2,FN);
xlabel('x1'); ylabel('x2');
figure(3);
surf(X1,X2,p);
xlabel('x1'); ylabel('x2');
figure(5)
surf(X1,X2,dif)
xlabel('x1'); ylabel('x2');
Particularly the error seems to be in the transition region which is the most important.
Does anyone have any better solution to this problem or see what I'm doing wrong??
Any help would be much appreciated!
EDIT: This is the desired outcome of the cumulative integration, The reason this function is of value to me is that when you randomly generate samples from this function on the closed interval [0,1] the higher weighted (i.e. the more likely) values appear more often in this way the samples converge on the expected value(s) (in the case of multiple peaks) this is desired outcome for algorithms such as particle filters, neural networks etc.
Think of the 1-dimensional case first. You have a function represented by a vector F and want to numerically integrate. cumsum(F) will do that, but it uses a poor form of numerical integration. Namely, it treats F as a step function. You could instead do a more accurate numerical integration using the Trapezoidal rule or Simpson's rule.
The 2-dimensional case is no different. Your use of cumsum(cumsum(F,1),2) is again treating F as a step function, and the numerical errors resulting from that assumption only get worse as the number of dimensions of integration increases. There exist 2-dimensional analogues of the Trapezoidal rule and Simpson's rule. Since there's a bit too much math to repeat here, take a look here:
http://onestopgate.com/gate-study-material/mathematics/numerical-analysis/numerical-integration/2d-trapezoidal.asp.
You DO NOT need to compute the 2-dimensional integral of the probability density function in order to sample from the distribution. If you are computing the 2-d integral, you are going about the problem incorrectly.
Here are two ways to approach the sampling problem.
(1) You write that you have a kernel density estimate. A kernel density estimate is a special case of a mixture density. Any mixture density can be sampled by first selecting one kernel (perhaps differently or equally weighted, same procedure applies), and then sampling from that kernel. (That applies in any number of dimensions.) Typically the kernels are some relatively simple distribution such as a Gaussian distribution so that it is easy to sample from it.
(2) Any joint density P(X, Y) is equal to P(X | Y) P(Y) (and equivalently P(Y | X) P(X)). Therefore you can sample from P(Y) (or P(X)) and then from P(X | Y). In order to sample from P(X | Y), you will need to integrate P(X, Y) along a line Y = y (where y is the sampled value of Y), but (this is crucial) you only need to integrate along that line; you don't need to integrate over all values of X and Y.
If you tell us more about your problem, I can help with the details.

How can I find equation of a plot connecting data points in Matlab?

I have various plots (with hold on) as show in the following figure:
I would like to know how to find equations of these six curves in Matlab. Thanks.
I found interactive fitting tool in Matlab simple and helpful, though somewhat limited in scope:
The graph above seems to be linear interpolation. Given vectors X and Y of data, where X contains the arguments and Y the function points, you could do
f = interp1(X, Y, x)
to get the linearly interpolated value f(x). For example if the data is
X = [0 1 2 3 4 5];
Y = [0 1 4 9 16 25];
then
y = interp1(X, Y, 1.5)
should give you a very rough approximation to 1.5^2. interp1 will match the graph exactly, but you might be interested in fancier curve-fitting operations, like spline approximations etc.
Does rxns stand for reactions? In that case, your curves are most likely exponential. An exponential function has the form: y = a*exp(b * x) . In your case, y is the width of mixing zone, and x is the time in years. Now, all you need to do is run exponential regression in Matlab to find the optimal values of parameters a and b, and you'll have your equations.
The advice, though there might be better answer, from me is: try to see the rate of increase in the curve. For example, cubic is more representative than quadratic if the rate of increase seems fast and find the polynomial and compute the deviation error. For irregular curves, you might try spline fitting. I guess there is also a toolbox in matlab for spline fitting.
There is a way to extract information with the current figure handle (gcf) from you graph.
For example, you can get the series that were plotted in a graph:
% Some figure is created and data are plotted on it
figure;
hold on;
A = [ 1 2 3 4 5 7] % Dummy data
B = A.*A % Some other dummy data
plot(A,B);
plot(A.*3,B-1);
% Those three lines of code will get you series that were plotted on your graph
lh=findall(gcf,'type','line'); % Extract the plotted line from the figure handle
xp=get(lh,'xdata'); % Extract the Xs
yp=get(lh,'ydata'); % Extract the Ys
There must be other informations that you can get from the "findall(gcf,...)" methods.

Generate Contour Given X, Y and Z vectors

Given 3 vector-pair, X, Y and Z, how to generate the contour? I understand that we need to make use of the contour plot. But the thing is that we need to pass in a 2x2 matrix for this argument, which presumably, is a matrix of Z corresponding to each X,Y pair. But this would mean that I have to go extra miles to create such a matrix by using griddata interpolation first before talking about contour generation.
Is there any other more succinct method?
Yes. Use the Tricontour tool. It is found on the file exchange (on Matlab Central.) This does the contouring as you desire directly, without forcing you to use meshgrid and griddata.
MATLAB addresses this need of yours fairly succinctly.
What you need to do is use meshgrid to two-dimensionalize your X and Y vectors. Here is a simple example to demonstrate how to generate a contour plot of z = sin (x^2 + x*y^2):
x = -10:0.1:10;
y = -10:0.1:10;
[x,y] = meshgrid(x,y);
z = sin(x.^2+x.*y.^2);
contour(x,y,z)
Note the use of the .^ and .* notations, which forces MATLAB to conduct an element-by-element evaluation of the z matrix, making it 2D in the process.