Matlab find the best constants for a fitting model - matlab

Please find the data in the link below, or if you can send me your private email, I can send you the data
https://dl.dropboxusercontent.com/u/5353938/test_matlab_lefou.xlsx
In the excel sheet, the first column is y, the second is x and the third is t, I hope this will make things much more clear, and many thanks for the help.
I need to use the following model because it is the one that fits best my data, but what I don't know is how to find the best values of a and b, that will allow me to get the best fit, (I can attach a file if you need the values), I already have the values of y, x and t:
y= a*sqrt(x).exp(b.t)
Thanks

Without the dependency on the curve fitting toolbox, this problem can also be solved by using fminsearch. I first generate some data, which you already have but didn't share with us. An initial guess on the parameters a and b must be made (p0). Then I do the optimiziation by minizmizing the squared errors between data and fit resulting in the vector p_fit, which contains the optimized parameters for a and b. In the end, the result is visualized.
% ----- Generating some data for x, y and t (which you already got)
N = 10; % num of data points
x = linspace(0,5,N);
t = linspace(0,10,N);
% random parameters
a = rand()*5; % a between 0 and 5
b = (rand()-1); % b between -1 and 0
y = a*sqrt(x).*exp(b*t) + rand(size(x))*0.1; % noisy data
% ----- YOU START HERE WITH YOUR PROBLEM -----
% put x and t into a 2 row matrix for simplicity
D(1,:) = x;
D(2,:) = t;
% create model function with parameters p(1) = a and p(2) = b
model = #(p, D) p(1)*sqrt(D(1,:)).*exp(p(2)*D(2,:));
e = #(p) sum((y - model(p,D)).^2); % minimize squared errors
p0 = [1,-1]; % an initial guess (positive a and probably negative b for a decay)
[p_fit, r1] = fminsearch(e, p0); % Optimize
% ----- VISUALIZATION ----
figure
plot(x,y,'ko')
hold on
X = linspace(min(x), max(x), 100);
T = linspace(min(t), max(t), 100);
plot(X, model(p_fit, [X; T]), 'r--')
legend('data', sprintf('fit: y(t,x) = %.2f*sqrt(x)*exp(%.2f*t)', p_fit))
The result can look like
UPDATE AFTER MANY MANY COMMENTS
Your data are column vectors, my solution used row vectors. The error occured when the errorfunction tryed to compute the difference of a column vector (y) and a row-vector (result of the model-function). Easy hack: make them all to row vectors and use my approach. The result is: a = 0.5296 and b = 0.0013.
However, the Optimization depends on the initial guess p0, you might want to play around with it a little bit.
clear variables
load matlab.mat
% put x and t into a 2 row matrix for simplicity
D(1,:) = x;
D(2,:) = t;
y = reshape(y, 1, length(y)); % <-- also y is a row vector, now
% create model function with parameters p(1) = a and p(2) = b
model = #(p, D) p(1)*sqrt(D(1,:)).*exp(p(2)*D(2,:));
e = #(p) sum((y - model(p,D)).^2); % minimize squared errors
p0 = [1,0]; % an initial guess (positive a and probably negative b for a decay)
[p_fit, r1] = fminsearch(e, p0); % Optimize
% p_fit = nlinfit(D, y, model, p0) % as a working alternative with dependency on the statistics toolbox
% ----- VISUALIZATION ----
figure
plot(x,y,'ko', 'markerfacecolor', 'black', 'markersize',5)
hold on
X = linspace(min(x), max(x), 100);
T = linspace(min(t), max(t), 100);
plot(X, model(p_fit, [X; T]), 'r-', 'linewidth', 2)
legend('data', sprintf('fit: y(t,x) = %.2f*sqrt(x)*exp(%.2f*t)', p_fit))
The result doesn't look too satisfying though. But that mainly is because of your data. Have a look here:

With the cftool-command (curve fitting toolbox) you can fit to your own functions, returning the variables that you need (a,b). Make sure your x-data and y-data are in separate variables. you can also specify weights for your measurements.

Related

