0
votes

I am using Matlab curve-fitting tool cftool to fit my data. The issue is that the y values are largely varying (strongly decreasing) with respect to x-axis. A sample is given below,

x         y
0.1     237.98
1       25.836
10      3.785
30      1.740
100     0.804
300     0.431
1000    0.230
2000    0.180

The fitted format is: y=a/x^b+c/x^d with a,b,c, and d as constants. The curve-fit from matlab is quite accurate for large y-values (that's at lower x-range) with less than 0.1% deviation. However, at higher x-values, the accuracy of the fit is not good (around 11% deviation). I would like also to include % deviation in the curve-fitting iteration to make sure the data is captured exactly. The plot is given for the fit and data reference. enter image description here

Can anyone suggest me for better ways to fit the data?

2

2 Answers

1
votes

The most common way to fit a curve is to do a least squares fit, which minimizes the sum of the square differences between the data and the fit. This is why your fit is tighter when y is large: an 11% deviation on a value of 0.18 is only a squared error of 0.000392, while a 0.1% deviation on a value of 240 is a squared error of 0.0576, much more significant.

If what you care about is deviations rather than absolute (squared) errors, then you can either reformulate the fitting algorithm, or transform your data in a clever way. The second way is a common and useful tool to know.

One way to do this in your case is fit the log(y) instead of y. This will have the effect of making small errors much more significant:

data = [0.1     237.98
1       25.836
10      3.785
30      1.740
100     0.804
300     0.431
1000    0.230
2000    0.180];

x = data(:,1);
y = data(:,2);


% Set up fittype and options.
ft = fittype( 'a/x^b + c/x^d', 'independent', 'x', 'dependent', 'y' );
opts = fitoptions( 'Method', 'NonlinearLeastSquares' );
opts.Display = 'Off';
opts.StartPoint = [0.420712466925742 0.585539298834167 0.771799485946335 0.706046088019609];

%% Usual least-squares fit
[fitresult] = fit( x, y, ft, opts );
yhat =  fitresult(x);
% Plot fit with data.
figure
semilogy( x, y );
hold on
semilogy( x, yhat);

deviation = abs((y-yhat))./y * 100

%% log-transformed fit
[fitresult] = fit( x, log(y), ft, opts );
yhat = exp(fitresult(x));
% Plot fit with data.
figure
semilogy( x, y );
hold on
semilogy( x, yhat );

deviation = abs((y-yhat))./y * 100
0
votes

One approach would be to fit to the lowest sum-of-squared relative error, rather than the lowest sum-of-squared absolute error. When I use the data posted in your question, fitting to lowest sum-of-squared relative error yields +/- 4 percent error - so this may be a useful option. To verify if you might want to consider this approach, here are the coefficients I determined from your posted data using this method:

a =  2.2254477037465399E+01
b =  1.0038013513610324E+00
c =  4.1544917994119190E+00
d =  4.2684956973959676E-01