pepe
pepe

Reputation: 9909

How to find inflection point of noisy data series using Matlab?

Given the following curve

enter image description here

I'd like to determine the index of the x-data point where the curve begins to increase in earnest (in this example that would be around x=15).

While I understand derivatives can be used for determining inflection points, note that the data is noisy and I'm unsure that approach would allow me to clearly identify the "true inflection point" (x=15 in this case).

I'm wondering if a simpler approach would be feasible such as

Do you have any suggestions on how to accomplish this?

Sample data from above curve

 index       SQMean   
_____    ____________

'0'      '139.428574'
'1'      '133.298706'
'2'      '135.961044'
'3'      '143.688309'
'4'      '133.298706'
'5'      '133.181824'
'6'      '134.896103'
'7'      '146.415588'
'8'      '142.324677'
'9'      '128.168839'
'10'     '146.116882'
'11'     '146.766235'
'12'     '134.675323'
'13'     '138.610382'
'14'     '140.558441'
'15'     '128.662338'
'16'     '138.480515'
'17'     '153.610382'
'18'     '156.207794'
'19'     '183.428574'
'20'     '220.324677'
'21'     '224.324677'
'22'     '230.415588'
'23'     '226.766235'
'24'     '223.935059'
'25'     '229.922073'
'26'     '234.389618'
'27'     '235.493500'
'28'     '225.727280'
'29'     '241.623383'
'30'     '225.805191'
'31'     '240.896103'
'32'     '224.090912'
'33'     '230.467529'
'34'     '248.285721'
'35'     '233.779221'
'36'     '225.532471'
'37'     '247.337662'
'38'     '233.000000'
'39'     '241.740265'
'40'     '235.688309'
'41'     '238.662338'
'42'     '236.636368'
'43'     '236.025970'
'44'     '234.818176'
'45'     '240.974030'
'46'     '251.350647'
'47'     '241.857147'
'48'     '242.623383'
'49'     '245.714279'
'50'     '250.701294'
'51'     '229.415588'
'52'     '236.909088'
'53'     '243.779221'
'54'     '244.532471'
'55'     '241.493500'
'56'     '245.480515'
'57'     '244.324677'
'58'     '244.025970'
'59'     '231.987015'
'60'     '238.740265'
'61'     '239.532471'
'62'     '232.363632'
'63'     '242.454544'
'64'     '243.831161'
'65'     '229.688309'
'66'     '239.493500'
'67'     '247.324677'
'68'     '245.324677'
'69'     '244.662338'
'70'     '238.610382'
'71'     '243.324677'
'72'     '234.584412'
'73'     '235.181824'
'74'     '228.974030'
'75'     '228.246750'
'76'     '230.519485'
'77'     '231.441559'
'78'     '236.324677'
'79'     '229.935059'
'80'     '238.701294'
'81'     '236.441559'
'82'     '244.350647'
'83'     '233.714279'
'84'     '243.753250'

Upvotes: 2

Views: 3262

Answers (1)

A. Donda
A. Donda

Reputation: 8477

If this is a one-off estimate, one thing you can do is to use the curve fitting tool from the Curve Fitting Toolbox. Here is an example where I fitted a piecewise linear function to your data:

(click on image for full size)

The function has the form

a * (x < b) + c * (x > d) + ((x - b) / (d - b) * (c - a) + a) * (x >= b) * (x <= d)

which says: there is a constant part for x < b with value a, another constant part for x > d with value c, and a linear ramp connecting them.

It is hard to fit such a function, and will only work well if you provide decent starting estimates (see small window in screenshot). It is therefore not a way to automate the process, but just to obtain improved estimates.

In this case, from a starting estimate of b = 15 the fit provides an improved estimate b = 16.58 with a 95%-CI of [15.96, 17.2], which indicates that indices 0 through 16 belong to the initial constant part.

The curve fitting tool can also generate code from your GUI specifications. In this case the result is:

[xData, yData] = prepareCurveData( index, SQMean );

% Set up fittype and options.
ft = fittype( 'a * (x < b) + c * (x > d) + ((x - b) / (d - b) * (c - a) + a) * (x >= b) * (x <= d)', 'independent', 'x', 'dependent', 'y' );
opts = fitoptions( ft );
opts.Display = 'Off';
opts.Lower = [-Inf -Inf -Inf -Inf];
opts.StartPoint = [140 15 230 20];
opts.Upper = [Inf Inf Inf Inf];

% Fit model to data.
[fitresult, gof] = fit( xData, yData, ft, opts );

% Plot fit with data.
figure( 'Name', 'untitled fit 1' );
h = plot( fitresult, xData, yData );
legend( h, 'SQMean vs. index', 'untitled fit 1', 'Location', 'NorthEast' );
% Label axes
xlabel( 'index' );
ylabel( 'SQMean' );
grid on

Upvotes: 1

Related Questions