interp1 fails to interpolate on a non-one-to-one function (curve)

87 views (last 30 days)
I hve a set of x-y data such this:
dis0 = []; force0 = [];
which are for example 38 by 1 vectors and I want to interpolate force0 to get its new values on another x values like u_test which is a 100 by 1 vector using interp1 like this:
force0 = interp1(dis0,force0,u_test,'cubic')
but gives me the result like this:
I've tried all methods of interp1 like linear, cubic, makima, etc but could not get what I want. Any suggestions and solutions? How can I interpolate my curve through some other x values without losing its original points?

Answers (1)

John D'Errico
John D'Errico on 4 Apr 2024 at 21:09
Edited: John D'Errico on 4 Apr 2024 at 21:16
interp1 does not fail here. It merely fails to do what it was not programmed to do! Interp1 does as designed. That you try to use it in a way that is meaningless in context of what interp1 is written to do, then what could you possibly expect? This is NOT a question of linear versis cubic, or a spline! This is merely that interp1 is designed to interpolate a function that has only 1 value for any given value of x. Mathematically, interp1 assumes the mapping it will interpolate is a single valued one. So for ANY value of x, it will expect only one value for y, if that presumption fails, then you get garbage.
You have 31 points. You don't supply them, so I'll make some up.
t = linspace(1,2*pi,50);
x = cos(t);
y = sin(2*t);
plot(x,y,'o')
Clearly that is not a single valued mapping. You CANNOT just throw it at interp1 directly, not and hope interp1 will succeed. How can you interpolate it? The simplest way is to do it parametrically. That will mean to interpolate x and y SEPARATELY and independently.
I'll use a linear interpolant. Be careful if you try to use a spline interpolant. Then you would need to be more creative about how to build that parametric vector s. But you can be quite free in how you build the vector sinterp as long as it is merely linear interpolation that is desired, and the data I saw from you does not merit more than a linear interpolation.
s = 1:numel(x);
ninterp = 1000; % 1000 points along the curve
sinterp = linspace(1,numel(x),ninterp);
xinterp = interp1(s,x,sinterp,'linear');
yinterp = interp1(s,y,sinterp,'linear');
plot(x,y,'ro',xinterp,yinterp,'b-')
Again, if you want a smooth interpolant like a spline, a tool like cscvn is recommended. Or you could use my interparc utility (as found on the file exchange for free download.)
  4 Comments
Esi Tesi
Esi Tesi on 5 Apr 2024 at 7:34
Yes, but however my curve has to look like the first curve that I shared above. (original curve with (dis0,force0))
If that's the problem, we can add a small decimal to force0 vector like this:
force0 = cumsum(ones(size(force0)))*eps + force0;
but this does not fix it and I still can't find force0 for corresponding u_test values.
Torsten
Torsten on 5 Apr 2024 at 9:38
Edited: Torsten on 5 Apr 2024 at 9:56
Yes, but however my curve has to look like the first curve that I shared above.
This is the first curve that you shared. The values of dis0 are only sorted. If you now sort force0 accordingly and connect the points, you get the blue curve. And this is the curve that interp1 uses for interpolation.
Look at your first curve that you shared.
Say u_test = 0.02.
Don't you understand that interp1 does not know whether to return -80, 60 or 80 because there are three possible values for force0 ?

Sign in to comment.

Categories

Find more on Interpolation in Help Center and File Exchange

Community Treasure Hunt

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

Start Hunting!