find polynomial equation from array with matlab - 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

Related

Obtaining a 2D interpolation polynomial in Matlab

I have three vectors, one of X locations, another of Y locations and the third is a f(x, y). I want to find the algebraic expression interpolation polynomial (using matlab) since I will later on use the result in an optimization problem in AMPL. As far as I know, there are not any functions that return the interpolation polynomial.
I have tried https://la.mathworks.com/help/matlab/ref/griddedinterpolant.html, but this function only gives the interpolated values at certain points.
I have also tried https://la.mathworks.com/help/matlab/ref/triscatteredinterp.html as sugested in Functional form of 2D interpolation in Matlab, but the output isn't the coefficents of the polynomial. I cannot see it, it seems to be locked inside of a weird variable.
This is a small program that I have done to test what I am doing:
close all
clear
clc
[X,Y] = ndgrid(1:10,1:10);
V = X.^2 + 3*(Y).^2;
F = griddedInterpolant(X,Y,V,'cubic');
[Xq,Yq] = ndgrid(1:0.5:10,1:0.5:10);
Vq = F(Xq,Yq);
mesh(Xq,Yq,Vq)
figure
mesh(X, Y, V)
I want an output that instead of returning the value at grid points returns whatever it has used to calculate said values. I am aware that it can be done in mathematica with https://reference.wolfram.com/language/ref/InterpolatingPolynomial.html, so I find weird that matlab can't.
You can use fit if you have the curve fitting toolbox.
If it's not the case you can use a simple regression, if I take your example:
% The example data
[X,Y] = ndgrid(1:10,1:10);
V = X.^2 + 3*(Y).^2;
% The size of X
s = size(X(:),1);
% Let's suppose that you want to fit a polynome of degree 2.
% Create all the possible combination for a polynome of degree 2
% cst x y x^2 y^2 x*y
A = [ones(s,1), X(:), Y(:), X(:).^2, Y(:).^2, X(:).*Y(:)]
% Then using mldivide
p = A\V(:)
% We obtain:
p =
0 % cst
0 % x
0 % y
1 % x^2
3 % y^2
0 % x*y

Why can't I use 'scatter3' here?

[X,Y] = meshgrid(-8:.5:8);
R = sqrt(X.^2 + Y.^2) + eps;
Z = sin(R)./R;
scatter3(X,Y,Z)
Error using scatter3 (line 64)
X, Y and Z must be vectors of the same length.
Matlab R2018b windows x64
As shown in the documentation, X, Y, Z must be vectors. (When you enter an article on mathworks from Googling, say, "matlab scatter3", you will first see the syntax for the function. Blue text means hyperlink. All the inputs are linked to the bottom of the page where their exact typing is defined.)
The reason is (probably) as follows.
As stated in the documentation, scatter3 puts circles (or other symbols of your choice if you modify the graphic object) on 3D coordinates of your choice. The coordinates are the ith element of X, Y, Z respectively. For example, the x-coordinate of the 10th point you wish to plot in 3D is X(10).
Thus it is not natural to input matrices into scatter3. If you know X(i), Y(i), Z(i) are indeed the coordinates you want to plot for all i, even though your X, Y, Z are not vectors for some reason, you need to reshape X, Y, Z.
In order to reshape, you can simply do scatter3(X(:), Y(:), Z(:)) which tells Matlab to read your arrays as a vectors. (You should look up in what order this is done. But it is in the intuitive way.) Or you can use reshape. Chances are: reshape is faster for large data set. But ofc (:) is more convenient.
The following should work:
[X,Y] = meshgrid(-8:.5:8);
R = sqrt(X.^2 + Y.^2) + eps;
Z = sin(R)./R;
X = X(:);
Y = Y(:);
Z = Z(:);
scatter3(X,Y,Z)
scatter3 needs vectors, not matrices as far as I can see here
this is my result:
If you want to use meshgrid without reshaping the matrices you have to use plot3 and the 'o' symbol. So you can get a similar result with:
plot3(X,Y,Z,'o')
EDIT:
A question that arose in association with this post was, which of the following methods is more efficient in terms of computation speed: The function reshape(X,[],1), suggested by me, or the simpler colon version X(:), suggested by #Argyll.
After timing the reshape function versus the : method, I have to admit that the latter is more efficient.
I added my results and the code I used to time both functions:
sizes = linspace(100,10000,100);
time_reshape = [];
time_col = [];
for i=1:length(sizes)
X = rand(sizes(i)); % Create random squared matrix
r = #() ResFcn(X);
c = #() ColFcn(X);
time_reshape = [time_reshape timeit(r)/1000] % Take average of 1000 measurements
time_col = [time_col timeit(c)/1000] % Take average of 1000 measurements
end
figure()
hold on
grid on
plot(sizes(2:end), time_col(2:end))
plot(sizes(2:end), time_reshape(2:end))
legend("Colon","Reshape","Location","northwest")
title("Comparison: Reshape vs. Colon Method")
xlabel("Length of squared matrix")
ylabel("Average execution time [s]")
hold off
function res = ResFcn(X)
for i = 1:1000 % Repeat 1000 times
res = reshape(X,[],1);
end
end
function res = ColFcn(X)
for i = 1:1000 % Repeat 1000 times
res = X(:);
end
end

