Borrar filtros
Borrar filtros

I want to fit the curve with two linear curves and find the point where the fitted curve deviates from the linear relationship, sort of the tangent point.

22 visualizaciones (últimos 30 días)
I couldn't find an appropriate answer to my question. I have attached the matlab script which plots the results and also the clean data. i want to fit two linear curves and identify the slopes. I tried depicting in the screenshot. Additionally i want to know the point where the fit deviates from the curve.
Maybe easier way is to split the data where we see two different scales. Fit fast rise region and then slow rise region.
Please suggest! Appreciate your help.

Respuestas (2)

Image Analyst
Image Analyst el 12 de Nov. de 2023
Find the point where the slope difference between the left and right side of the dividing point is greatest.
See my attached demo. Adapt it to use your data instead of my demo data.
  5 comentarios
Image Analyst
Image Analyst el 14 de Nov. de 2023
@T You need to widen your search range. Look at my code:
% Assume the crossing point will be somewhere in the middle half of the points.
% If you go much more outward than that there are too few points to get a good line and the slopes of the lines will vary tremendously.
% Fit a line through the right and left parts and get the slopes.
% Keep the point where the slope difference is greatest.
numPoints = length(x);
index1 = round(0.25 * numPoints); % 25% of the way through.
index2 = round(0.75 * numPoints); % 75% of the way through.
% In other words, assume that we need at least 25 percent of the points to make a good estimate of the line.
% Obviously if we took only 2 or 3 points, then the slope could vary quite dramatically,
Try going from 10% to 90% instead of from 25% to 75%.
William Rose
William Rose el 14 de Nov. de 2023
Editada: William Rose el 14 de Nov. de 2023
@T,
[edit: change "there" to "therefore" near the end of my comments]
Sorry I went a bit academic in my previous comment. That is a mistake I sometimes make.
You write: "eventually I would eventually ignore the second part of the curve (which is almost a flat line). So essentially I want to find the intersection point of two tangents of these two curves and while finding the slope of the first curve on log-log, ignore the second half of the curve.". This is interesting and I understand it. The tricky part about doing this is deciding what part of the curve to ignore. You said "second half", but I assume you did not necessarily mean exactly half.
I suggest that you fit the data with two straight lines, and require the right hand line to be flat. Then see where the left line intersects the flat right line.
There's still a question, if you do the approach I suggest: Do you want the flat right line's y-axis intercept to be (A) at the y-asymptote of the curve, or do you want the flat right line's y-intercept to be (B) fitted by a least squares approach? Try both and see which you prefer.
clear;
load('y1_clean.mat'); load('x_clean.mat');
logy=log(y1); logx=log(x);
% Method A: Right line is horizontal, with y-intercept=mean(last 100 points)
% - which is an estimate of the y-asymptote of the curve.
[a0A,a1A,b0A,x0A] = bilinearFitA(logx,logy);
Local minimum found. Optimization completed because the size of the gradient is less than the value of the optimality tolerance.
% Method B: Right line is horizontal, with y-intercept determined by least squares
% fit of all points to the right of the intercept of the left and right lines.
[a0B,a1B,b0B,x0B] = bilinearFitB(logx,logy);
Local minimum found. Optimization completed because the size of the gradient is less than the value of the optimality tolerance.
% plot results
figure;
subplot(211);
plot(logx,logy,'r.',[min(logx),x0A],a0A+a1A*[min(logx),x0A],'-b',...
x0A,a0A+a1A*x0A,'gs',[x0A,max(logx)],[b0A,b0A],'-b');
grid on; ylabel('log y'); xlabel('log x'); title('Method A')
subplot(212);
plot(logx,logy,'r.',[min(logx),x0B],a0B+a1B*[min(logx),x0B],'-b',...
x0B,a0B+a1B*x0B,'gs',[x0B,max(logx)],[b0B,b0B],'-b');
grid on; ylabel('log y'); xlabel('log x'); title('Method B')
function [a0,a1,b0,x0] = bilinearFitA(x,y)
%BILINEARFITA Fit two straight lines to a set of x,y data.
% The right line is horizontal, with intercept b0=mean(last 100 y-values)
% The fitting function is
% y = a0 + a1*x if x<=x0
% y = b0 if x>x0
% where x0 = (b0-a0)/a1
% x, y should be vectors of equal length.
%% Determine b0 and initial guesses for a0, a1
b0=mean(y(end-99:end));
x1=x(1:floor(length(x)/2));
y1=y(1:floor(length(x)/2));
p = polyfit(x1,y1,1);
a0init=p(2); a1init=p(1);
f0=[a0init;a1init]; % initial guess
% Define function myFun=difference between measured and predicted y
function v=myFun(f)
%f=[a0;a1];
a0=f(1); a1=f(2);
x0=(b0-a0)/a1;
v=zeros(length(x),1);
for i=1:length(x)
if x(i)<=x0
v(i)=a0+a1*x(i)-y(i);
else
v(i)=b0-y(i);
end
end
end
%% Find two straight lines
f = lsqnonlin(@myFun,f0);
a0=f(1);
a1=f(2);
x0 = (b0-a0)/a1;
end % end bilinearFitA
function [a0,a1,b0,x0] = bilinearFitB(x,y)
%BILINEARFITB Fit two straight lines to a set of x,y data.
% The right line is horizontal. Its intercept b0 is determined by least
% squares fitting of all the data to the right of x0.
% The fitting function is
% y = a0 + a1*x if x<=x0
% y = b0 if x>x0
% where x0 = (b0-a0)/a1
% x, y should be vectors of equal length.
%% Determine initial guesses for a0, a1, b0
x1=x(1:floor(length(x)/2));
y1=y(1:floor(length(x)/2));
x2=x(ceil(length(x)/2):end);
y2=y(ceil(length(x)/2):end);
p = polyfit(x1,y1,1);
a0init=p(2); a1init=p(1);
b0init=mean(y2);
f0=[a0init;a1init;b0init]; % initial guess
% Define function myFun=difference between measured and predicted y
function v=myFun(f)
%f=[a0;a1;b0];
a0=f(1); a1=f(2); b0=f(3);
x0=(b0-a0)/a1;
v=zeros(length(x),1);
for i=1:length(x)
if x(i)<=x0
v(i)=a0+a1*x(i)-y(i);
else
v(i)=b0-y(i);
end
end
end
%% Find two straight lines
f = lsqnonlin(@myFun,f0);
a0=f(1);
a1=f(2);
b0=f(3);
x0 = (b0-a0)/a1;
end
Based on your previous comments, I predict that you will not really like either of the plots above, because the left lines in both are not tangent to the red points. They are not tangent because they are minimizing the sum squared error.
You may also think (as I did) that the left lines do not look like they are the best fit lines to the data (the red dots) in the range they span. The lines appear to fit the data from logx=2 to 3.5 much better than the data at the far left, from logx=-0.5 to +0.5. This happens because there are many more points between logx=2 and 3.5 than there are between logx=-0.5 to +0.5. Therefore the left fitted line "tries harder" to fit the data between logx=2 and 3.5 than to fit the far left data.
Good luck.

