2D data fit lsqcurvefit with NaN in grid
14 views (last 30 days)
Show older comments
Using Star Strider's solution to fit 2D data to a custom function: https://de.mathworks.com/matlabcentral/answers/119001-2d-data-fitting-surface I ran into the problem that it does not work if the z values contain NaNs.
take the exact same problem but exchange z with:
x = [1 2 4 6 8 10 13 17 21 25];
y = [0.2 0.5 1 2 4 7 10 14 18 22];
z =[1,0.6844,0.3048,NaN,0.1689,0.1432,0.1192,0.1015,0.09080,0.08410;1,0.7096,0.3595,0.2731,0.2322,0.2081,0.1857,0.1690,0.1590,0.1529;1,0.7451,0.4362,0.3585,0.3217,0.2999,0.2797,0.2648,NaN,0.2504;1,0.7979,0.5519,0.4877,0.4574,0.4394,NaN,0.4107,NaN,0.3994;1,NaN,0.6945,0.6490,NaN,0.6145,0.6027,0.5945,0.5896,0.5870;1,NaN,NaN,0.7758,NaN,0.7531,NaN,0.7410,0.7383,0.7368;1,0.9397,0.8647,0.8436,NaN,0.8278,0.8228,0.8195,0.8181,NaN;1,0.9594,0.9087,NaN,NaN,0.8839,0.8808,0.8791,NaN,NaN;1,0.9705,0.9342,0.9238,NaN,0.9165,0.9145,0.9133,NaN,NaN;NaN,0.9776,0.9502,0.9425,0.9390,0.9372,0.9358,NaN,NaN,NaN]
% to fit, Star Strider suggests:
[X Y] = meshgrid(x,y);
% Create input independent variable (10 x 10 x 2):
XY(:,:,1) = X;
XY(:,:,2) = Y;
% Create Objective Function:
surfit = @(B,XY) B(1)*exp(B(2).*XY(:,:,1)) + (1 - exp(B(3).*XY(:,:,2)));
% surfit = @(B,XY) exp(B(1).*XY(:,:,1)) + (1 - exp(B(2).*XY(:,:,2)));
% Do Regression
B = lsqcurvefit(surfit, [0.5 -0.5 -0.5], XY, z, [0 -10 -10], [1 10 10])
it all works nicely without NaNs in z.
with NaNs, the fit gives an error. Is there any way to only give the valid value tuples to lsqcurvefit?
I tried indexing the NaNs but XY(nonNaNs,:) is not allowed by matlab...
Interpolating the missing data is not an option
Thank you for the assistance.
0 Comments
Accepted Answer
Bjorn Gustavsson
on 3 Jun 2022
Edited: Bjorn Gustavsson
on 3 Jun 2022
You could try doing this with lsqnonlin:
x = [1 2 4 6 8 10 13 17 21 25];
y = [0.2 0.5 1 2 4 7 10 14 18 22];
z =[1,0.6844,0.3048,NaN,0.1689,0.1432,0.1192,0.1015,0.09080,0.08410;1,0.7096,0.3595,0.2731,0.2322,0.2081,0.1857,0.1690,0.1590,0.1529;1,0.7451,0.4362,0.3585,0.3217,0.2999,0.2797,0.2648,NaN,0.2504;1,0.7979,0.5519,0.4877,0.4574,0.4394,NaN,0.4107,NaN,0.3994;1,NaN,0.6945,0.6490,NaN,0.6145,0.6027,0.5945,0.5896,0.5870;1,NaN,NaN,0.7758,NaN,0.7531,NaN,0.7410,0.7383,0.7368;1,0.9397,0.8647,0.8436,NaN,0.8278,0.8228,0.8195,0.8181,NaN;1,0.9594,0.9087,NaN,NaN,0.8839,0.8808,0.8791,NaN,NaN;1,0.9705,0.9342,0.9238,NaN,0.9165,0.9145,0.9133,NaN,NaN;NaN,0.9776,0.9502,0.9425,0.9390,0.9372,0.9358,NaN,NaN,NaN];
[X Y] = meshgrid(x,y);
idxOK = isfinite(z(:)); % find the points with finite z
% Define a residual-function
surf_res = @(B,X,Y,Z) Z - (B(1)*exp(B(2).*X) + (1 - exp(B(3).*Y)));
% Fit only using the finite-valued points
B = lsqnonlin(@(B) surf_res(B,X(idxOK),Y(idxOK),z(idxOK)), [1,1,1]);
% Check the results
plot3(X,Y,z,'r*')
hold on
surf(X,Y,-surf_res(B,X,Y,zeros(size(X))))
But it might be neater with a separation of the surface-function and the residual-function:
surf_fcn = @(B,X,Y) (B(1)*exp(B(2).*X) + (1 - exp(B(3).*Y)));
res_fcn = @(B,X,Y,Z,fcn) Z - fcn(B,X,Y);
B2 = lsqnonlin(@(B) res_fcn(B,X(idxOK),Y(idxOK),z(idxOK),surf_fcn), [1,1,1]);
plot3(X,Y,z,'r*')
hold on
surf(X,Y,surf_fcn(B2,X,Y))
You can constrain the search-space similarly with lsqnonlin as with lsqcurvefit. In this case the surface-function doesn't seem ideal, but I guess it is a test-example.
HTH
More Answers (0)
See Also
Categories
Find more on Get Started with Curve Fitting Toolbox in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!