How plot a two-dimensional function in three-dimensional space with MATLAB?

I want to plot a two-dimensional function of the polar coordinates r and theta in three-dimensional cartesian coordinates. I have that (sorry about bad maths formatting, LaTeX not compatible, it seems)
f(r,theta) = r/2 * (cos(theta - pi/4) + sqrt(1 + 1/2 * cos(2*theta)))
Converting r and theta to cartesian coordinates
x = r * cos(theta), y = r * sin(theta)
Further, the domain is -1<r<1 and 0<theta<2 * pi, which I define by
r = -1:2/50:1;
and
theta = 0:2*pi/50:2*pi;
giving me two vectors of the same dimensions.
I can define the x and y values used for plotting as row vectors by
x = r. * cos(theta);
and
y = r. * sin(theta);
So now I need to define the z values, which will depend on the values of x and y. I thought I should make a 101x101 where each matrix element contains a data point of the final surface. But how should I do this? I thought about using a double for loop:
for i=1:numel(r)
for j=1:numel(theta)
z(i,j) = r(i)/2 .* cos(theta(j) - pi/4) + r(i).*sqrt(1 + 1/2 * cos(2.*theta(j)));
end
end
Then simply surf(z)
While this definitely gives me a surface, it gives me the incorrect surface! I don't know what is happening here. The incorrect surface is given in Figure 1, while the correct one is given in Figure 2. Can anyone help me out? For reference, the correct surface was plotted with GeoGebra, using
A = Function[<expression 1>, <Expresison 2>, <Expression 3>, <var 1>, <start>, <stop>, <var 2>, <start>, <stop>]
Figure 1. Incorrect surface.
Figure 2. Correct surface.
As others have said, you can use meshgrid to make this work.
Here's your example using gridded r and theta and an anonymous function to replace the double loop:
r = -1:2/50:1;
theta = 0:2*pi/50:2*pi;
% define anonymous function f(r,theta)
f = #(r,theta) r/2 .* (cos(theta - pi/4) + sqrt(1 + 1/2 .* cos(2.*theta)));
% generate grids for r and theta
[r, theta] = meshgrid(r,theta);
% calculate z from gridded r and theta
z = f(r,theta);
% convert r,theta to x,y and plot with surf
x = r.*cos(theta);
y = r.*sin(theta);
surf(x,y,z);
You need to use meshgrid to get matrix coordinates if you want to use surf. Taking your x and y (lower case), call
[X,Y] = meshgrid(x,y);
Then X and Y (upper case) will have the same values as you gave it, but laid out in the two-dimensional array as expected by surf. Loop over the indices here and compute your Z, which should have all(size(Z) == size(X)).
https://www.mathworks.com/help/matlab/ref/meshgrid.html

USE DIFFERENTIAL MATRIX OPERATOR TO SOLVE ODE

