Gerono Lemniscate
Lately I’ve been doing some game development for fun and was exploring ways to make sprites move in a figure-eight pattern. An online search led me to the Lemniscate of Gerono1, which is a figure-eight curve named after French mathematician Camille-Christophe Gerono2. The term lemniscate describes a curve that produces a continuous figure-eight3. What interested me about the Lemniscate of Gerono was the perceived simplicity; being defined parametrically as4:
x = a * np.sin(t)
y = a * np.cos(t) * np.sin(t)Using python this can be plotted using the following code:
import numpy as np
import matplotlib.pyplot as plt
t = np.linspace(0,2 * np.pi, 1024)
a = 1
x = a * np.sin(t)
y = a * np.cos(t) * np.sin(t)
plt.plot(x,y)
plt.show()The result is a figure-eight curve in the range (+- a, +- a/2)4.

Lemniscate of Gerono
Given parametric equations only contain multiply, sin and cos I thought it would be a fun exercise to implement the curve in Fixed-Point using look up tables5. Implementing the lemniscate in fixed point would allow me to draw the curve on a simple display using a microcontroller.
Fixed point implementation and considerations
I have written before about fixed point but in short it is the technique of representing floating point numbers using integers. The article explains how to generate a fixed point lookup table for sin and cos that uses a uint8_t angle (in the range 0 -> 2PI) as an index. I recommend a look at ARM’s fixed point manual6 which has some example code for implementing basic mathematical operations such as add and multiply etc. Like with the microboids7 project the display is in the range [-1, 1) using Q15 representation. A given (x, y) point in Q15 can then be converted to an integer pixel co-ordinate for writing to an LCD display.
Assuming I followed the aforementioned article to generate the sin and cos lookup tables, the next requirement is a Q15-Arithmetic Multiply function which can be implemented as follows6:
#define MAX_BITS (32)
#define MAX_Q (MAX_BITS >> 1U)
int16_t QMath_Multiply(int16_t a, int16_t b, uint16_t q)
{
ASSERT(q < MAX_Q);
int16_t result = (int16_t)(((int32_t)a * (int32_t)b) >> q);
return result;
}The lemniscate of Gerono can then be implemented as thus:
static uint8_t t;
int16_t a = 0x7FFF /* ~ = 0.99997 in float */
/* x = a * sin(t) */
int16_t x = QMath_Multiply(a, qsin[t], 15);
/* y = a * sin(t) * cos(t) */
int16_t y = QMath_Multiply(a, qsin[t], 15);
y = QMath_Multiply(y, qcos[t], 15);
t++;After converting the Q15 (x, y) point to a pixel co-ordinate the end result is a lemniscate curve:

Lemniscate of Gerono in Q15 fixed point