MATLAB - interpolating a 2D curve with multiple Y's per X - matlab

I would like to interpolate a data set, but a given X can have multiple Y's, example given below:
A(:,1:2,1)=
95.2343 70.6159
96.4501 71.5573
97.4430 72.7315
98.9743 72.8699
100.0470 71.7690
100.3872 70.2699
100.7797 68.7837
102.1478 68.0814
103.6851 68.0521
105.0307 68.7966
105.8972 70.0666
106.7177 71.3665
107.7095 72.5416
108.9175 73.4924
110.3574 74.0309
111.8943 73.9859
113.3936 73.6446
114.6645 72.7794
115.5911 71.5522
116.2426 70.1591
116.3922 68.6286
116.3503 67.0914
116.7771 65.6147
117.9045 64.5692
119.4065 64.2425
120.9432 64.2923
122.2526 65.0975
122.9486 66.4682
122.8841 68.0043
122.5492 69.5051
122.2403 71.0109
122.0819 72.5402
These are points along the body of a snake, digitized from top-down video. Their posture frequently results in 2 or more Y points per X, and because they turn (often dramatically) while I need to maintain a consistent XY framework, I can't just rotate my X and Y.
I can make a spline function using cscvn, and when plotted using fnplt it looks great! But the moment I try to get values back using ppval, it all goes to crap and I get two curves that look nothing like the snake or what's shown in fnplt.
IMAGE HERE:
http://imgur.com/aYJ0Ftj
All I want is to fit a curve to those points, and convert that curve to a series of maybe 200 XY points.
I'm assuming that there is some obscenely simple answer, some command I've just never turned up in my searching, but I cannot find it for the life of me. This is quite far outside my usual skillset (I'm more used to crawling through swamps catching anything scaly or slimy), so I'm sure I'm overlooking something totally obvious to a skilled MATLAB user.
Thanks!

Perhaps this is what you already tried, but a comment was a bit small, so here is one idea that may help you
x = [1 2 3 4 5 6 7 6 5];
y = [1 4 4 3 2 2 2 3 4];
t = 1:length(x);
figure; plot(x,y)
xx = interp1(t,x,1:.01:length(x),'pchip');
yy = interp1(t,y,1:.01:length(x),'pchip');
hold on; plot(xx,yy,'g')
I avoided the unique values restriction on interp by interpolating x and y both as a function of t.

OK, thanks to Yvon and Trogdor, I managed to crudely cludge together some code:
ht=[1:32];
tx=linspace(1,32,500);
m=ht;
m(2:3,:)=squeeze(A(:,:,i))';
m1=m(1,:);
m2=m(2,:);
m3=m(3,:);
SFX=spline(m1,m2);
pSFX=ppval(SFX,tx);
SFY=spline(m1,m3);
pSFY=ppval(SFY,tx);
AS(:,1,i)=pSFX;
AS(:,2,i)=pSFY;
plot(AS(:,1,i),AS(:,2,i),'Marker','o');
It's riddled with pointless variables, steps, and redundancies, but I'm an anatomist, so that makes me comfortable (seriously, google 'recurrent laryngeal nerve').
How do I add reputation for y'all?

Related

Why is the resultant of my improfile function returning with a mirrored graph in MATLAB?

I am currently running improfile on MATLAB with a line going through the center of the picture below:
After doing so, I'm plotting the resultant using the code below:
xi = [1 size(d_Img,2) size(d_Img,2) 1];
yi = [ceil(size(d_Img,1)/2), ceil(size(d_Img,1)/2), ceil(size(d_Img,1)/2 ),ceil(size(d_Img,1)/2)];
c_d = improfile(d_Img,xi,yi);
c_c = improfile(c_Img,xi,yi);
c_d = c_d';
c_c = c_c';
size_c = size(c_d);
n = 1:size_c(2);
plot(n,c_d);
And here is the plot:
Why are the curves mirroring each other? I am asking to gain a better understanding of what exactly improfile seems to be achieving in MATLAB.
improfile computes something like a "path integral", it gives you the image intensity values around a user specified path. For example, if you use:
improfile(img,[1 1],[1 size(img,2)]);
It gives the same as img(:,1). This is because the path you are using in improfile is from (1,1) to (1,size(img,2)) , meaning the first row. However you could definitely add more complicated paths.
In your case you are going trow a path defined by 4 points. The points are, if I substitute your equation by the resultant numbers:
(1,79)->(134,79)->(134,79)->(1,79). Thus, looking at this, it is obvious that your result should be mirrored, because you are integrating over a line the way there, and back!
Sidenote:
you can do plot(c_d); and forget about that n

GUI solving equations project

I have a Matlab project in which I need to make a GUI that receives two mathematical functions from the user. I then need to find their intersection point, and then plot the two functions.
So, I have several questions:
Do you know of any algorithm I can use to find the intersection point? Of course I prefer one to which I can already find a Matlab code for in the internet. Also, I prefer it wouldn't be the Newton-Raphson method.
I should point out I'm not allowed to use built in Matlab functions.
I'm having trouble plotting the functions. What I basically did is this:
fun_f = get(handles.Function_f,'string');
fun_g = get(handles.Function_g,'string');
cla % To clear axes when plotting new functions
ezplot(fun_f);
hold on
ezplot(fun_g);
axis ([-20 20 -10 10]);
The problem is that sometimes, the axes limits do not allow me to see the other function. This will happen, if, for example, I will have one function as log10(x) and the other as y=1, the y=1 will not be shown.
I have already tried using all the axis commands but to no avail. If I set the limits myself, the functions only exist in certain limits. I have no idea why.
3 . How do I display numbers in a static text? Or better yet, string with numbers?
I want to display something like x0 = [root1]; x1 = [root2]. The only solution I found was turning the roots I found into strings but I prefer not to.
As for the equation solver, this is the code I have so far. I know it is very amateurish but it seemed like the most "intuitive" way. Also keep in mind it is very very not finished (for example, it will show me only two solutions, I'm not so sure how to display multiple roots in one static text as they are strings, hence question #3).
function [Sol] = SolveEquation(handles)
fun_f = get(handles.Function_f,'string');
fun_g = get(handles.Function_g,'string');
f = inline(fun_f);
g = inline(fun_g);
i = 1;
Sol = 0;
for x = -10:0.1:10;
if (g(x) - f(x)) >= 0 && (g(x) - f(x)) < 0.01
Sol(i) = x;
i = i + 1;
end
end
solution1 = num2str(Sol(1));
solution2 = num2str(Sol(2));
set(handles.roots1,'string',solution1);
set(handles.roots2,'string',solution2);
The if condition is because the subtraction will never give me an absolute zero, and this seems to somewhat solve it, though it's really not perfect, sometimes it will give me more than two very similar solutions (e.g 1.9 and 2).
The range of x is arbitrary, chosen by me.
I know this is a long question, so I really appreciate your patience.
Thank you very much in advance!
Question 1
I think this is a more robust method for finding the roots given data at discrete points. Looking for when the difference between the functions changes sign, which corresponds to them crossing over.
S=sign(g(x)-f(x));
h=find(diff(S)~=0)
Sol=x(h);
If you can evaluate the function wherever you want there are more methods you can use, but it depends on the size of the domain and the accuracy you want as to what is best. For example, if you don't need a great deal of accurac, your f and g functions are simple to calculate, and you can't or don't want to use derivatives, you can get a more accurate root using the same idea as the first code snippet, but do it iteratively:
G=inline('sin(x)');
F=inline('1');
g=vectorize(G);
f=vectorize(F);
tol=1e-9;
tic()
x = -2*pi:.001:pi;
S=sign(g(x)-f(x));
h=find(diff(S)~=0); % Find where two lines cross over
Sol=zeros(size(h));
Err=zeros(size(h));
if ~isempty(h) % There are some cross-over points
for i=1:length(h) % For each point, improve the approximation
xN=x(h(i):h(i)+1);
err=1;
while(abs(err)>tol) % Iteratively improve aproximation
S=sign(g(xN)-f(xN));
hF=find(diff(S)~=0);
xN=xN(hF:hF+1);
[~,I]=min(abs(f(xN)-g(xN)));
xG=xN(I);
err=f(xG)-g(xG);
xN=linspace(xN(1),xN(2),15);
end
Sol(i)=xG;
Err(i)=f(xG)-g(xG);
end
else % No crossover points - lines could meet at tangents
[h,I]=findpeaks(-abs(g(x)-f(x)));
Sol=x(I(abs(f(x(I))-g(x(I)))<1e-5));
Err=f(Sol)-g(Sol)
end
% We also have to check each endpoint
if abs(f(x(end))-g(x(end)))<tol && abs(Sol(end)-x(end))>1e-12
Sol=[Sol x(end)];
Err=[Err g(x(end))-f(x(end))];
end
if abs(f(x(1))-g(x(1)))<tol && abs(Sol(1)-x(1))>1e-12
Sol=[x(1) Sol];
Err=[g(x(1))-f(x(1)) Err];
end
toc()
Sol
Err
This will "zoom" in to the region around each suspected root, and iteratively improve the accuracy. You can tweak the parameters to see whether they give better behaviour (the tolerance tol, the 15, number of new points to generate, could be higher probably).
Question 2
You would probably be best off avoiding ezplot, and using plot, which gives you greater control. You can vectorise inline functions so that you can evaluate them like anonymous functions, as I did in the previous code snippet, using
f=inline('x^2')
F=vectorize(f)
F(1:5)
and this should make plotting much easier:
plot(x,f(x),'b',Sol,f(Sol),'ro',x,g(x),'k',Sol,G(Sol),'ro')
Question 3
I'm not sure why you don't want to display your roots as strings, what's wrong with this:
text(xPos,yPos,['x0=' num2str(Sol(1))]);

Data fitting for time dependent matrix sets in Matlab

I have 6 data sets, each data set is a 576by576 matrix. Each set of data represents measurements taken within 30 second intervals. e.g. set1 at t=0, set2 at time =30, ... ,set5 at 150 seconds.
You can look at these sets as frames if you will. I need to take first data point (1,1) from each data set -> (1,1,0), (1,1,3),(1,1,6),(1,1,9),(1,1,12),(1,1,15) and based on those 6 points find a fitting formula, then assign that general solution to the first spot of my solution matriz SM(1,1). I need to do this for every data point in the 6 sets until I have a 576by576 solution matriz.
if everything goes right I should be able to plot SM(0s)=set1, SM(30s)=set2,etc. but not only that. SM(45) should return a prediction of measurements at t=45 and so on and so forth. The purpose is to have one matrix than can predict data fluctuation from time t= 0 to 150 seconds.
Additional information:
1.- Each data point is independent form the rest of the data points in the same set.
2.- it is a none-linear fit
3.- all values are real
Does Matlab have an optimization tool for this kind of problem?
Should I treat the problem as 1D data fit and create a for loop that does the job 576^2 times?
(I don't even know where to begin)
Feel free to ask or edit anything if I wasn't clear enough. I am not sure that I've chosen the most precise title for this kind of problem.Thanks
Update:
Based on Guddu's answer I came up with this:
%% Loadint data Matrix A
A(:,:,1) = abs(set1);
A(:,:,2) = abs(set2);
A(:,:,3) = abs(set3);
A(:,:,4) = abs(set4);
A(:,:,5) = abs(set5);
A(:,:,6) = abs(set6);
%% Creating Solution Matrix B
t=0:30:150;
SM=zeros([576 576 150]);
for i=1:576
for j=1:576
y=squeeze(A(i,j,1:6));
f=fit(t',y,'smoothingspline');
data=feval(f,1:150);
SM(i,j,:)=data;
end
end
%% Plotting Frame at t=45
figure(1);
imshow(SM(:,:,45),[])
I am not sure if this is the most efficient way to do it, but it works. I am open to new ideas or suggestions. Thanks
i would suggest your main data matrix would be of size (6,576,576) -> a. first point (1,1) from each dataset would be a(1,1,1), a(2,1,1), a(3,1,1) .. a(6,1,1). as you have said each point (i,j) in each dataset from other point (k,l), i would suggest treat each position (i,j) for all datasets separately from other positions. so it would be looping 576*576 times. code could be something like this
t=0:30:150;
for i=1:576
for j=1:576
datavec=squeeze(a(1:6,i,j)); % Select (i,j) point from all 6 frames
% do the curve fitting and save in SM(i,j)
end
end
i am just curious what kind of non-linear function you want to fit to 6 points. this might not be the answer you want but it was kind of long to put in a comment

Finding normal distributions overlap using double Integral (dblquad) in MATLAB. Strange behaviour

I am calculating the overlap of two normal bivariate distribution using the following function
function [ oa ] = bivariate_overlap_integral(mu_x1,mu_y1,mu_x2,mu_y2)
%calculating pdf. Using x as vector because of MATLAB requirements for integration
bpdf_vec1=#(x,y,mu_x,mu_y)(exp(-((x-mu_x).^2)./2.-((y-mu_y)^2)/2)./(2*pi));
%calcualting overlap of two distributions at the point x,y
overlap_point = #(x,y) min(bpdf_vec1(x,y,mu_x1,mu_y1),bpdf_vec1(x,y,mu_x2,mu_y2));
%calculating overall overlap area
oa=dblquad(overlap_point,-100,100,-100,100);
You can see that this involves taking a double integral (x: -100 to 100, y:-100 to 100, ideally -inf to inf but suffices at the moment) from the function overlap_point which is minimum of 2 pdf-s given by the function bpdf_vec1 of two distributions at the point x,y.
Now, PDF is never 0, so I would expect that the larger the area of the interval, the larger will the end result become, obviously with the negligible difference after a certain point. However, it appears that sometimes, when I decrease the size of the interval the result grows. For instance:
>> mu_x1=0;mu_y1=0;mu_x2=5;mu_y2=0;
>> bpdf_vec1=#(x,y,mu_x,mu_y)(exp(-((x-mu_x).^2)./2.-((y-mu_y)^2)/2)./(2*pi));
>> overlap_point = #(x,y) min(bpdf_vec1(x,y,mu_x1,mu_y1),bpdf_vec1(x,y,mu_x2,mu_y2));
>> dblquad(overlap_point,-10,10,-10,10)
ans =
0.0124
>> dblquad(overlap_point,-100,100,-100,100)
ans =
1.4976e-005 -----> strange, as theoretically cannot be smaller then the first answer
>> dblquad(overlap_point,-3,3,-3,3)
ans =
0.0110 -----> makes sense that the result is less than the first answer as the
interval is decreased
Here we can check that the overlaps are (close to) 0 at the border points of interval.
>> overlap_point (100,100)
ans =
0
>> overlap_point (-100,100)
ans =
0
>> overlap_point (-100,-100)
ans =
0
>> overlap_point (100,-100)
ans =
0
Does this perhaps have to do with the implementation of dblquad, or am I making a mistake somewhere? I use MATLAB R2011a.
Thanks
CONGRATULATIONS! You win the award for being the 12 millionth person to ask essentially this question. :) What I'm trying to say is this is an issue that everyone stumbles over at first. Honestly, this question gets asked over and over again, so really, this question should be marked as a dup.
What happens with these things is a bivariate normal is essentially a delta function when viewed from far enough away. And you don't need to really spread that region out too far, since the normal density drops off fast. It is essentially zero over most of the domain you are trying to integrate over, at least to within the tolerances employed.
So then if the quadrature happens to hit some sample points near the areas where there is mass, then you may get some realistic estimate of your integral. But if all the tool sees are numbers that are essentially zero over the entire domain, it concludes the integral is zero. Remember, adaptive integration tools are NOT omniscient. They do not know anything about your function. It is a black box to them. These are NOT symbolic tools.
BTW, this is NOT something I'd expect to see consistently different for Octave versus MATLAB. It is only an issue of the adaptive integrator, and where it chooses to set its sample points down.
OK, here are my octave results.
>fomat long
>z10 = dblquad(overlap_point,-10,10,-10,10)
z10 = 0.0124193303284589
>z100 = dblquad(overlap_point,-100,100,-100,100)
z100 = 0.0124193303245106
>z100 - z10
ans = -3.94835379669001e-012
>z10a = dblquad(overlap_point,-10,10,-10,10,1e-8)
z10a = 0.0124193306514996
>z100a = dblquad(overlap_point,-100,100,-100,100,1e-8)
z100a = 0.0124193306527155
>z100a-z10a
ans = 1.21588676627038e-012
BTW. I've noticed this type of problem before with numerical solutions. Sometimes you make a change that you expect will improve the accuracy of the result (in this case by making your limits closer to the ideal case of the full plane), but instead you get the opposite effect and the result becomes less accurate. What's happening in this case is that by going out "wider", to -100..100, you're shifting the focus away from where the really important action is happening in your function, which is close to the origin. At some point the implementation of dblquad that you're using must start increasing the intersample distance as you increase the limits, and then it starts missing some important stuff close to the origin.
Maybe someone with running a later version of matlab can check this out and see if it's been improved.

Issue in mean square error plot

There are 2 column vectors A,B containing 100 data values. I intend to plot the MSE(mean square error ) using the following code but all I get is a single dot instead of a line plot. Please help how to go about it.
A=x(:,1);
B=y(:,1);
er=(double(A)-double(B)).^2;
row_er=mean(er,2); % variable changed
plot(row_er);
This script works fine.
A = randn(10, 1);
B = randn(10, 1);
er=(double(A)-double(B)).^2;
row_e=mean(er,2);
plot(row_e)
Probably you have a typo (row_er)
row_e=mean(er,2);
plot(row_er);
Please notice that the command mean returns the mean of a vector (which is one simple value). If you want to plot plot the square error then you just plot((A-B).^2).
But... If you are interested in plotting the mean square error with, say, 10 samples average, you will have a plot with only 10 points (100 / 10 because each 10 data points are averaged to give you one point).
The command would be
plot(blkproc((A-B).^2,[10,1],'mean'))
hope it helps.