We were asked to define our own differential operators on MATLAB, and I did it following a series of steps, and then we should use the differential operators to solve a boundary value problem:
-y'' + 2y' - y = x, y(0) = y(1) =0
my code was as follows, it was used to compute this (first and second derivative)
h = 2;
x = 2:h:50;
y = x.^2 ;
n=length(x);
uppershift = 1;
U = diag(ones(n-abs(uppershift),1),uppershift);
lowershift = -1;
L= diag(ones(n-abs(lowershift),1),lowershift);
% the code above creates the upper and lower shift matrix
D = ((U-L))/(2*h); %first differential operator
D2 = (full (gallery('tridiag',n)))/ -(h^2); %second differential operator
d1= D*y.'
d2= ((D2)*y.')
then I changed it to this after posting it here and getting one response that encouraged the usage of Identity Matrix, however I still seem to be getting no where.
h = 2;
n=10;
uppershift = 1;
U = diag(ones(n-abs(uppershift),1),uppershift);
lowershift = -1;
L= diag(ones(n-abs(lowershift),1),lowershift);
D = ((U-L))/(2*h); %first differential operator
D2 = (full (gallery('tridiag',n)))/ -(h^2); %second differential operator
I= eye(n);
eqn=(-D2 + 2*D - I)*y == x
solve(eqn,y)
I am not sure how to proceed with this, like should I define y and x, or what exactly? I am clueless!
Because this is a numerical approximation to the solution of the ODE, you are seeking to find a numerical vector that is representative of the solution to this ODE from time x=0 to x=1. This means that your boundary conditions make it so that the solution is only valid between 0 and 1.
Also this is now the reverse problem. In the previous post we did together, you know what the input vector was, and doing a matrix-vector multiplication produced the output derivative operation on that input vector. Now, you are given the output of the derivative and you are now seeking what the original input was. This now involves solving a linear system of equations.
Essentially, your problem is now this:
YX = F
Y are the coefficients from the matrix derivative operators that you derived, which is a n x n matrix, X would be the solution to the ODE, which is a n x 1 vector and F would be the function you are associating the ODE with, also a n x 1 vector. In our case, that would be x. To find Y, you've pretty much done that already in your code. You simply take each matrix operator (first and second derivative) and you add them together with the proper signs and scales to respect the left-hand side of the ODE. BTW, your first derivative and second derivative matrices are correct. What's left is adding the -y term to the mix, and that is accomplished by -eye(n) as you have found out in your code.
Once you formulate your Y and F, you can use the mldivide or \ operator and solve for X and get the solution to this linear system via:
X = Y \ F;
The above essentially solves the linear system of equations formed by Y and F and will be stored in X.
The first thing you need to do is define a vector of points going from x=0 to x=1. linspace is probably the most suitable where you can specify how many points we want. Let's assume 100 points for now:
x = linspace(0,1,100);
Therefore, h in our case is just 1/100. In general, if you want to solve from the starting point x = a up to the end point x = b, the step size h is defined as h = (b - a)/n where n is the total number of points you want to solve for in the ODE.
Now, we have to include the boundary conditions. This simply means that we know the beginning and ending of the solution of the ODE. This means that y(0) = y(1) = 0. As such, we make sure that the first row of Y has only the first column set to 1 and the last row of Y has only the last column set to 1, and we'll set the output position in F to both be 0. This symbolizes that we already know the solution at these points.
Therefore, your final code to solve is just:
%// Setup
a = 0; b = 1; n = 100;
x = linspace(a,b,n);
h = (b-a)/n;
%// Your code
uppershift = 1;
U = diag(ones(n-abs(uppershift),1),uppershift);
lowershift = -1;
L= diag(ones(n-abs(lowershift),1),lowershift);
D = ((U-L))/(2*h); %first differential operator
D2 = (full (gallery('tridiag',n)))/ -(h^2);
%// New code - Create differential equation matrix
Y = (-D2 + 2*D - eye(n));
%// Set boundary conditions on system
Y(1,:) = 0; Y(1,1) = 1;
Y(end,:) = 0; Y(end,end) = 1;
%// New code - Create F vector and set boundary conditions
F = x.';
F(1) = 0; F(end) = 0;
%// Solve system
X = Y \ F;
X should now contain your numerical approximation to the ODE in steps of h = 1/100 starting from x=0 up to x=1.
Now let's see what this looks like:
figure;
plot(x, X);
title('Solution to ODE');
xlabel('x'); ylabel('y');
You can see that y(0) = y(1) = 0 as per the boundary conditions.
Hope this helps, and good luck!

MATLAB polynomial fit selective powers

I have 2 vectors x and y to which I want to fit a polynomial as y = f(x) in MATLAB.
I could have used polyfit. However, I want to fit only selective power terms of the polynomial. For example, y = f(x) = a*x^3 + b*x + c. Notice that I don't have the x^2 term in there. Is there any built-in function in MATLAB to achieve this?
I am not sure if simply ignoring the coefficient that MATLAB gives for x^2 is same as fitting the polynomial without x^2 term.
If you don't have the curve fitting tool box (see #thewaywewalk's comment), or anyway, it is easy to use mldivide:
x=rand(10,1); % your x data
y=5*x.^3+2*x+7+rand(10,1)*.01; % some y data with noise
[x.^3 x ones(size(x))]\y % least squares solve to y = a*x^3 + b*x + c
gives
ans =
4.9799
2.0211
6.9980
Note that "simply ignoring the coefficient that MATLAB gives for x^2" is definitely not the "same as fitting the polynomial without x^2 term".
It sounds like you have the fitting toolbox and want to just remove a possible coefficient. If that's the case, here's a way to do it.
%What is the degree of the polynomial (cubic)
polyDegree = 3;
%What powers do you want to skip (x^2 and x)
skipPowers = [2, 1];
%This sets up the options
opts = fitoptions( 'Method', 'LinearLeastSquares' );
%All coefficients of degrees not specified between x^n and x^0 can have any value
opts.Lower = -inf(1, polyDegree + 1);
opts.Upper = inf(1, polyDegree + 1);
%The coefficients you want to skip have a range from 0 to 0.
opts.Lower(polyDegree + 1 - skipPowers) = 0;
opts.Upper(polyDegree + 1 - skipPowers) = 0;
%Do the fit using the specified polynomial degree.
[fitresult, gof] = fit( x, y, ['poly', num2str(polyDegree)] , opts );
In recent Matlab versions you can do it easily with a GUI by selecting the APPS tab and then the Curve Fitting Tool.
For example, I define:
x = 1:10;
y = x + randn(1,10);
I then select those variables as X data, Y data in the tool and I choose a custom equation defined as a*x^3 + b*x + c. The results are: