Hi. Yeah, that looks like the kind of thing. Also see:

https://ece.uwaterloo.ca/~dwharder/Maplesque/Bezier/BestFittingBezierCurves.pptEssentially what your PDF is showing is a 24-element LUT, but instead of having discrete values or linearly interpolated steps it uses a series of Bezier curves (a spline) to smooth out the curve.

You would want to implement this using 32-bit signed integers with 8-bit fixed point. It simplifies things to use floats but it will also be slower, so best to avoid this.

A cubic bezier curve is a curve with two fixed end points (anchors) and two control points that define the curve. A variable that is in the range 0-1 (usually called t) defines how far along the curve you are from the start point when t=0 to the end point when t=1. The formula for a Bezier curve is (where ^ is 'to the power of'):

Code: Select all

`v = P0 * (1 - t)^3`

+ P1 * 3 * (1 - t)^2 * (t)

+ P2 * 3 * (1 - t) * (t)^2

+ P3 * (t)^3

For the first curve the control points are at: 0, (2*sqrt(2) - 1) / 7, 2 * (2*sqrt(2) - 1) / 7, sqrt(2) / 2.

In 8-bit fixed point this means:

To calculate t (in 8-bit FP), we know the range of the segment of the line for this 1/8th of the curve is PI/4, so t = 256 * angle / (PI/4)

Code: Select all

`t = 256 * angle / 0.78539816`

i = 256 - t

tsq = (t * t) >> 1 // 15-bit fixed point t^2

tcu = tsq * t // 23-bit fixed point t^3

isq = (i * i) >> 1 // 15-bit fixed point (1-t)^2

icu = isq * i // 23-bit fixed point (1-t)^3

// Now calculate the point on the curve

y = (0 * icu)

y = y + (67 * (3 * isq * t))

y = y + (133 * (3 * i * tsq))

y = y + (181 * (tcu))

// y is now a 31-bit fixed point value representing sin(angle) where 0 <= angle <= PI/4

Of course, all this work only calculates the first 1/8th of the curve.

You have two choices now. The first is to look at the first PI/2 of the sine curve and produce an if statement for the two curves, then tweak the values depending on the angle sector, and the second is to create a look up table of all the points, get the curve segment, multiply by 4 and use the Bezier points starting at that index (LUT[ix], LUT[ix+1], LUT[ix+2], LUT[ix+3]).

This is an example of the first possibility, because not requiring look-ups saves memory overhead, which would need to be 16-bit entries, so 48 bytes of LUT (and also an ugly global variable).

Code: Select all

`angle = angle / 0.78539816 // Divide by sin(PI/4): Integer part is the sector, decimal part is the range 0-1`

sector = floor(angle)

t = 256 * (angle - sector)

if (sector & 2) // Then between PI/2 and 3*PI/2

sector = sector ^ 1

t = 256 - t

i = 256 - t

....... tsq, tcu, .....

if ((sector & 1) == 0)

// Bezier curve part 1 (use values above)

else

// Bezier curve part 2

if (sector & 4) // Then between PI and 2*PI

y = -y

result = y / 2147483648.0 // Convert 31-bit FP to a float, 0-1

This completely avoids floating point and should get the result required. I haven't tested this though, and have worked solely from your PDF.

What I would suggest is to use simulation in Flowcode to test any routine like this, and draw on the GLCD component to display the results.

I hope this is enough to go on. Cheers,

Jonny