How to fit a function to 2D array when some parts of the underlaying function are known?
1 visualización (últimos 30 días)
Mostrar comentarios más antiguos
Dominik Hiltbrunner
el 8 de Oct. de 2021
Comentada: Alex Sha
el 19 de Oct. de 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 comentarios
Respuesta aceptada
Alan Weiss
el 8 de Oct. de 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 comentarios
Alex Sha
el 19 de Oct. de 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
Más respuestas (0)
Ver también
Categorías
Más información sobre Creating and Concatenating Matrices en Help Center y File Exchange.
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!