Fit Curve to a "C" shape

28 views (last 30 days)
Christopher Axten
Christopher Axten on 29 May 2021
Commented: Christopher Axten on 30 May 2021
Hey all,
I'm trying to use the curve fitting utilities to fit data although I'm having trouble. To make a simple example I am trying to fit a "C" shape with the code below. As you can see in the attached figure, the fitted curve does not follow the points, I'm assuming because such a curve would return two values for f(x) on the interval of x equals -1 to 1. My intended workaround is to make two splines, but this quickly becomes annoying for my actual problem, so I'm looking for a solution where Matlab draws a curve through the points in the order that are entered (kind of like the plotting utility). Any thoughts would be appreciated.
Thanks,
Chris
x = [1 0 -1 0 1];
y = [-1 -1 0 1 1];
f = fit(x',y','smoothingspline');
plot(f,x,y,'o')
xlim([-2 2])
ylim([-2 2])
  1 Comment
Christopher Axten
Christopher Axten on 29 May 2021
Found an answer online for anyone else with the issue:
They really should just add an example like this to the spline documentation page for clarity.

Sign in to comment.

Accepted Answer

John D'Errico
John D'Errico on 29 May 2021
Edited: John D'Errico on 29 May 2021
A spline produces a FUNCTION, SINGLE VALUED. That is, for any x, it is assumed there is a single y. Is that the case for you? NO.
In that case, you need to convert this to a problem that is so. Or you need to use a tool designed to handle non-single valued relationships, so general curvilinear arcs in the plane.
x = [1 0 -1 0 1];
y = [-1 -1 0 1 1];
[theta,R] = cart2pol(x,y);
theta = unwrap(theta);
We need to be careful, and use unwrap here. It will resolve jumps in polar angle as the curve wraps around. Otherwise, spline will get confused.
The simple solution, since your function already lives nicely in a non-translated polar coordinate frame around the origin, is to do as I did above, now just use an interpolant. Spline will suffice, or we could be even more lazy and use interp1.
r_of_theta = spline(theta,R);
th_interp = linspace(min(theta),max(theta),100);
[x_interp, y_interp] = pol2cart(th_interp,fnval(r_of_theta,th_interp));
plot(x,y,'ro',x_interp,y_interp,'b-')
axis equal
grid on
Remember to use unwrap!
This works nicely enough, at least for this simple problem. For more complicated problems, you may want to try my interparc code, as found on the file exchange. It could handle more complicated problems, even ones where the curve crosses itself. Find it here:
xyint = interparc(100,x,y);
plot(x,y,'ro',xyint(:,1),xyint(:,2),'b-')
axis equal
grid on
It produced a subtly different curve shape, because the spline it uses is a subtly different spline model. But the nice thing about interparc is it does not ask you to do anything special like understand a conversion to polar coordinates, or to understand why unwrap was necessary in my first fit.
  9 Comments
Image Analyst
Image Analyst on 30 May 2021
This doesn't look like a C shape. Anyway, are you trying to do
  1. a fit (regression where the points may not necessarily go through your training points), or
  2. an interpolation (where you have additional points in between training points but also goes through the training points as well)?
Which one? I'm betting on interpolation. You have a flat-topped red curve because you're interpolating at points that do not include your training points. I don't have the curve fitting toolbox so I can't run your code. What x values do you want to interpolate? Some set of x values that does not include the training points, or additional x values in addition to the training points? Seems like the latter since you didn't like the flat red top. So I think you can do
xDesired = sort(unique([xTraining, xAdditional]));
yDesired = spline(x, y, xDesired);
Christopher Axten
Christopher Axten on 30 May 2021
You're right it doesn't, my intention with the "C" was to find a solution for splining something that isn't a fuction, like in the lower x coordinates of the data, so in the future I'll be more forward with the exact problem at hand.
I am ultimately looking for the derivative of the data, so I was looking for a fit that I could differentiate. I initially used a second order finite difference to approximate it (pasted below) but it doesn't do very well near the front, as you would imagine. I don't know how much better a spline can do, but at least it would be smoother. There will be a point where the derivative (dUe/dx) is infinite because of how x doubles back, but I can avoid that point.
NOTE: I did figure out final answer to what I'm trying to do. It is unlikely your background is in the aerospace industry, but I was trying to work with the edge velocity from a stagnation point on an airfoil. The work around is to start x at the stagnation point, rather than the geometric leading edge, which makes the whole thing a function and all of the difficult parts go away.
Thank you to John, Image, and Walter for your help and thoughts!
dUdx = zeros(1,length(x));
for d = 2:length(x)-1
dUdx(d) = (Ue(d+1)-Ue(d-1))/(2*x(d+1)-x(d-1));
end

Sign in to comment.

More Answers (3)

Walter Roberson
Walter Roberson on 29 May 2021
You will not be able to do this in cartesian coordinates. You will need to transform to some other coordinate system, such as angle (independent) and magnitude (dependent) relative to the centroid.

Sulaymon Eshkabilov
Sulaymon Eshkabilov on 29 May 2021
Just a piecewise interpolation can be done in this case, but not fit model calculation:
clearvars
x = [1 0 -1 0 1];
y = [-1 -1 0 1 1];
N = 1:numel(x);
xy = [x;y];
SP = makima(N, xy);
%SP = pchip(N, xy);
IN = linspace(1,numel(x));
INTER = ppval(SP, IN);
plot(x,y,'bd', INTER(1,:),INTER(2,:), 'r-', 'linewidth', 2)
legend('DATA','Interpolation', 'location', 'best')
  1 Comment
Christopher Axten
Christopher Axten on 29 May 2021
Sulaymon,
Thank you for the response! This is pretty close to what I found in another question after I posted my question, and it worked pretty well. My actual problem is more complex than the example "C" I presented, so I am going to compare this approach and the polar transformation approach that John outlined.
Thanks,
Chris

Sign in to comment.


Image Analyst
Image Analyst on 30 May 2021
You can fit the data to an ellipse, like in my attached demo. Then when you construct the curve you can just crop off any fitted values with x > your max x. Would an ellipse work for you?
Please attach a .mat file with your actual (x,y) data - sometimes simple data like you posted are too "perfect" and cause problems, like if your "simple" x or y values are perfect duplicates but your actual data don't have duplicates.
  1 Comment
Christopher Axten
Christopher Axten on 30 May 2021
Hey, thank you for the response. I posted an image of the points I am trying to fit under John's comment. I don't think an ellipse would fit my actual problem well, but it would probably work great for the example I based the question on. Sorry for the miscommunication there, I was trying to keep it simple for brevity.

Sign in to comment.

Products

Community Treasure Hunt

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

Start Hunting!