Hello,
I have data points represented by red stars on a graph (Fig 1, attached), and I would like to fit a curve to them. The curve does not have to be accurate -- it just needs to serve as a visual guide. I have drawn a sketch below to show what I would like. The other curves on the graph are by-products from the code I pulled this image from, and are not relevant to this problem. How can I fit a curve to the red data points in MATLAB?
--------------------
I have tried using polyfit, smoothingspline, pchip and other curve-fitting tools, but all of them connect the wrong data points together, since this graph is actually x = f(y). In MS Excel, if I switch the axes so the curve becomes a one-to-one function where y = f(x), I can easily fit a quadratic curve to the points.
I am currently plotting each point indivdually. I can plot the points with a line, but it is not very smooth (see Fig 2, attached). I guess I could just increase the number of data points, but that increases computation time too much. Any suggestions?
Please find below some things I have already tried. The red data points are saved in 1 x 11 doubles p_tn (x values) and p_Tn (y values).
Thank you so much! PLEASE let me know if you need more information, clarification, or data.
%Attempt 1 - Polyfit
[p,s,mu] = polyfit(p_Tn,p_tn,3);
[Y,delta] = polyval(p,p_Tn,s,mu)
X = linspace(0,0.05,length(Y));
plot(Y,X,'k-')
%Attempt 2 - Non parametric fitting
xq = linspace(0,0.05,100);
p = pchip(p_tn',p_Tn',xq);
pp = ppval(p,xq);
plot(xq,pp);
%Attempt 3 - Smoothingspline
f = fit(p_tn',p_Tn','smoothingspline');
plot(f)
%Attempt 4 - Split upper and lower half of data points and use polyfit
for i = 1:length(p_tn)-1
if p_tn(i) > p_tn(i+1)
x1(i) = p_tn(i) ;
y1(i) = p_Tn(i) ;
elseif p_tn(i) < p_tn(i+1)
x2(i) = p_tn(i) ;
y2(i) = p_Tn(i) ;
end
end
p1 = polyfit(x1,y1,2);
p2 = polyfit(x2,y2,2);
xf1 = linspace(min(x1),0.05);
xf2 = linspace(min(x2),0.05);
f1 = polyval(p1,xf1);
f2 = polyval(p2,xf2);
plot(x1,y1,x2,y2)
plot(xf1,f1,'r--')
plot(xf2,f2,'r')

댓글 수: 2

dpb
dpb 2019년 9월 25일
Make it easy for somebody to help you...attach the data points
Sarah Armstrong
Sarah Armstrong 2019년 9월 25일
Of course! I have p_tn (x values) and p_Tn (y values) attached in a .mat file. Thanks!

댓글을 달려면 로그인하십시오.

 채택된 답변

darova
darova 2019년 9월 25일

0 개 추천

Look HERE and HERE

댓글 수: 6

Sarah Armstrong
Sarah Armstrong 2019년 9월 25일
편집: Sarah Armstrong 2019년 9월 25일
Using your suggestion on this question, I wrote the following and produced this graph...Can I refine this at all? I think this is the closest so far.
figure(2)
% parameter - curve length
t = [0; cumsum(sqrt(diff(p_tn').^2+diff(p_Tn').^2))];
% refine parameter
t1 = linspace(0,t(end));
xt = spline(t,p_tn,t1);
yt = spline(t,p_Tn,t1);
plot(p_tn,p_Tn,'o-r') % original data
hold on
plot(xt,yt) % interpolated data
hold off
Can I refine this at all?
What do you mean?
Maybe polyfit will be better for this
img1.png
load('sarah_data_points.mat')
x = p_tn;
y = p_Tn;
figure(2)
% parameter - curve length
t = [0 cumsum(sqrt(diff(x).^2+diff(x).^2))];
% refine parameter
t1 = linspace(0,t(end));
px = polyfit(t,x,2);
py = polyfit(t,y,2);
x1 = polyval(px,t1);
y1 = polyval(py,t1);
plot(x,y,'o-r') % original data
hold on
plot(x1,y1) % interpolated data
hold off
Another attempt:
  • make X data the scale as Y
  • make interpolation
  • return original scale to X data
load('sarah_data_points.mat')
x = p_tn;
y = p_Tn;
xscale = (max(y)-min(y)) / (max(x)-min(x));
x = xscale*x;
% parameter - curve length
t = [0 cumsum(sqrt(diff(x).^2+diff(y).^2))];
% refine parameter
t1 = linspace(0,t(end));
x1 = spline(t,x,t1);
y1 = spline(t,y,t1);
plot(x/scale,y,'o-r') % original data
hold on
plot(x1/scale,y1) % interpolated data
hold off
Sarah Armstrong
Sarah Armstrong 2019년 9월 26일
Wow, this is beautiful! The sum of the squares and normalizing the values made all the difference -- I never would have guessed. Thank you so much!
I want to apply a linear polyfit between data points that have identical x or y values to straighten out the curve between the first and last couple of data points. Is this possible with a for loop? fig2_sarah_data_points.png.
DOn't know why you need loop? I believe separating data into groups should work!
Or maybe interpolate all data with spline and interp1 and fill with NaN areas you don't want
ind = y(3) < y1 & y1 < y(end-1); % indices between ends
Experiment to get the result you want
Sarah Armstrong
Sarah Armstrong 2019년 9월 30일
Awesome, I will play around with this instead of using a loop. I am also thinking about trying polar co-ordinates to see if that can refine it as well, but for now the curve is accurate enough as-is! Thank you for your help.

댓글을 달려면 로그인하십시오.

추가 답변 (1개)

Ted Shultz
Ted Shultz 2019년 9월 25일

0 개 추천

Because you are looking to make a function of “y” rather than “x”, you would need to flip the X and Y when you solve the equation (this is equivalent to when you rotated in excel).
Try something like this:
p = polyfit(y,x,n)
y1 = linspace(0,4*pi);
x1 = polyval(p,y1);
figure
plot(x,y,'o')

카테고리

도움말 센터File Exchange에서 2-D and 3-D Plots에 대해 자세히 알아보기

질문:

2019년 9월 25일

댓글:

2019년 9월 30일

Community Treasure Hunt

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

Start Hunting!

Translated by