MATLAB: Fit a monotonically increasing curve to inexact data

fitMATLABmonotonicspline

I have a set of points that in general are monotonically increasing. There are some points that break this trend though, perhaps due to noise.
I would like to fit a symbolic equation to this data, however this function must be strictly monotonic. How can I do this without specifying some complicated custom optimization function?

Best Answer

One option is to use the Curve Fitting Tool within MATLAB. You can open this tool using the function "cftool". From this point you have several choices:
  1. You can select "Polynomial" and test out some different degrees to see if the fit is good, and if they appear monotonic.
2. You can select "Smoothing Spline" and click "Smoother" until the function appears monotonic.
Note that neither of these methods would strictly enforce monotonicity.
Once you have created a good fit to the data, you can saving the generated fit to your workspace (found under the Fit tab of the CFTool) and then extract the polynomial coefficients of the curve in order to create a symbolic equation.
Another option is to alter the raw data before creating a fit. The following example code is from the comp.soft-sys-matlab newsgroup with thanks to John D'Errico.
This example will alter your raw data ('x' and 'y') to become monotonically increasing via minimal changes:
n = length(x);
C = eye(n);
D = y;
A = diag(ones(n,1),0) - diag(ones(n-1,1),1);
A(end,:) = [];
b = zeros(n-1,1);
opts = optimset('lsqlin');
opts.LargeScale = 'off';
opts.Display = 'none';
yhat = lsqlin(C,D,A,b,[],[],[],[],[],opts);
plot(x,y,'ro',x,yhat,'b-*')
After performing the above calculations, we can consider interpolation methods, as these methods would not produce a monotonic curve from non-monotonic data. From the "cftool", the variable "yhat" is now monotonically increasing. From this point, you can:
  1. Run any of the above options
  2. Select Interpolation, and then select "Cubic" or "PCHIP".
Note that PCHIP Interpolation on monotonic data will be strictly monotonic. Once again, you will be able to extract the corresponding polynomial coefficients after saving the generated fit to your workspace.
Finally, you could download the following 3rd party toolbox from the MATLAB File Exchange:
Using this toolbox, you can calculate a spline fit to your data, and you can specify that the result is strictly increasing using the following command:
>> pp = slmengine(x,y,'increasing','on','result','pp');
If you would prefer to fit a cubic function to your data, that is equivalent to specifying exactly two knots, one at either end of your data:
>> pp = slmengine(x,y,'knots',[1 10],'increasing','on','result','pp');
From this point, you can then extract the polynomial coefficients with the command "slmpar(pp, 'symabs' )".