how to fit implicit function to data
显示 更早的评论
I have these data points
data=[0 1
0.355257 0.726061
0.749002 0.382696
1 0
2.401699 -0.9817
3.049682 -1.49588
4.105308 -2.51708
3.419108 -2.79514
1.784289 -2.188
0.763907 -1.56124
0 -1];
I need to fit this implicit function to the data
f = @(x,y) abs(x)^a + abs(y)^b +c*x*y-1;
where a, b, c are the 3 positive parameters to be estimated.
Can anyone help me?
采纳的回答
更多回答(1 个)
Rik
2018-12-10
Or, if you don't have the curve fitting toolbox (or the optimization toolbox), you can use fminsearch. The code below might be a bit overpowered for your use case, but it is re-usable. Both functions shown below are meant to end up on the FEX at some point.
data=[0 1
0.355257 0.726061
0.749002 0.382696
1 0
2.401699 -0.9817
3.049682 -1.49588
4.105308 -2.51708
3.419108 -2.79514
1.784289 -2.188
0.763907 -1.56124
0 -1];
x=data(:,1);y=data(:,2);
f = @(fitval,x) abs(x).^fitval(1) + abs(y).^fitval(2) +fitval(3).*x.*y-1;
initial_guess=[1 1 1];
bounds=[0 inf;0 inf;0 inf];
fit_val=fit_fminsearch(f,x,y,initial_guess,bounds);
clc
fprintf('a=%.4f\nb=%.4f\nc=%.4f\n',fit_val)
function [fit_val,gof_struct]=fit_fminsearch(f,x,y,initial_guess,bounds)
%Use fminsearch to fit data to a function
%The first input should be a function handle, anonymous function or inline
%function (for releases without anonymous functions) which accepts the fit
%value as the first input and the x as the second input. It must allow x
%and initial_guess as inputs and return a vector the same size as y.
%
%The bounds input is optional and should be a matrix with two columns and
%length(initial_guess) rows. By default this is set to -inf to inf.
%
% Examples:
%
% f=inline('b*x','b','x');
% x=1:10;y=2*x;initial_guess=1;
% B=fit_fminsearch(f,x,y,initial_guess);
%
% f=@(b,x) b*x;
% x=1:10;y=2*x;initial_guess=1;
% B=fit_fminsearch(f,x,y,initial_guess);
%#dependencies{ifversion}
persistent OLS
if isempty(OLS)
% adapted Ordinary Least Squares cost function
OLS_as_char=[...
'sum((f(b,x) - y).^2) +'... % OLS part
'inf^(any(b<bounds(:,1))-1) +'...%converts true to inf
'inf^(any(b>bounds(:,2))-1)'];
if ifversion('<',7,'Octave','<','1')
%Anonymous functions were not introduced, so use an inline function
%instead. This will be removed in later releases, so avoid inline
%when this is possible.
OLS=inline(OLS_as_char,'b','x','y','f','bounds'); %#ok<DINLN>
else
%The syntax checker of older releases trip up over statements
%defining anonymous function, so use eval to trick it.
eval(['OLS=@(b,x,y,f,bounds) ' OLS_as_char ';'])
end
end
if nargin==4
%set the default bounds
bounds=inf*ones(numel(initial_guess),2);
bounds(:,1)=-inf;
end
opts = optimset('MaxFunEvals',50000, 'MaxIter',10000);
% Use 'fminsearch' to minimise the 'OLS' function
fit_val = fminsearch(OLS, initial_guess(:), opts,x,y,f,bounds);
if nargout==2
err=y-f(fit_val,x);
SSres=sum(err.^2);
SStot=sum((y-mean(y)).^2);
rsq=1-(SSres./SStot);
RMS=sqrt(mean(err.^2));
gof_struct=struct;
gof_struct.sse=SSres;
gof_struct.rsquare=rsq;
gof_struct.rmse=RMS;
end
end
function tf=ifversion(test,Rxxxxab,varargin)
%Determine if the current version satifies a version restriction
%
% To keep the function fast, no input checking is done.
%
% Syntax:
% tf=ifversion(test,Rxxxxab)
% tf=ifversion(test,Rxxxxab,'Octave',test_for_Octave,v_Octave)
%
% Output:
% tf - If the current version satisfies the test this returns true.
% This works similar to verLessThan.
%
% Inputs:
% Rxxxxab - Char array containing a release description (e.g. 'R13',
% 'R14SP2' or 'R2018b') or the numeric version.
% test - Char array containing a logical test. The interpretation of
% this is equivalent to eval([current test Rxxxxab]). For
% examples, see below.
%
% Examples:
% ifversion('>=','R2009a') returns true when run on R2009a or later
% ifversion('<','R2016a') returns true when run on R2015b or older
% ifversion('==','R2018a') returns true only when run on R2018a
% ifversion('<',0,'Octave','>',0) returns true only on Octave
%
% The conversion is based on a manual list and therefore needs to be
% updated manually, so it might not be complete. Although it should be
% possible to load the list from Wikipedia, this is not implemented.
%
% Version: 0.1
% Date: 2018-10-27
% Author: H.J. Wisselink
% Licence: CC by-nc-sa 4.0 ( creativecommons.org/licenses/by-nc-sa/4.0 )
% Email= 'h_j_wisselink*alumnus_utwente_nl';
% Real_email = regexprep(Email,{'*','_'},{'@','.'})
%The decimal of the version numbers are padded with a 0 to make sure v7.10
%is larger than v7.9. This does mean that any numeric version input needs
%to be adapted.
persistent v_num v_dict octave
if isempty(v_num)
%test if Octave is used instead of Matlab
octave=exist('OCTAVE_VERSION', 'builtin');
%get current version number
v_num=version;
ind=strfind(v_num,'.');
if numel(ind)~=1,v_num(ind(2):end)='';end
v_num=[str2double(v_num(1:(ind-1))) str2double(v_num((ind+1):end))];
v_num=v_num(1)+v_num(2)/100;
%get dictionary to use for ismember
v_dict={'R13' 6.05;'R13SP1' 6.05;'R13SP2' 6.05;'R14' 7;'R14SP1' 7;...
'R14SP2' 7.00;'R14SP3' 7.01;'R2006a' 7.02;'R2006b' 7.03;...
'R2007a' 7.04;'R2007b' 7.05;'R2008a' 7.06;'R2008b' 7.07;...
'R2009a' 7.08;'R2009b' 7.09;'R2010a' 7.10;'R2010b' 7.11;...
'R2011a' 7.12;'R2011b' 7.13;'R2012a' 7.14;'R2012b' 8.00;...
'R2013a' 8.01;'R2013b' 8.02;'R2014a' 8.03;'R2014b' 8.04;...
'R2015a' 8.05;'R2015b' 8.06;'R2016a' 9.00;'R2016b' 9.01;...
'R2017a' 9.02;'R2017b' 9.03;'R2018a' 9.04;'R2018b' 9.05};
end
if octave
if nargin==2
warning('HJW:ifversion:NoOctaveTest',['No version test ',...
'for Octave was provided.' char(10) 'This function ',...
'might return an unexpected outcome.']) %#ok<CHARTEN>
%Use the same test as for Matlab, which will probably fail.
L=ismember(v_dict(:,1),Rxxxxab);
if sum(L)~=1
v=NaN;
warning('HJW:ifversion:NotInDict',...
'The requested version is not in the hard-coded list.')
else
v=v_dict{L,2};
end
else
[test,v]=deal(varargin{4:5});
%convert 4.1 to 4.01
v=0.1*v+0.9*fix(v);
end
else
if isnumeric(Rxxxxab)
%convert R notation to numeric and convert 9.1 to 9.01
v=0.1*Rxxxxab+0.9*fix(Rxxxxab);
else
L=ismember(v_dict(:,1),Rxxxxab);
if sum(L)~=1
v=NaN;
warning('HJW:ifversion:NotInDict',...
'The requested version is not in the hard-coded list.')
else
v=v_dict{L,2};
end
end
end
switch test
case '=='
tf= v_num == v;
case '<'
tf= v_num < v;
case '<='
tf= v_num <= v;
case '>'
tf= v_num > v;
case '>='
tf= v_num >= v;
end
end
类别
在 帮助中心 和 File Exchange 中查找有关 Get Started with Curve Fitting Toolbox 的更多信息
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!
