4

Forum

I've got a set of data that apparently forms an ellipse in 3D space (not an ellipsoid, but a curve in 3D). Being inspired by following thread http://au.mathworks.com/matlabcentral/newsreader/view_thread/65773 and with the help from someone ,I manage to get the optimization code running and outputs a set of best parameters x (vector). However, when I try to use this x to replicate the ellipse,the outcomes is a strange straight line in the space. I have been stacked on this for days., still don't know what went wrong....pretty much devastated... I hope someone can shed some light on this. The Mathematica formulations for the ellipse follows the same as in the above thread ,where

The 3D-ellipse is given by: (x;y;z) = (z1;z2;z3) + R(alpha,beta,gamma).(acos(phi); b*sin(phi);0)

where: * z is the translation vector. * R is the rotation matrix (using Euler angles, we first rotate alpha rad around the x-axis, then beta rad around the y-axis and finally gamma rad around the z-axis again). * a is the long axis of the ellipse * b is the short axis of the ellipse.

Here is my target function for optimization (ellipsefit.m)

function [merit]= ellipsefit(x, vmatrix) % x is the initial parameters, vmatrix stores the datapoints
load vmatrix.txt % In vmatrix, the data are stored: N rows x 3 columns
a = x(1);
b = x(2);c
alpha = x(3);
beta = x(4);
gamma = x(5);
z = [x(6),x(7),x(8)];
t = z'
[dim1, dim2]=size(vmatrix);
% construction of rotation matrix R(alpha,beta,gamma)
R1 = [cos(alpha), sin(alpha), 0; -sin(alpha), cos(alpha), 0; 0, 0, 1];v
R2 = [1, 0, 0; 0, cos(beta), sin(beta); 0, -sin(beta), cos(beta)];
R3 = [cos(gamma), sin(gamma), 0; -sin(gamma), cos(gamma), 0; 0, 0, 1];
R = R3*R2*R1;
% first  compute  vector phi (in the length of the data) by minimizing for every
% point in the data set the distance of this point to the ellipse
% (with its initial parameters a,b,alpha,beta,gamma, z1,z2,z3 held fixed) with respect to phi.
for i=1:dim1
point=vmatrix(i,:)';
dist=@(phi)sum((R*[a*cos(phi); b*sin(phi); 0]+t-point)).^2; 
phi(i)=fminbnd(dist,0,2*pi);
end
v = [a*cos(phi); b*sin(phi); zeros(size(phi))];
P = R*v;
%The targetfunction is: g = (xi1,xi2,xi3)' -(z1,z2,z3)'-R(alpha,beta,gamma)(a cos(phi), b sin(phi),0)'
% Construction of distance function
merit = [vmatrix(:,1)-z(1)-P(1),vmatrix(:,2)-z(2)-P(2),vmatrix(:,3)-z(3)-P(3)]; 
merit = sqrt(sum(sum(merit.^2)))
end

here is the main function for parameters initialization and call for opts (xfit.m)

function [y] = xfit (x)
x= [1 1 1 1 1 1 1 1] % initial parameters
[x] = fminsearch(@ellipsefit,x) % set the distance minimum as the target function
y=x
end

code to reconstruct the ellipse in scatter points (ellipsescatter.txt)

x= [0.655,0.876,1.449,2.248,1.024,0.201,-0.11,0.002] % values obtained according to above routines
a = x(1);
b = x(2);
alpha = x(3);
beta = x(4);
gamma = x(5);
z = [x(6),x(7),x(8)];
R1 = [cos(alpha), sin(alpha), 0; -sin(alpha), cos(alpha), 0; 0, 0, 1];
R2 = [1, 0, 0; 0, cos(beta), sin(beta); 0, -sin(beta), cos(beta)];
R3 = [cos(gamma), sin(gamma), 0; -sin(gamma), cos(gamma), 0; 0, 0, 1];
R = R3*R2*R1;
phi=linspace(0,2*pi,100)
v = [a*cos(phi); b*sin(phi); zeros(size(phi))];
P = R*v;
u = P'

and last the data points (vmatrix)

