2d polynomial fitting to table data MATLAB - matlab

I am trying to use 2D polynomial fitting for my table data, my data format is exactly like the link below:
http://www.mathworks.de/help/toolbox/curvefit/brx2ldg-1.html#bso46rp-1
I mean I have vector X with length n, Y with length m and m*n Matrix Z, I would like to fit 5 degree 2d polynomial to my data,
I am wondering that is there any syntax in MATLAB for solving this problem? like SFIT command in IDL, http://star.pst.qub.ac.uk/idl/SFIT.html
I have cftool and sftool, but it seems that they don't work for this purpose or most probably I don't know how to employ them.
and I know that there some m.file which people share in MATLAB Mathworks file exchange, please if you know one works properly, suggest me.
I'd appreciate any help and comment.

You can use polyfitn from file exchange and re-format your data in order to have 3 MxN x,y,z vectors.
Example:
Assume you have a table data of the form
N = 100; M = 80;
x = linspace(0, 1, M);
y = linspace(0, 1, N).';
z = bsxfun(#franke, x, y);
Create meshgrid for x, and y instead
N = 100; M = 80;
[x, y] = meshgrid(0:1:N, 0:1:M);
z = bsxfun(#franke, x, y);
(Note that unique(x) and unique(y) will give you the original linspace values of your table rows and columns.)
Use polyfitn to get the 5-degree polynomial coefficients
p = polyfitn([x(:),y(:)], z(:), 5);
You can additionally convert the result into a symbolic form to view the polynomial using the provided polyn2sym(p)
>> pretty(polyn2sym(p))
5 4 4 3 2
90264379051097 X1 2537627280433653 X1 X2 7778045812403061 X1 6982058230382053 X1 X2
- ------------------------- - -------------------------- + ------------------------ - -------------------------- + ...
2417851639229258349412352 38685626227668133590597632 604462909807314587353088 77371252455336267181195264

Related

Rotate discrete dataset Octave

I have a discrete dataset, X=[x1,x2,..,x12] & Y=[y1,y2,...,y12]. X ranges from [-25, 0] and Y ranges from [1e-6, 1e0]. X does not increase uniformly - as x approaches a value of 0, data sampling density increases from increments of 2.5 to increments of 1. Each x value is units of cm. I cannot get a good fit to the data from fitting a function (I've tried quite a few). I'm left with the discrete data. My need is to sweep the X, Y data completly around the Z axis and put the resulting swept data values into a matrix Z of size (51, 51). I've tried using the cylinder function, [u,v,w] = cylinder(Y) thinking I could extract the data or create a matrix Z from [u, v, w]. I can't seem to sort that out. surf(u,v,w) plots almost correctly - the scaling on the (u, v) axes ranges from [-1, 1] instead of [-25, 25]. This is, I assume, because I'm using cylinder(Y). When I try [u,v,w] = cylinder(X,Y) I get, error: linspace: N must be a scalar. It seems like there should be a better way then my approach of using cylinder to take the X & Y data, interpolate between points (to fill Z where data isn't), rotate it, and put the result into a matrix Z. Any suggestions are welcome. I'm using Octave 6.3.0. Thank you in advance.
Create a matrix R containing distance from origin values.
Use for loops and single value interpolation to cover the R space.
Place the interpolated values into the matrix Z.
% Original data X = [-25,-22.5,...,0]; size(X) = 1 12
% Original data Y = [1e-6, 1.3e-6,...,1] size(Y) = 1 12
u = [-range(X):1:range(X)]; v = [-range(X):1:range(X)]';
R = -sqrt(u.^2.+v.^2);
Z = zeros( 2 .* range(X) + 1);
for i = 1:size(R,1)
for j = 1:size(R,2)
if R(i,j) < min(X); Z(i,j) = 0; endif
if R(i,j) >= min(X); Z(i,j) = interp1(X,Y,R(i,j)); endif
endfor
endfor

Using meshgrid in MATLAB when the function has matrix operations

I need to plot level surfaces of a 3 variable function. The variables are in a column vector X = [x, y, z]^t. The function is f(X) = X^t * A * X. Where ^t means transpose and A is a 3x3 constant matrix. I know for a fact that A is symmetric and therefore diagonalizable, i.e. A = V * D * V^t. Just in case it turns out to be useful.
I intend to use isosurface to get the points of the function where it equals a certain level and then use patch to plot.
However I can't figure out how to compute the value of the function for every point in the grid. Ideally I'd like to do
x = linspace(-1, 1,10); y=x; z = x;
[XX,YY,ZZ]=meshgrid(x,y,z);
f = [XX YY ZZ]'*A*[XX YY ZZ];
level = 1;
s = isosurface(XX,YY,ZZ,f,level);
patch(s, 'EdgeColor','none','FaceColor','blue');
but this won't work obviously because of the sizes of XX and A. What I've done so far is do the math myself to obtain the function as a polynomial of XX, YY and ZZ but it's incredibly ugly and not practical.
Anybody knows how to do this? Thanks!
If I understand correctly, this does that you want. In the following explanation I will use 10x10x10 points as given in your example (although the code works for any number of points). Also, I define a random 3x3 matrix A.
Once XX, YY and ZZ have been generated as 10x10x10 arrays (step 1), the key is to build a 1000x3 matrix in which the first column is x coordinate, the second is y and the third is z. This is variable XYZ in the code below (step 2).
Since XYZ is a matrix, not a vector, the function f can't be computed using matrix multiplication. But it can be obtained efficiently with bsxfun. First compute an intermediate 1000x3x3 variable (XYZ2) with all 3x3 products of coordinates for each of the 1000 points (step 3). Then reshape it into a 1000x9 matrix and multiply by the 9x1 vector obtained from linearizing A (step 4).
The f thus obtained has size 1000x1. You need to reshape it into a 10x10x10 array to match XX, YY and ZZ (step 5). Then you can use isosurface as per your code (step 6).
A = rand(3);
x = linspace(-1, 1,10); y = x; z = x;
[XX,YY,ZZ] = meshgrid(x,y,z); %// step 1
XYZ = [XX(:) YY(:) ZZ(:)]; %// step 2
XYZ2 = bsxfun(#times, XYZ, permute(XYZ, [1 3 2])); %// step 3
f = reshape(XYZ2,[],numel(A))*A(:); %// step 4
f = reshape(f, size(XX)); %// step 5
level = 1;
s = isosurface(XX,YY,ZZ,f,level);
patch(s, 'EdgeColor','none','FaceColor','blue'); %// step 6
I suspect that you could explicitly define your function as
ffun = #(x,y,z) [x y z]*A*[x; y; z];
then use arrayfun to apply this function to each element of your coordinate vectors:
f = arrayfun(ffun,XX,YY,ZZ);
This will return f(i)=ffun(XX(i),YY(i),ZZ(i)) for each i in 1:numel(XX), which I think is what you are after. The output f will have the same shape as your input arrays, which seems perfectly fine to use with isosurface later.

using size of scatter points to weight line of best fit in matlab

Is it possible to use the size (s) of the points to 'weight' the line of best fit?
x = [1 2 3 4 5];
y = [2 4 5 3 4];
s = [10 15 20 2 5];
scatter(x,y,s)
hold on
weight = s;
p = polyfit(x,y,1); %how do I take into account the size of the points?
f = polyval(p,x);
plot(x,f,'-r')
Using Marcin's suggestion, you can incorporate lscov into polyfit. As the documentation explains, polynomial fitting is done by computing the Vandermonde matrix V of x, and then executing p = V\y. This is the standard formalism of any least-squares solution, and lends itself to weighted-least-squares in MATLAB through lscov.
Taking your x, y and weight vectors, instead of calling polyfit(x,y,n) you can do the following:
% Construct Vandermonde matrix. This code is taken from polyfit.m
V(:,n+1) = ones(length(x),1,class(x));
for j = n:-1:1
V(:,j) = x.*V(:,j+1);
end
% Solve using weighted-least-squares
p = lscov(V,y,weight);
You can even go one step further, and modify polyfit.m itself to include this functionality, or add another function polyfitw.m if you are not inclined to modify original MATLAB functions. Note however that polyfit has some more optional outputs for structure, computed using QR decomposition as detailed in the documentation. Generalization of these outputs to the weighted case will require some more work.
x = (1:10)';
y = (3 * x + 5) + rand(length(x),1)*5;
w = ones(1,length(y));
A = [x ones(length(x),1)];
p = lscov(A,y,w);
plot(x,y,'.');
hold on
plot(x,p(1)*x + p(2),'-r');

Using matlabs regress like polyfit

I have:
x = [1970:1:2000]
y = [data]
size(x) = [30,1]
size(y) = [30,1]
I want:
% Yl = kx + m, where
[k,m] = polyfit(x,y,1)
For some reason i have to use "regress" for this.
Using k = regress(x,y) gives some totally random value that i have no idea where it comes from. How do it?
The number of outputs you get in "k" is dependant on the size of input X, so you will not get both m and k just by putting in your x and y straight. From the docs:
b = regress(y,X) returns a p-by-1 vector b of coefficient estimates for a multilinear regression of the responses in y on the predictors in X. X is an n-by-p matrix of p predictors at each of n observations. y is an n-by-1 vector of observed responses.
It is not exactly stated, but the example in the help docs using the carsmall inbuilt dataset shows you how to set this up. For your case, you'd want:
X = [ones(size(x)) x]; % make sure this is 30 x 2
b = regress(y,X); % y should be 30 x 1, b should be 2 x 1
b(1) should then be your m, and b(2) your k.
regress can also provide additional outputs, such as confidence intervals, residuals, statistics such as r-squared, etc. The input remains the same, you'd just change the outputs:
[b,bint,r,rint,stats] = regress(y,X);

find polynomial equation from array with matlab

I've some x.mat and y.mat.
And I would like to find the polynomial equation from this.
I've tried
p = polyfit(x,y,3);
with y2 = p(1)*x.^3 + p(2)*x.^2 + p(3)*x
but my y2 is not equal to the original y . What is wrong ?
Thanks you
As radarhead wrote in his comment, you forgot the coefficient of zero degree (p(4) here).
Assuming x and y are vectors of same length n, polyfit(x,y,n-1) will return a vector containing the coefficients of the interpolating polynomial (of degree n-1) in descending order.
Then, the value of the interpolating polynomial at a point z will be given by:
p(1)*z^3 + p(2)*z^2 + p(3)*z + p(4)
Don't forget p(4)! As Bas suggested, you can use the polyval function to easily compute the value of a polynomial at a a given point:
polyval(p,z);
To illustrate this, see the code below, which generates 4 data points, plots those points and the polynomial interpolating them:
n = 4;
x = sort(rand(n,1));
y = rand(n,1);
p = polyfit(x,y,n-1);
figure
hold on
plot(x,y,'bo');
xx=linspace(x(1),x(end),100);
plot(xx,polyval(p,xx),'r');
hold off