n-dimensional non-linear curve fitting in Matlab - matlab

Is there any way to fit a function with n variables in Matlab? Any example would be very useful.
Till now I used curve fitting toolbox, which provides solution I need for functions with 2 arguments. But now I need to fit a function with much more variables.
The worst thing is that dependance is non-linear (probably something like a/x+b/y+c/z+…, but it's only a hypothesis). If it was linear, '\' operator would do the trick.

lsqnonlin will do, e.g.
%% generate noisy points for fitting
a = 1; b = 2; c = 3;
x = rand(100,3);
y = a./x(:,1) + b./x(:,2) + c./x(:,3) + 0.1*rand(1,1);
%% fitting
% define residual vector
minRes = #(p) (p(1) ./ x(:,1) + p(2) ./ x(:,2) + p(3) ./ x(:,3) - y);
% start values
par0 = [1,1,1];
% optimize
par = lsqnonlin(minRes, par0);

lsqnonlin
function included in Matlab

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

Fitting data to a known function MATLAB (without curve fitting toolbox)

I have a function with three parameters and some data that I want to fit. How can I do this optimally? I am not even sure of the range of the three parameters in the equation.
The function has free parameters alpha, beta and gamma and is given by
y = (1 - alpha + alpha./sqrt(1 + 2*beta*(gamma*x).^2./alpha)).^(-1) - 1;
I have arrays of x and y data points (around 50 points in each set) to which I want to find the best fit (defined as minimizing least squares) using any alpha, beta and gamma.
The solutions online recommend the curve fitting toolbox, which I do not have on my machine and am unable to install. I only have the barebones MATLAB 2015b version.
You need an optimization algorithm for smooth, R^n -> R functions. Since you have only access to barebone Matlab, a good idea is to take an algorithm from File Exchange. For illustration I picked LMFnlsq, which should suffice since you have a small problem, although it seems to be more general and a little bit overkill here.
Download LMFnlsq and add to your Matlab path.
Example
For convenience make a function called regr_fun:
function y = regr_fun(par, x)
alpha = par(1);
beta = par(2);
gamma = par(3);
y = (1 - alpha + alpha./sqrt(1 + 2*beta*(gamma*x).^2./alpha)).^(-1) - 1;
end
Curve fitting (in the same folder as regr_fun):
%---------------------------------------------------------------------
% DUMMY DATA
%---------------------------------------------------------------------
% Generate data from known model contaminated with random noise
rng(333) % for reproducibility
alpha = 2;
beta = 0.1;
gamma = 0.1;
par = [alpha, beta, gamma];
xx = 1:50;
y_true = regr_fun(par, xx);
yy = y_true + normrnd(0,1,1,50);
%---------------------------------------------------------------------
% FIT MODEL
%---------------------------------------------------------------------
% intial point of solver
p0 = [1,1,1];
obj_fun = #(p) sum((regr_fun(p, xx) - yy).^2);
% optimization
p_fit = LMFnlsq(obj_fun, p0);
y_fit = regr_fun(p_fit, xx);
%---------------------------------------------------------------------
% PLOT
%---------------------------------------------------------------------
plot(xx, yy, 'o')
hold on
plot(xx, y_true)
plot(xx, y_fit, '--')
Note
Although matlab.codetools.requiredFilesAndProducts lists the symbolic toolbox as well, for this problem it is not needed and the function should run withouth that as well.

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:

Using MATLAB to write a function that implements Newton's method in two dimensions

I am trying to write a function that implements Newton's method in two dimensions and whilst I have done this, I have to now adjust my script so that the input parameters of my function must be f(x) in a column vector, the Jacobian matrix of f(x), the initial guess x0 and the tolerance where the function f(x) and its Jacobian matrix are in separate .m files.
As an example of a script I wrote that implements Newton's method, I have:
n=0; %initialize iteration counter
eps=1; %initialize error
x=[1;1]; %set starting value
%Computation loop
while eps>1e-10&n<100
g=[x(1)^2+x(2)^3-1;x(1)^4-x(2)^4+x(1)*x(2)]; %g(x)
eps=abs(g(1))+abs(g(2)); %error
Jg=[2*x(1),3*x(2)^2;4*x(1)^3+x(2),-4*x(2)^3+x(1)]; %Jacobian
y=x-Jg\g; %iterate
x=y; %update x
n=n+1; %counter+1
end
n,x,eps %display end values
So with this script, I had implemented the function and the Jacobian matrix into the actual script and I am struggling to work out how I can actually create a script with the input parameters required.
Thanks!
If you don't mind, I'd like to restructure your code so that it is more dynamic and more user friendly to read.
Let's start with some preliminaries. If you want to make your script truly dynamic, then I would recommend that you use the Symbolic Math Toolbox. This way, you can use MATLAB to tackle derivatives of functions for you. You first need to use the syms command, followed by any variable you want. This tells MATLAB that you are now going to treat this variable as "symbolic" (i.e. not a constant). Let's start with some basics:
syms x;
y = 2*x^2 + 6*x + 3;
dy = diff(y); % Derivative with respect to x. Should give 4*x + 6;
out = subs(y, 3); % The subs command will substitute all x's in y with the value 3
% This should give 2*(3^2) + 6*3 + 3 = 39
Because this is 2D, we're going to need 2D functions... so let's define x and y as variables. The way you call the subs command will be slightly different:
syms x, y; % Two variables now
z = 2*x*y^2 + 6*y + x;
dzx = diff(z, 'x'); % Differentiate with respect to x - Should give 2*y^2 + 1
dzy = diff(z, 'y'); % Differentiate with respect to y - Should give 4*x*y + 6
out = subs(z, {x, y}, [2, 3]); % For z, with variables x,y, substitute x = 2, y = 3
% Should give 56
One more thing... we can place equations into vectors or matrices and use subs to simultaneously substitute all values of x and y into each equation.
syms x, y;
z1 = 3*x + 6*y + 3;
z2 = 3*y + 4*y + 4;
f = [z1; z2];
out = subs(f, {x,y}, [2, 3]); % Produces a 2 x 1 vector with [27; 25]
We can do the same thing for matrices, but for brevity I won't show you how to do that. I will defer to the code and you can see it then.
Now that we have that established, let's tackle your code one piece at a time to truly make this dynamic. Your function requires the initial guess x0, the function f(x) as a column vector, the Jacobian matrix as a 2 x 2 matrix and the tolerance tol.
Before you run your script, you will need to generate your parameters:
syms x y; % Make x,y symbolic
f1 = x^2 + y^3 - 1; % Make your two equations (from your example)
f2 = x^4 - y^4 + x*y;
f = [f1; f2]; % f(x) vector
% Jacobian matrix
J = [diff(f1, 'x') diff(f1, 'y'); diff(f2, 'x') diff(f2, 'y')];
% Initial vector
x0 = [1; 1];
% Tolerance:
tol = 1e-10;
Now, make your script into a function:
% To run in MATLAB, do:
% [n, xout, tol] = Jacobian2D(f, J, x0, tol);
% disp('n = '); disp(n); disp('x = '); disp(xout); disp('tol = '); disp(tol);
function [n, xout, tol] = Jacobian2D(f, J, x0, tol)
% Just to be sure...
syms x, y;
% Initialize error
ep = 1; % Note: eps is a reserved keyword in MATLAB
% Initialize counter
n = 0;
% For the beginning of the loop
% Must transpose into a row vector as this is required by subs
xout = x0';
% Computation loop
while ep > tol && n < 100
g = subs(f, {x,y}, xout); %g(x)
ep = abs(g(1)) + abs(g(2)); %error
Jg = subs(J, {x,y}, xout); %Jacobian
yout = xout - Jg\g; %iterate
xout = yout; %update x
n = n + 1; %counter+1
end
% Transpose and convert back to number representation
xout = double(xout');
I should probably tell you that when you're doing computation using the Symbolic Math Toolbox, the data type of the numbers as you're calculating them are a sym object. You probably want to convert these back into real numbers and so you can use double to cast them back. However, if you leave them in the sym format, it displays your numbers as neat fractions if that's what you're looking for. Cast to double if you want the decimal point representation.
Now when you run this function, it should give you what you're looking for. I have not tested this code, but I'm pretty sure this will work.
Happy to answer any more questions you may have. Hope this helps.
Cheers!

regression in matlab

I have this matlab code for regression with one indepenpent variable, but what if I have two independent variables(x1 and x2)? How should I modify this code of polynomial regression?
x = linspace(0,10,200)'; % independent variable
y = x + 1.5*sin(x) + randn(size(x,1),1); % dependent variable
A = [x.^0, x]; % construct a matrix of permutations
w = (A'*A)\(A'*y); % solve the normal equation
y2 = A*w; % restore the dependent variable
r = y-y1; % find the vector of regression residual
plot(x, [y y2]);
Matlab has facilities for polynomial regression function polyfit. Have you tried that?
http://www.mathworks.com/help/techdoc/data_analysis/f1-8450.html
http://www.mathworks.com/help/toolbox/stats/bq_676m-2.html#bq_676m-3
But if you want to workout your own formulation,you should probably look at textbook or some online resources on regression e.g.
http://www.edwardtufte.com/tufte/dapp/DAPP3a.pdf