0.002037965 0.004225765 0.002020202
0.005766671 0.007269193 0.004040404
0.010004802 0.00995638  0.006060606
0.014444336 0.012502725 0.008080808
0.019083408 0.014909533 0.01010101
0.023967745 0.017144827 0.012121212
0.03019849  0.01969697  0.014591289
0.038857283 0.022727273 0.017839321
0.045443501 0.024730475 0.02020202
0.051213405 0.026346492 0.022222222
0.061038174 0.028787879 0.02555121
0.069408829 0.030575164 0.028282828
0.075785861 0.031818182 0.030321465
0.088818543 0.033954681 0.034343434
0.095538223 0.03490652  0.036363636
0.109421234 0.036499949 0.04040404
0.123800737 0.037746182 0.044444444
0.131206601 0.038218171 0.046464646
0.146438211 0.038868525 0.050505051
0.162243245 0.039117883 0.054545455
0.178662839 0.03893748  0.058585859
0.195740664 0.038296774 0.062626263
0.204545539 0.037790433 0.064646465
0.222781268 0.036340005 0.068686869
0.23715887  0.034848485 0.071748051
0.251787024 0.033009003 0.074747475
0.26196429  0.031542949 0.076767677
0.278510276 0.028787879 0.079919236
0.294365342 0.025757576 0.082799669
0.306221108 0.023197784 0.084848485
0.31843759  0.020305704 0.086868687
0.331291367 0.016967964 0.088888889
0.342989936 0.013636364 0.090622484
0.352806191 0.010606061 0.091993214
0.36201461  0.007575758 0.093211986
0.376385537 0.002386324 0.094949495
0.386214665 -0.001515152    0.096012
0.396173756 -0.005800677    0.096969697
0.406365393 -0.010606061    0.097799682
0.417897899 -0.016666667    0.098516141
0.428059375 -0.022727273    0.098889844
0.436894505 -0.028787879    0.09893196
0.444444123 -0.034848485    0.098652697
0.45074522  -0.040909091    0.098061305
0.455830971 -0.046969697    0.097166076
0.457867157 -0.05   0.096591789
0.46096663  -0.056060606    0.095199991
0.461974832 -0.059090909    0.094368708
0.462821268 -0.063709158    0.092929293
0.46279206  -0.068181818    0.091323015
0.462224312 -0.071212121    0.090097745
0.461247257 -0.074242424    0.088770148
0.459194871 -0.07812596 0.086868687
0.456406121 -0.0818267  0.084848485
0.45309565  -0.085162601    0.082828283
0.449335762 -0.088184223    0.080808081
0.445185841 -0.090933095    0.078787879
0.440695103 -0.093443633    0.076767677
0.435904796 -0.095744683    0.074747475
0.429042582 -0.098484848    0.072052312
0.419877272 -0.101489369    0.068686869
0.41402731  -0.103049401    0.066666667
0.407719192 -0.104545455    0.064554798
0.395265308 -0.106881864    0.060606061
0.388611992 -0.107880111    0.058585859
0.374697979 -0.10945186 0.054545455
0.360058411 -0.11051623 0.050505051
0.352443612 -0.11084211 0.048484848
0.336646801 -0.111097219    0.044444444
0.320085063 -0.110817414    0.04040404
0.31150078  -0.110465333    0.038383838
0.293673303 -0.109300395    0.034343434
0.275417637 -0.107575758    0.030396076
0.265228963 -0.106361993    0.028282828
0.251914589 -0.104545455    0.025603647
0.234385536 -0.101745907    0.022222222
0.223443994 -0.099745394    0.02020202
0.212154519 -0.097501571    0.018181818
0.20046153  -0.09497557 0.016161616
0.188298809 -0.092121085    0.014141414
0.17558878  -0.088883868    0.012121212
0.162241674 -0.085201142    0.01010101
0.148154337 -0.081000773    0.008080808
0.136529019 -0.077272727    0.006507255
0.127611912 -0.074242424    0.005361311
0.116762238 -0.070350086    0.004040404
0.103195122 -0.065151515    0.002507114
0.095734279 -0.062121212    0.001725236
0.081719652 -0.056060606    0.000388246
0   0   0
Steven Cheng
  • 43
  • 1
  • 5
  • From a cursory look at your code the only difference between the implementation of the ellipse generation in the merit function and the reconstruction after the fit is the loop where you generate `phi` values. I can't tell what the purpose of that is but it's absent in the reconstruction. – Buck Thorn Mar 14 '15 at 20:57
  • If I understand the problem you are trying to solve correctly, you are trying to fit an ellipse to a set of data points in 3D space that lie on a plane. Is that right? – Buck Thorn Mar 14 '15 at 21:53
  • Yes, you are correct. That is exactly what I'm trying to do.As regards to your comment on Phi, it does exist in the reconstruction part as phi=linspace(0,2*pi,100). The ideal was to use a set of initial parameters to calculate phi vectors (by minimizing for every point in the data set the distance of this point to the ellipse), then through optimization routines to best parameters, then graph the ellipse in 3D using those parameters within a spread of phi in [0:2*pi] space. Does it seems to be a correct logic ? – Steven Cheng Mar 15 '15 at 00:30
  • If your approach still does not work, you might try the following: identify the plane common to all these points (you could do this by least squares fitting) to make a rotation matrix that you can use to rotate the points into the xy plane. Then it should be relatively trivial to fit the points to an ellipse. – Buck Thorn Mar 15 '15 at 18:41
  • I attempted the method I suggest and it worked with your data, but it required rewriting your objective function. Also, I understand the purpose of the loop to determine phi, and it looks like you are computing the merit function the wrong way. My advise is to use that same loop to determine phi values to generate the merit function. – Buck Thorn Mar 16 '15 at 09:29
  • Thanks for getting back to me. I'm not quite sure about the objective function you mentioned about. I consider myself very new to Matlab, do you mind if I have a look at your code which is working ? – Steven Cheng Mar 16 '15 at 13:43
  • Ok, I went ahead and posted an answer following this approach. – Buck Thorn Mar 16 '15 at 13:59

