Identifying the linear part of a curve

47 views (last 30 days)
Commented: Star Strider on 15 Feb 2021
Hi,
I am trying to identify the x and y values where the linear regime ends of a curve that is fairly noisy.
I've tried a few different methods to identify my coordinates; first, I've tried using the ischange function, but have some trouble identifying if the MaxNumChanges value is appropriate. The values generated from specifying 3 maximum changes seems to be the most accurate for my system, but I'd like to know if there is a better way to this.
Second, I've also tried using a threshold value as an input instead of MaxNumChanges but am unsure of what value to select. Using any Threshold value from 30-76 provides the same result as having MaxNumChanges set to 3.
Lastly, I've also simply tried to fit a linear model to the linear regime and excluded data points until the R2 value is unaffected.
I'd appreciate is any one can tell me what the most robust way to do this is.
Heres a picture shwowing the coordinates with varying MaxNumChanges: Here's the code I used:
T1.Properties.VariableNames = {'Molecules','A245'};
% ThrVal = 50;
% [TF,Sl,Ic] = ischange(T1.Molecules, 'linear','Threshold',ThrVal);
[TF,SI,Ic] = ischange(T1.Molecules, 'linear','MaxNumChanges',3);
Idx = find(TF);
figure
plot(T1.Molecules, T1.A245)
hold on
plot(T1.Molecules(Idx(1)), T1.A245(Idx(1)), '+r')
hold off
grid
text(T1.Molecules(Idx(1)), T1.A245(Idx(1)), sprintf('\\leftarrowLinear Region End:\n Molecules = %10.4f\n A245 = %10.4f', T1.Molecules(Idx(1)), T1.A245(Idx(1))), 'HorizontalAlignment','left', 'VerticalAlignment','top')
Thank you!

Star Strider on 15 Feb 2021
Edited: Star Strider on 15 Feb 2021
The problem is that the data are noisy, so they need to be made less so.
Also, the smoothing and ischange functions need to use ‘A245’, not ‘Molecules’, at least if I correctly assume what you want to do.
Try this:
T1.Properties.VariableNames = {'Molecules','A245'};
N = height(T1);
A245 = filtfilt(ones(1,fix(N/20)), N/20, T1.A245);
% ThrVal = 50;
% [TF,Sl,Ic] = ischange(T1.Molecules, 'linear','Threshold',ThrVal);
[TF,SI,Ic] = ischange(A245, 'linear');%,'MaxNumChanges',3);
Idx = find(TF);
figure
plot(T1.Molecules, T1.A245)
hold on
plot(T1.Molecules(Idx(end)), T1.A245(Idx(end)), '+r')
hold off
grid
xlabel('Molecules')
ylabel('A_{245}')
text(T1.Molecules(Idx(end)), T1.A245(Idx(end))*1.025, sprintf('\\leftarrowLinear Region End:\n Molecules = %10.4f\n A245 = %10.4f', T1.Molecules(Idx(end)), T1.A245(Idx(end))), 'HorizontalAlignment','left', 'VerticalAlignment','top')
figure
plot(T1.Molecules, A245)
grid
xlabel('Molecules')
ylabel('A_{245}')
title('Smoothed A_{245}')
The second plot is not necessary for the code. It simply shows the effect of using a simple moving-average filter to smooth the data. (I have no idea what version/release you are using, or what Toolboxes you have, so using filter instead of filtfilt will likely produce an acceptable result, as well as movmean or smoothdata. I wrote my enhancements to use the simplest options available.)
EDIT — (15 Feb 2021 at 14:28) .
Star Strider on 15 Feb 2021
My pleasure!
Can you tell me why you didn't specify MaxNumChanges in your code?
That argument was not necessary. With the filtered signal, there were only 2 changes.
Your solution gives me a value of ~3.12 units, is there way to make that more accurate?
I have no idea what your signal is, what your criteria are, or what you want as a result.