Iniciar sesión para comentar.


William Rose
William Rose el 6 de Nov. de 2023
Editada: William Rose el 6 de Nov. de 2023
[edit: corrected typo in formula for ]
The figure you included shows two striaight lines (black) fitted to a portion of a curve (blue). You have drawn two dots where the straight lines cross the curve. You want to know how to locate those points. In order to do that, you must explain how you chose the regions of the curve to fit with each straight line.
If you fit a curvilinear data set with two straight lines
if
if
then the two lines intersect at
Here is a figure from an article which I co-authored in which we compared four ways of fitting experimental data: one straight line, blinear i.e. two straight lines (like yours), exponential, and log-log. The different models have dfferent numbers of adjustable parameters, so one "penalizes" models with more adjustable parameters. See the paper (attached) for details, including all equations. The figure from that paper which is most relevant to your question is shown below.
It shows the bilinear fit to data from one subject.
  7 comentarios
William Rose
William Rose el 14 de Nov. de 2023
Here's another idea, inspired by your earlier comments.
Fit a horizontal line to the right side: intercept b1=mean(last N points). This is a simple and arbitrary way of estimating the horizontal asymptote.
Fit a straight line a0+a1*logx through the data from logx=0 to 2. This is a simple and arbitrary way of getting a line that is more or less tangent to a chunk of the left hand region of the data, which is what you seem to want to do.
The logx coordinate of the intersection is logx0=(b0-a0)/a1.
load('y1_clean.mat'); load('x_clean.mat');
logy=log(y1); logx=log(x);
% Right line is horizontal, with y-intercept=mean(last N points)
N=100; % number of points used to estimate right horizontal asymptote
logxlim=[0,2]; % values of logx for left line fit
% Fit left and right lines
p = polyfit(logx(logx>=logxlim(1) & logx<=logxlim(2)),logy(logx>=logxlim(1) & logx<=logxlim(2)),1);
a0=p(2); a1=p(1); % left line
b0=mean(logy(end-N+1:end)); % right line
logx0=(b0-a0)/a1; % logx coord of intersection
% display results on console
fprintf('a0=%.2f, a1=%.2f, b0=%.2f, logx0=%.2f\n',a0,a1,b0,logx0)
a0=-6.47, a1=0.99, b0=-3.70, logx0=2.80
% plot results
figure;
plot(logx,logy,'r.',[min(logx),logx0],a0+a1*[min(logx),logx0],'-b',...
logx0,a0+a1*logx0,'gs',[logx0,max(logx)],[b0,b0],'-b');
grid on; ylabel('log y'); xlabel('log x'); title('Tangent and Asymptote Fit')
How's that?

Iniciar sesión para comentar.

Categorías

Más información sobre Get Started with Curve Fitting Toolbox en Help Center y File Exchange.

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by