1 Answers1

6

This answer is not a direct fit in 3D, it instead involves first a rotation of the data so that the plane of the points coincides with the xy plane, then a fit to the data in 2D.

% input: data, a N x 3 array with one set of Cartesian coords per row

% remove the center of mass
CM = mean(data);
datap = data - ones(size(data,1),1)*CM;


% now rotate all points into the xy plane ...
% start by finding the plane:

[u s v]=svd(datap);

% rotate the data into the principal axes frame:

datap = datap*v;


% fit the equation for an ellipse to the rotated points

x= [0.25 0.07 0.037 0 0]'; % initial parameters    
options=1;
xopt = fmins(@fellipse,x,options,[],datap) % set the distance minimum as the target function

This is the function fellipse, based on the function provided:

function [merit]= fellipse(x,data) % x is the initial parameters, data stores the datapoints

a = x(1);
b = x(2);
alpha = x(3);    
z = x(4:5);

R = [cos(alpha), sin(alpha), 0; -sin(alpha), cos(alpha), 0; 0, 0, 1];
data = data*R; 

merit = 0;

[dim1, dim2]=size(data);
for i=1:dim1
    dist=@(phi)sum( ( [a*cos(phi);b*sin(phi)] + z - data(i,1:2)').^2 ); 
    phi=fminbnd(dist,0,2*pi);
    merit = merit+dist(phi);
end

end

Also, note again that this can be turned into a fit directly in 3D, but this answer is just as good if you can assume the data points lie approx. in a 2D plane. The current solution is likely much more efficient then a solution in 3D with additional parameters.

Hopefully the code is self-explanatory. I recommend looking at the link included in the OP, it explains the purpose of the loop over phi.

And this is how you can inspect the result of the fit:

a = xopt(1);
b = xopt(2);
alpha = xopt(3);
z = [xopt(4:5) ; 0]';

phi = linspace(0,2*pi,100)';
simdat = [a*cos(phi) b*sin(phi) zeros(size(phi))];
R = [cos(alpha), -sin(alpha), 0; sin(alpha), cos(alpha), 0; 0, 0, 1];
simdat = simdat*R  + ones(size(simdat,1), 1)*z ; 


figure, hold on
plot3(datap(:,1),datap(:,2),datap(:,3),'o')
plot3(simdat(:,1),simdat(:,2),zeros(size(simdat,1),1),'r-')

Edit

The following is a 3D approach. It does not appear to be very robust as it is quite sensitive to the choice of starting parameters. Some improvements may be necessary.

CM = mean(data);
datap = data - ones(size(data,1),1)*CM;
xopt = [  0.07 0.25 1 -0.408976 0.610120 0 0  0]';
options=1;
xopt = fmins(@fellipse3d,xopt,options,[],datap) % set the distance minimum as the target function

The function fellipse3d is

function [merit]= fellipse3d(x,data) % x is the initial parameters, data stores the datapoints

a = abs(x(1));
b = abs(x(2));
alpha = x(3);
beta = x(4);
gamma = x(5);
z = x(6:8)';

[dim1, dim2]=size(data);

R1 = [cos(alpha), sin(alpha), 0; -sin(alpha), cos(alpha), 0; 0, 0, 1];
R2 = [1, 0, 0; 0, cos(beta), sin(beta); 0, -sin(beta), cos(beta)];
R3 = [cos(gamma), sin(gamma), 0; -sin(gamma), cos(gamma), 0; 0, 0, 1];
R = R3*R2*R1;

data = (data - z(ones(dim1,1),:))*R; 

merit = 0;
for i=1:dim1
    dist=@(phi)sum( ([a*cos(phi);b*sin(phi);0]  - data(i,:)').^2 ); 
    phi=fminbnd(dist,0,2*pi);
    merit = merit+dist(phi);
end
end

You can visualize the results with

a = xopt(1);
b = xopt(2);
alpha = -xopt(3);
beta = -xopt(4);
gamma = -xopt(5);
z = xopt(6:8)' + CM;

dim1 = 100;
phi = linspace(0,2*pi,dim1)';

simdat = [a*cos(phi) b*sin(phi) zeros(size(phi))];

R1 = [cos(alpha), sin(alpha), 0; ...
     -sin(alpha), cos(alpha), 0; ... 
        0, 0, 1];

R2 = [1, 0, 0;  ...
      0, cos(beta), sin(beta);  ...
      0, -sin(beta), cos(beta)];

R3 = [cos(gamma), sin(gamma), 0;  ...
      -sin(gamma), cos(gamma), 0;  ...
           0, 0, 1];

R = R1*R2*R3;

simdat = simdat*R + z(ones(dim1,1),:); 

figure, hold on
plot3(data(:,1),data(:,2),data(:,3),'o')
plot3(simdat(:,1),simdat(:,2),simdat(:,3),'r-')
Buck Thorn
  • 5,024
  • 2
  • 17
  • 27
  • I should add a comment: this implementation is with octave but it should be analogous on matlab, with possible differences in how vars are passed to the optimization functions. – Buck Thorn Mar 16 '15 at 19:53
  • Thanks. If I understand the code correctly, function [merit]= fellipse_2(x,data) should be function [merit]= fellipse_2(x,datap) ? – Steven Cheng Mar 17 '15 at 03:45
  • and If I understand correctly, your solution was trying to project 3D data onto a 2D plane (in this case XY plane), and then fit the a, b, alpha, z(x), z(y). This sort of resolved the problem partially and offered a possible approach that may be carried further. I was wondering if I then fix a, b, alpha, z(x), z(y), and repeat the same process on other planes, will it eventually yield Opts in 3D space ? – Steven Cheng Mar 17 '15 at 03:55
  • Again, thanks for your time and effort. wish to vote this answer as 'useful', but without success. the pages says ' need reputation'... – Steven Cheng Mar 17 '15 at 03:55
  • You're right about fellipse_2 naming, sorry about the messup with the function name. You can of course repeat with other planes ad nauseam, as long as you are pretty confident the points lie mostly on planes it should work. The only thing to watch out for is the use of svd and the rotation of the points performed after that. I believe svd sorts the principal axis so that the first two should always be the "largest" (the two "largest" ones correspond to the plane on which your points lie, in technical terms they correspond to the largest singular values). – Buck Thorn Mar 17 '15 at 09:50
  • I am not sure how you intend to use this. For instance, if you would like to get the angle at which the original plane of an ellipse lay relative to the xy plane, you can compute that from the vectors in "v" obtained from svd. I am not sure what you mean about "fixing" values of the 2D parameters for fits to other ellipses, or about building up Opts in 3D space. Is it an ellipsoid you wish to fit, and you have a collection of slices of the ellipsoid? I would say fixing parameters will then probably not work since a and b most certainly will change, but prob not z or alpha. – Buck Thorn Mar 17 '15 at 09:58
  • Once you understand the code you may feel like going back and performing the fit directly in 3D. It may be very slow to converge, as it seemed to me (this is in part because the simplex method is reliable but very slow). I could try this but I think the code you posted already contains most of the answer. The approach here is just easier to understand and prob faster. – Buck Thorn Mar 17 '15 at 10:03
  • Finally, don't worry about voting as useful, it was a good exercise, and thanks for accepting the answer. Gave you a +1 for persistence :-) – Buck Thorn Mar 17 '15 at 10:04
  • I'm not trying to fit the data with an ellipsoid, I just wish to fit them with an ellipse in 3D. I agree with you that 'fixing' the parameters obtained in 2D plane is not a good ideal because they are actually different values in 3D. – Steven Cheng Mar 17 '15 at 11:49
  • I'm a bit confused. In this way you get a' b' alpha' zx' zy' in XY plane. and using the same method one could get a'' b'' beta'' zy'' zz'' in YZ plane, and a''' b''' gamma''' zz''' zx''' in ZX plane. but I really want to know is the a b alpha beta gamma zx zy zz. – Steven Cheng Mar 17 '15 at 11:56
  • Do you think that if I use x = [average (a', a'', a'''), average (b', b'', b'''),average (alpha', alpha'', alpha'''),average (beta', beta'', beta'''),average (gamma', gamma'', gamma'''),average (zx', zx'', zx'''),average (zy', zy'', zy'''),average (zz', zz'', zz''') ] as initial value and start 1 direct 3D fit will generate anything ? – Steven Cheng Mar 17 '15 at 12:02
  • I guess to solve my problem, a direct 3D data fit is a must. you mentioned the this can be transfer to a direct 3D fit, can you show me how? As I thought my original code still have some underlined problems. much appreciated. – Steven Cheng Mar 17 '15 at 12:04
  • I had a look at this post https://stackoverflow.com/questions/28963126/fitting-an-ellipse-through-orbital-data. He was dealing an exactly the same issue, and his direct fit seems to be working. unfortunately, I tried to run his code but never success. – Steven Cheng Mar 17 '15 at 12:08
  • I tried a 3d version now. It involved a small change in the function but fits converge slowly and are not very robust in that the starting parameters have to be picked carefully and the fits can converge on bad solutions. This could be due simply to the choice of optimization engine on Octave. Things may work better with MATLAB. – Buck Thorn Mar 18 '15 at 00:19
  • Before running the optimization I tested manually trial starting values for the ellipse parameters beta and gamma which describe the orientation of the ellipse in 3D. With some tinkering it (kind of) worked and I will post the code as an update to my answer, but I think the original answer is still pretty good - adding extra fitting parameters complicates simplex convergence. – Buck Thorn Mar 18 '15 at 00:20
  • The problem with the 2D fit is with obtaining a set of parameters that reproduce the ellipse in 3D. The value of z depends on the center of the set of points, while the alpha/beta/gamma pars depend on v but I haven't done the derivation (it requires relating the Euler angles to the angles represented by cosines in v). – Buck Thorn Mar 18 '15 at 00:20
  • The averaging method you suggest does not make sense, or at least I don't understand what you are proposing exactly. The link you provide is to a solution in Python. I haven't tried it myself but there seem to be some good hints in there. You may find this a more promising direction to pursue. The solution I posted is incomplete in that you still need to obtain the angles and z. If I get a chance I will do this a little later. – Buck Thorn Mar 18 '15 at 00:20
  • I noticed by the way an error in your definition of R2. Your code shows `R2 = [0, 0, 1; 0, cos(beta), sin(beta); 0, -sin(beta), cos(beta)];` but it should read `R2 = [1, 0, 0; 0, cos(beta), sin(beta); 0, -sin(beta), cos(beta)];` – Buck Thorn Mar 18 '15 at 00:32
  • I understand that initial parameters are very important to the fittings, and there may exist some local minimums. Looking forward to your updated code, although 2D fitting is working fine, 3D fitting is essential to this problem. – Steven Cheng Mar 18 '15 at 13:10
  • ever mind the averaging method, I just thought it may be useful for get some initial values. That python solution seems to be working,but I just cannot get it running...(don't know why but that code just wouldn't run) – Steven Cheng Mar 18 '15 at 13:12
  • Thanks for the reminding though, indeed it's an error. – Steven Cheng Mar 18 '15 at 13:13
  • I posted a 3d solution, although I found it does not converge reliably. This could be because of the nature of the problem, because of the optimization engine I am using, or some bug. Please run my code and see if it works for you, that is about as much as I can work on this for now. If I come up with something else I will post it. – Buck Thorn Mar 18 '15 at 14:06
  • Hi, Try hard. thanks for the updated code. I have to say that the 3D fit is not work well as the 2D fit. I guess this is due to both the optimization engine and initial values and the nature of this problem. but I'm happy to settle it for now. Thank you again, for you continuing efforts and time. – Steven Cheng Mar 19 '15 at 05:09