Optimizing an ellipse

Click and drag on the plots below to draw a curve. A gradient descent optimizer will then attempt to find an ellipse that best fits the curve. The plot that incorporates phase usually fits the curve better.

Details

Gradient descent works by attempting to minimize the "error" between the hand-drawn curve and the ellipse, which is computed by summing over the euclidean distances between points on the ellipse and each corresponding point on the hand-drawn curve:

sum(i = 0..N, euclid(ellipse(2 * pi * i / N), handdrawn(i)))

The two plots use two different models of an ellipse. The first is modeled with four configurable parameters a, b, x0, and y0:

(x0 + a * cos(t), y0 + b * sin(t))

This model works ok, but the point where t=0 is always at the 3'oclock position, as shown by the small circle. That prevents the error sum above from ever converging to zero if you draw a loop that doesn't start from the 3 o'clock position.

For example, if you draw a loop starting somewhere on the x axis, and then circle around the origin, then this model would could fit the drawn curve pretty well. But if you draw a loop starting somewhere on the y-axis instead, then the model would be unable to fit it very well. This is because at t=0, the model always has y=y0.

To address this issue, the second model adds a fifth "phase" parameter:

(x0 + a * cos(t + phase), y0 + b * sin(t + phase))

The phase parameter effectively allows the ellipse to rotate. That way, it can fit any hand-drawn ellipse curve regardlesss of where the drawing started. The small circle is the point on the ellipse where t=0, and is usually close to the first point on the hand-drawn ellipse.

The goal of this project was to prove that the phase parameter helps with the problem of optimizing a function that outputs a closed loop. A similar optimization problem which I plan to tackle next is optimizing the curve of an end-effector on an n-bar linkage.

without phase
with phase