How to fit a function to 2D array when some parts of the underlaying function are known?
1 vue (au cours des 30 derniers jours)
Afficher commentaires plus anciens
Dominik Hiltbrunner
le 8 Oct 2021
Commenté : Alex Sha
le 19 Oct 2021
I have an unknown function Z=f(X,Y) where a subset of Z-values are known for a certain range of X and Y values.
Consider the following example
clc; clear; close all;
Z = [6.63900000000000e-09 3.92700000000000e-09 3.70100000000000e-09 3.37800000000000e-09 2.92600000000000e-09 2.57500000000000e-09 2.29900000000000e-09 1.89100000000000e-09 1.60700000000000e-09 1.39700000000000e-09 1.23600000000000e-09
1.13700000000000e-08 6.48300000000000e-09 6.10300000000000e-09 5.67100000000000e-09 5.02700000000000e-09 4.50200000000000e-09 4.07400000000000e-09 3.42200000000000e-09 2.95000000000000e-09 2.59200000000000e-09 2.31200000000000e-09
1.53100000000000e-08 8.55100000000000e-09 8.04300000000000e-09 7.54900000000000e-09 6.78500000000000e-09 6.14200000000000e-09 5.60700000000000e-09 4.77300000000000e-09 4.15500000000000e-09 3.67900000000000e-09 3.30000000000000e-09
1.87700000000000e-08 1.03400000000000e-08 9.72000000000000e-09 9.18400000000000e-09 8.33400000000000e-09 7.60300000000000e-09 6.98600000000000e-09 6.00700000000000e-09 5.26700000000000e-09 4.68900000000000e-09 4.22700000000000e-09
3.42700000000000e-08 1.83900000000000e-08 1.72600000000000e-08 1.66000000000000e-08 1.54900000000000e-08 1.44700000000000e-08 1.35600000000000e-08 1.20400000000000e-08 1.08200000000000e-08 9.83100000000000e-09 9.00500000000000e-09
5.17500000000000e-08 2.77800000000000e-08 2.60800000000000e-08 2.53000000000000e-08 2.40100000000000e-08 2.27700000000000e-08 2.16400000000000e-08 1.96600000000000e-08 1.80100000000000e-08 1.66200000000000e-08 1.54200000000000e-08
7.59600000000000e-08 4.14600000000000e-08 3.89400000000000e-08 3.79300000000000e-08 3.64600000000000e-08 3.50100000000000e-08 3.36600000000000e-08 3.12100000000000e-08 2.91000000000000e-08 2.72400000000000e-08 2.56100000000000e-08
1.23700000000000e-07 6.97800000000000e-08 6.54700000000000e-08 6.35700000000000e-08 6.17000000000000e-08 5.99600000000000e-08 5.83000000000000e-08 5.52400000000000e-08 5.24900000000000e-08 4.99900000000000e-08 4.77300000000000e-08
1.78100000000000e-07 1.03100000000000e-07 9.65000000000000e-08 9.27700000000000e-08 9.02000000000000e-08 8.80900000000000e-08 8.61500000000000e-08 8.25800000000000e-08 7.93200000000000e-08 7.63200000000000e-08 7.35500000000000e-08];
X = 1e-6*[0.5 0.75 1 2.5 5 7.5 10 15 20 25 30];
Y = [2.50000000000000e-07 5.00000000000000e-07 7.50000000000000e-07 1.00000000000000e-06 2.50000000000000e-06 5.00000000000000e-06 1.00000000000000e-05 2.50000000000000e-05 5.00000000000000e-05];
surf(X,Y,Z)
I want a function that predicts Z-values within the given range of X and Y values, and I know the following structure of the underlying function:
- Z is proportional to where c is an unknown constant.
- Z is proportional to where and are unknown constants.
How can I find the function f(X,Y) with Matlab?
0 commentaires
Réponse acceptée
Alan Weiss
le 8 Oct 2021
Well, it depends what you mean by "Z is proportional to c/X and Z is proportional to c2 + c3Y + c4Y^2". You could mean that Z is proportional to c/X + c2 + c3Y + c4Y^2. In that case, you can solve for the coefficients c using backslash.
Alternatively, you could mean that Z is proportional to (c1/X + c2) * (c3 + c4Y + c5Y^2). In that case, the c vector enters nonlinearly, and you need to use lsqcurvefit. Here is a script that shows both ways. I took the liberty of scaling things to be more order one, but feel free to unscale.
Z = [6.63900000000000e-09 3.92700000000000e-09 3.70100000000000e-09 3.37800000000000e-09 2.92600000000000e-09 2.57500000000000e-09 2.29900000000000e-09 1.89100000000000e-09 1.60700000000000e-09 1.39700000000000e-09 1.23600000000000e-09
1.13700000000000e-08 6.48300000000000e-09 6.10300000000000e-09 5.67100000000000e-09 5.02700000000000e-09 4.50200000000000e-09 4.07400000000000e-09 3.42200000000000e-09 2.95000000000000e-09 2.59200000000000e-09 2.31200000000000e-09
1.53100000000000e-08 8.55100000000000e-09 8.04300000000000e-09 7.54900000000000e-09 6.78500000000000e-09 6.14200000000000e-09 5.60700000000000e-09 4.77300000000000e-09 4.15500000000000e-09 3.67900000000000e-09 3.30000000000000e-09
1.87700000000000e-08 1.03400000000000e-08 9.72000000000000e-09 9.18400000000000e-09 8.33400000000000e-09 7.60300000000000e-09 6.98600000000000e-09 6.00700000000000e-09 5.26700000000000e-09 4.68900000000000e-09 4.22700000000000e-09
3.42700000000000e-08 1.83900000000000e-08 1.72600000000000e-08 1.66000000000000e-08 1.54900000000000e-08 1.44700000000000e-08 1.35600000000000e-08 1.20400000000000e-08 1.08200000000000e-08 9.83100000000000e-09 9.00500000000000e-09
5.17500000000000e-08 2.77800000000000e-08 2.60800000000000e-08 2.53000000000000e-08 2.40100000000000e-08 2.27700000000000e-08 2.16400000000000e-08 1.96600000000000e-08 1.80100000000000e-08 1.66200000000000e-08 1.54200000000000e-08
7.59600000000000e-08 4.14600000000000e-08 3.89400000000000e-08 3.79300000000000e-08 3.64600000000000e-08 3.50100000000000e-08 3.36600000000000e-08 3.12100000000000e-08 2.91000000000000e-08 2.72400000000000e-08 2.56100000000000e-08
1.23700000000000e-07 6.97800000000000e-08 6.54700000000000e-08 6.35700000000000e-08 6.17000000000000e-08 5.99600000000000e-08 5.83000000000000e-08 5.52400000000000e-08 5.24900000000000e-08 4.99900000000000e-08 4.77300000000000e-08
1.78100000000000e-07 1.03100000000000e-07 9.65000000000000e-08 9.27700000000000e-08 9.02000000000000e-08 8.80900000000000e-08 8.61500000000000e-08 8.25800000000000e-08 7.93200000000000e-08 7.63200000000000e-08 7.35500000000000e-08];
Z = Z*1e8;
X = 1e-6*[0.5 0.75 1 2.5 5 7.5 10 15 20 25 30];
X = X*1e6;
Y = [2.50000000000000e-07 5.00000000000000e-07 7.50000000000000e-07 1.00000000000000e-06 2.50000000000000e-06 5.00000000000000e-06 1.00000000000000e-05 2.50000000000000e-05 5.00000000000000e-05];
Y = Y*1e6;
[xx,yy] = meshgrid(X,Y);
surf(xx,yy,Z)
z1 = Z(:);
x1 = xx(:);
y1 = yy(:);
v1 = [1./x1 ones(size(x1)) y1 y1.^2]; % linear problem Z ~ c1/X + c2 + c3*Y + c4*Y^2
r1 = v1\z1;
zout = v1*r1; % Implied response
zout = reshape(zout,size(Z)); % Get ready to plot
figure
surf(xx,yy,zout)
xdata = [x1 y1]; % Nonlinear response problem
rng default
x0 = randn(1,5);
options = optimoptions("lsqcurvefit","MaxFunctionEvaluations",5e5,"MaxIterations",1e5);
cout = lsqcurvefit(@twofun,x0,xdata,z1,[],[],options); % Find nonlinear parameters
zout2 = twofun(cout,xdata); % Get implied response
zout2 = reshape(zout2,size(Z)); % Get ready to plot
figure
surf(xx,yy,zout2)
function r = twofun(c,xdata)
x = xdata(:,1);
y = xdata(:,2);
r = (c(1)./x + c(2)) .* ( c(3) + c(4)*y + c(5)*y.^2 );
end
Alan Weiss
MATLAB mathematical toolbox documentation
4 commentaires
Alex Sha
le 19 Oct 2021
Hi, Dominik, the fitting function below should be much better, and simple enough:
z = p1*power(y,p2+p3/x)+p4
Root of Mean Square Error (RMSE): 4.96676186258674E-9
Sum of Squared Residual: 2.44220361656497E-15
Correlation Coef. (R): 0.988334476564506
R-Square: 0.976805037566037
Parameter Best Estimate
---------- -------------
p1 3.00671529372895E-5
p2 0.59991103826544
p3 -0.0367412799143221
p4 -1.63336827935451E-9
Plus de réponses (0)
Voir également
Catégories
En savoir plus sur Creating and Concatenating Matrices dans Help Center et File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!