Using arrayfun to solve a equation system (with vpasolve) MatLab

I am struggling with solving a problem as efficient as possible.
I have two equations and want to solve them together. Furthermore, I want to solve them for four different cases. I can solve them independently altering the code for each case. I can also solve them by accessing a vector that contains the desired value for one of them (e.g., the first value of A) by using arrayfun. However I can't manage to do all of them together.
My code:
clc
clear all
close all
% scalar parameters
g = 9.807; % Gravity constant, m/s2
d = 1.225; % Density of air, kg/m3
x = 1000; % Height, m
% vector parameters
%t = 0:2:10; % time, seconds
A = [1.2; 1.7; 1.8; 0.3]; % Area, m^2
m = [82; 84; 90; 25]; % Mass, kg
Cd = [0.3; 1.14; 0.29; 0.045]; % Drag coefficient, -
syms v t
eqn1 = 2*m./(A.*Cd*d).* log(abs(cosh(t.*sqrt(A.*Cd*d*g./(2*m))))) == x;
eqn2 = (2*g*m./(d*A.*Cd)).*tanh(t.* sqrt((g*d*Cd.*A)./(2*m))) - v == 0;
eqns=[eqn1 eqn2];
variables = [v t];
result = arrayfun(#vpasolve, eqns, 'uniform', 0)
%disp('v='),disp(eval(v));
%disp('t='),disp(eval(t));
I get a result for t (which is weirdly negative and I don't know why), but I only get a {1×1 struct} for v, which I don't want. I know I can solve this also by using a for loop, but I wanted to make it more efficient.
I tried the code written above and solved it in various forms, however not as desired.
The way you have it implemented you're effectively trying to solve four equations with two unknowns, which isn't supported by vpasolve except in the case of polynomial systems.
It looks like you're trying to solve the same system for four different combinations of values for the parameters A, m, and Cd. The easiest way to do that is to just break this out as a for loop (there is simply no benefit to using arrayfun here – speed or otherwise). You'll need to create some temporary symbolic variable for the parameter (there are a few ways this could be done). Here is example code to do just that:
% scalar parameters
g = 9.807; % Gravity constant, m/s2
d = 1.225; % Density of air, kg/m3
x = 1000; % Height, m
% vector parameters
%t = 0:2:10; % time, seconds
A = [1.2; 1.7; 1.8; 0.3]; % Area, m^2
m = [82; 84; 90; 25]; % Mass, kg
Cd = [0.3; 1.14; 0.29; 0.045]; % Drag coefficient, -
syms v t real
syms A_sym m_sym Cd_sym real % Temporary symbolic variables
eqn1 = 2*m_sym./(A_sym.*Cd_sym*d).* log(abs(cosh(t.*sqrt(A_sym.*Cd_sym*d*g./(2*m_sym))))) == x;
eqn2 = (2*g*m_sym./(d*A_sym.*Cd_sym)).*tanh(t.* sqrt((g*d*Cd_sym.*A_sym)./(2*m_sym))) - v == 0;
eqns=[eqn1 eqn2];
variables = [v t];
n = length(A); % Number of prameter sets
result = cell(n,1); % Preallocate resultant cell array
for i = 1:n
% Substitute in numeric values for i-th parameter set
eqns_sub = subs(eqns,{A_sym,m_sym,Cd_sym},{A(i),m(i),Cd(i)});
% Solve and store in cell array
result{i} = vpasolve(eqns_sub,variables);
end
The output, result, is a 4-by-1 cell array of structs with your two variables, v and t, as VPA-valued fields for each.
You could replace the last few lines with the following if what you want is a numeric array as the output (this assumes that only one solution is found for each parameter set):
n = length(A); % Number of prameter sets
result = zeros(n,length(variables)); % Preallocate resultant array
for i = 1:n
% Substitute in numeric values for i-th parameter set
eqns_sub = subs(eqns,{A_sym,m_sym,Cd_sym},{A(i),m(i),Cd(i)});
% Solve, convert to double precision, and store in array
out = vpasolve(eqns_sub,variables);
result(i,:) = double([out.v out.t]);
end

Constrained linear least squares not fitting data

I am trying to fit a 3D surface polynomial of n-degrees to some data points in 3D space. My system requires the surface to be monotonically increasing in the area of interest, that is the partial derivatives must be non-negative. This can be achieved using Matlab's built in lsqlin function.
So here's what I've done to try and achieve this:
I have a function that takes in four parameters;
x1 and x2 are my explanatory variables and y is my dependent variable. Finally, I can specify order of polynomial fit. First I build the design matrix A using data from x1 and x2 and the degree of fit I want. Next I build the matrix D that is my container for the partial derivatives of my datapoints. NOTE: the matrix D is double the length of matrix A since all datapoints must be differentiated with respect to both x1 and x2. I specify that Dx >= 0 by setting b to be zeroes.
Finally, I call lsqlin. I use "-D" since Matlab defines the function as Dx <= b.
function w_mono = monotone_surface_fit(x1, x2, y, order_fit)
% Initialize design matrix
A = zeros(length(x1), 2*order_fit+2);
% Adjusting for bias term
A(:,1) = ones(length(x1),1);
% Building design matrix
for i = 2:order_fit+1
A(:,(i-1)*2:(i-1)*2+1) = [x1.^(i-1), x2.^(i-1)];
end
% Initialize matrix containing derivative constraint.
% NOTE: Partial derivatives must be non-negative
D = zeros(2*length(y), 2*order_fit+1);
% Filling matrix that holds constraints for partial derivatives
% NOTE: Matrix D will be double length of A since all data points will have a partial derivative constraint in both x1 and x2 directions.
for i = 2:order_fit+1
D(:,(i-1)*2:(i-1)*2+1) = [(i-1)*x1.^(i-2), zeros(length(x2),1); ...
zeros(length(x1),1), (i-1)*x2.^(i-2)];
end
% Limit of derivatives
b = zeros(2*length(y), 1);
% Constrained LSQ fit
options = optimoptions('lsqlin','Algorithm','interior-point');
% Final weights of polynomial
w_mono = lsqlin(A,y,-D,b,[],[],[],[],[], options);
end
So now I get some weights out, but unfortunately they do not at all capture the structure of the data. I've attached an image so you can just how bad it looks. .
I'll give you my plotting script with some dummy data, so you can try it.
%% Plot different order polynomials to data with constraints
x1 = [-5;12;4;9;18;-1;-8;13;0;7;-5;-8;-6;14;-1;1;9;14;12;1;-5;9;-10;-2;9;7;-1;19;-7;12;-6;3;14;0;-8;6;-2;-7;10;4;-5;-7;-4;-6;-1;18;5;-3;3;10];
x2 = [81.25;61;73;61.75;54.5;72.25;80;56.75;78;64.25;85.25;86;80.5;61.5;79.25;76.75;60.75;54.5;62;75.75;80.25;67.75;86.5;81.5;62.75;66.25;78.25;49.25;82.75;56;84.5;71.25;58.5;77;82;70.5;81.5;80.75;64.5;68;78.25;79.75;81;82.5;79.25;49.5;64.75;77.75;70.25;64.5];
y = [-6.52857142857143;-1.04736842105263;-5.18750000000000;-3.33157894736842;-0.117894736842105;-3.58571428571429;-5.61428571428572;0;-4.47142857142857;-1.75438596491228;-7.30555555555556;-8.82222222222222;-5.50000000000000;-2.95438596491228;-5.78571428571429;-5.15714285714286;-1.22631578947368;-0.340350877192983;-0.142105263157895;-2.98571428571429;-4.35714285714286;-0.963157894736842;-9.06666666666667;-4.27142857142857;-3.43684210526316;-3.97894736842105;-6.61428571428572;0;-4.98571428571429;-0.573684210526316;-8.22500000000000;-3.01428571428571;-0.691228070175439;-6.30000000000000;-6.95714285714286;-2.57232142857143;-5.27142857142857;-7.64285714285714;-2.54035087719298;-3.45438596491228;-5.01428571428571;-7.47142857142857;-5.38571428571429;-4.84285714285714;-6.78571428571429;0;-0.973684210526316;-4.72857142857143;-2.84285714285714;-2.54035087719298];
% Used to plot the surface in all points in the grid
X1 = meshgrid(-10:1:20);
X2 = flipud(meshgrid(30:2:90).');
figure;
for i = 1:4
w_mono = monotone_surface_fit(x1, x2, y, i);
y_nr = w_mono(1)*ones(size(X1)) + w_mono(2)*ones(size(X2));
for j = 1:i
y_nr = w_mono(j*2)*X1.^j + w_mono(j*2+1)*X2.^j;
end
subplot(2,2,i);
scatter3(x1, x2, y); hold on;
axis tight;
mesh(X1, X2, y_nr);
set(gca, 'ZDir','reverse');
xlabel('x1'); ylabel('x2');
zlabel('y');
% zlim([-10 0])
end
I think it may have something to do with the fact that I haven't specified anything about the region of interest, but really I don't know. Thanks in advance for any help.
Alright I figured it out.
The main problem was simply an error in the plotting script. The value of y_nr should be updated and not overwritten in the loop.
Also I figured out that the second derivative should be monotonically decreasing. Here's the updated code if anybody is interested.
%% Plot different order polynomials to data with constraints
x1 = [-5;12;4;9;18;-1;-8;13;0;7;-5;-8;-6;14;-1;1;9;14;12;1;-5;9;-10;-2;9;7;-1;19;-7;12;-6;3;14;0;-8;6;-2;-7;10;4;-5;-7;-4;-6;-1;18;5;-3;3;10];
x2 = [81.25;61;73;61.75;54.5;72.25;80;56.75;78;64.25;85.25;86;80.5;61.5;79.25;76.75;60.75;54.5;62;75.75;80.25;67.75;86.5;81.5;62.75;66.25;78.25;49.25;82.75;56;84.5;71.25;58.5;77;82;70.5;81.5;80.75;64.5;68;78.25;79.75;81;82.5;79.25;49.5;64.75;77.75;70.25;64.5];
y = [-6.52857142857143;-1.04736842105263;-5.18750000000000;-3.33157894736842;-0.117894736842105;-3.58571428571429;-5.61428571428572;0;-4.47142857142857;-1.75438596491228;-7.30555555555556;-8.82222222222222;-5.50000000000000;-2.95438596491228;-5.78571428571429;-5.15714285714286;-1.22631578947368;-0.340350877192983;-0.142105263157895;-2.98571428571429;-4.35714285714286;-0.963157894736842;-9.06666666666667;-4.27142857142857;-3.43684210526316;-3.97894736842105;-6.61428571428572;0;-4.98571428571429;-0.573684210526316;-8.22500000000000;-3.01428571428571;-0.691228070175439;-6.30000000000000;-6.95714285714286;-2.57232142857143;-5.27142857142857;-7.64285714285714;-2.54035087719298;-3.45438596491228;-5.01428571428571;-7.47142857142857;-5.38571428571429;-4.84285714285714;-6.78571428571429;0;-0.973684210526316;-4.72857142857143;-2.84285714285714;-2.54035087719298];
% Used to plot the surface in all points in the grid
X1 = meshgrid(-10:1:20);
X2 = flipud(meshgrid(30:2:90).');
figure;
for i = 1:4
w_mono = monotone_surface_fit(x1, x2, y, i);
% NOTE: Should only have 1 bias term
y_nr = w_mono(1)*ones(size(X1));
for j = 1:i
y_nr = y_nr + w_mono(j*2)*X1.^j + w_mono(j*2+1)*X2.^j;
end
subplot(2,2,i);
scatter3(x1, x2, y); hold on;
axis tight;
mesh(X1, X2, y_nr);
set(gca, 'ZDir','reverse');
xlabel('x1'); ylabel('x2');
zlabel('y');
% zlim([-10 0])
end
And here's the updated function
function [w_mono, w] = monotone_surface_fit(x1, x2, y, order_fit)
% Initialize design matrix
A = zeros(length(x1), 2*order_fit+1);
% Adjusting for bias term
A(:,1) = ones(length(x1),1);
% Building design matrix
for i = 2:order_fit+1
A(:,(i-1)*2:(i-1)*2+1) = [x1.^(i-1), x2.^(i-1)];
end
% Initialize matrix containing derivative constraint.
% NOTE: Partial derivatives must be non-negative
D = zeros(2*length(y), 2*order_fit+1);
for i = 2:order_fit+1
D(:,(i-1)*2:(i-1)*2+1) = [(i-1)*x1.^(i-2), zeros(length(x2),1); ...
zeros(length(x1),1), -(i-1)*x2.^(i-2)];
end
% Limit of derivatives
b = zeros(2*length(y), 1);
% Constrained LSQ fit
options = optimoptions('lsqlin','Algorithm','active-set');
w_mono = lsqlin(A,y,-D,b,[],[],[],[],[], options);
w = lsqlin(A,y);
end
Finally a plot of the fitting (Have used a new simulation, but fit also works on given dummy data).

Least squares assuming functional form of the solution

I am trying to solve the following least squares problem:
b(alpha)=A(alpha,beta)x(beta)
I am trying to use an alternative approach, which is to assume the functional form of x(beta) through the use of tunable parameters, say x(beta, a, c). How can I solve this problem in MATLAB for a least squares solution for those parameters?
I second the comments -this would be much easier if you gave a slightly more verbose description of your problem and most importantly add a minimal working example.
As far as I understand though, you want to solve a linear system of equations with some additional assumptions about the fitted parameters. This can be done by expressing them as an optimisation problem.
Here for example I've fitted a quadratic where the coefficients of x^0 and x^1 are both dependant on some other arbitrary parameter a (for this example a = 6 - that's what we're trying to recover from the data).
There are 2 different approaches plotted here - unconstrained and constrained optimisation. You can see that all of them approximate our data well, but only the constrained optimisation recovers a value of a close to 6 (5.728). Anyway, have a look at the code and I hope this helps with your problem somewhat. If you can, try to use the reduced number of parameters approach. It is always better to reduce your fitting problems to lower dimensional spaces if possible - much less risk of local minima and much faster solutions.
Here is the code:
close all; clear; clc;
%% Generate test data
x = 1:100;
rng(0); % Seed rng
% Polynomial where we know something about the parameters - we know that if
% the coefficient of x^0 is 'a'm then the coefficient of x^1 is (1-a).
a = 6;
y = a + (1-a).*x + 0.1*x.^2;
y = y + 30*randn(size(x)); % Add some noise
%% Fit with mrdivide and Vandermonde matrix
A = vander(x); A = A(:,end-2:end)';
b = y;
k1 = b/A;
%% Fit with an unconstrained optimiser
f = #(k) optimfun1(x,y,k);
k0 = [1 1 1]; % Starting point
k2 = fminsearch(f,k0);
%% Fit with a constrained optimiser
f = #(k) optimfun1(x,y,k);
k0 = [1 1 1];
Aeq = [0 1 1]; beq = 1; % Constrain k2 = 1 - k3 which is equivalent to k2+k3 = 1
k3 = fmincon(f,k0,[],[],Aeq,beq);
%% Fit with a reduced number of parameters
f = #(k) optimfun2(x,y,k);
k0 = [1 1];
k4 = fminsearch(f,k0);
k4 = [k4 1-k4(2)]; % Infer the last coeff.
%% Plot
plot(x,y,'ko');
hold on
plot(x,polyval(k1,x));
plot(x,polyval(k2,x));
plot(x,polyval(k3,x));
plot(x,polyval(k4,x));
legend('k^{dat} = [6.000 -5.000 0.100];',...
sprintf('k^{unc}_1 = [%.3f %.3f %.3f]',flipud(k1(:))),...
sprintf('k^{unc}_2 = [%.3f %.3f %.3f]',flipud(k2(:))),...
sprintf('k^{cns}_1 = [%.3f %.3f %.3f]',flipud(k3(:))),...
sprintf('k^{cns}_2 = [%.3f %.3f %.3f]',flipud(k4(:))),...
'location','northwest');
grid on;
xlabel('x');
ylabel('f(x)');
title(sprintf('f(x) = a + (1-a)x + 0.1x^2; a = %d',a));
function diff = optimfun1(x,y,k)
yfit = polyval(k,x);
dy = yfit-y;
diff = sum(dy.^2); % Sum of squared residuals
end
function diff = optimfun2(x,y,k)
k = [k 1-k(2)]; % Infer the last coeff.
yfit = polyval(k,x);
dy = yfit-y;
diff = sum(dy.^2);
end
Without knowing exactly how does the parameter works, it is difficult to figure out what to do. For example if the parameter is
x(beta, a, c) = a * x(beta) + c
Then your equation becomes
b(alpha)= A(alpha,beta) * (a * x(beta) + c)
b(alpha) - c*A(alpha,beta) = A(alpha,beta) * a * x(beta)
which then perhaps you can solve in the standard way (I'm treating b and A as numbers and x as the only variable here disregarding the alpha and beta). For more non-linear relation, it gets complex.

Best approach to speed up pixel processing in matlab

I have a couple of big 3 dimensional matrices (e.g. dimension:16330,1300,16). For each cell I need to develop a simple linear regression model and extract some information such as slope and intercept of the fitted model.I created a loop and run the processing pixel by pixel but it will take for ever. Is there any suggestion that I can improve the following code?
% read the multiband image (16330,1300,16)
[A,R] = geotiffread('16Bands_image.tif');
% this is a vector (1*16) that i fit it against the third dimension of each
%pixel throughout the image
Load external.m
intercept = zeros(size(A,1),size(A,2));
slope = zeros(size(A,1),size(A,2));
for i=1:size(A,1)
for j=1:size(A,2)
REF=squeeze(A(i,j,:));
p=fitlm(REF,external);
intercept(i,j)=p.Coefficients.Estimate(1);
slope(i,j) = p.Coefficients.Estimate(2);
end
end
Thanks
If p = fitlm(external, REF) is what you need, there is a fast solution: reshape the image into 16 by (16330*1300), and apply the model without loop.
A = reshape(A, [], 16)'; % reshape and transpose to 16 by N
X = external(:);
X = X - mean(X);
b = [ones(16,1) X] \ A; % solve all once
Rows 1 and 2 of b are intercept and slope respectively.
I don't know your data, but this supposes A is the measured data.
If indeed you want the other way, you may still need loop over pixels:
external = external(:); % make sure it is column
b = zeros(2, size(A,2)); % A in 16 by N
for i = 1:size(A,2)
X = A(:,i);
X = X - mean(X);
b(:,i) = [ones(16,1) X] \ external;
end
But this is still slow, although it is faster than fitlm.

Curvefitting for power law function y= a(x^b)+c

I am new to MATLAB, and I am trying to fit a power law through a dataset. I have been trying to use isqcurvefit function, but I am unsure how to proceed as the instructions found through Google are too convoluted for a beginner. I would like to derive the values b and c from the equation y = a(x^b)+c, and any suggestions would be greatly appreciated. Thanks.
You can use lsqcurvefit to fit a non linear curve through measured data points in least-square sense as follows:
% constant parameters
a = 1; % set the value of a
% initial guesses for fitted parameters
b_guess = 1; % provide an initial guess for b
c_guess = 0; % provide an initial guess for c
% Definition of the fitted function
f = #(x, xdata) a*(xdata.^x(1))+x(2);
% generate example data for the x and y data to fit (this should be replaced with your real measured data)
xdata = 1:10;
ydata = f([2 3], xdata); % create data with b=2 and c=3
% fit the data with the desired function
x = lsqcurvefit(f,[b_guess c_guess],xdata,ydata);
%result of the fit, i.e. the fitted parameters
b = x(1)
c = x(2)