Fix16 LUT sin cos fixmath.h

I’m facing some problem using sin/cos Look Up Table from fixmath.h
Here my code:


#include "Pokitto.h"
#include "fixmath.h"

Pokitto::Core g;
Pokitto::Display d;

int main ()
{
    g.begin();

    while (g.isRunning())
    {
        if (g.update())
        {

            Fix16 toRad=fix16_from_float(PI/180.0);
            Fix16 radius=fix16_from_int(30);
            for(int a=0; a<360; a+=15)
            {
                Fix16 angle=fix16_from_int(a);
                Fix16 angleRad=angle * toRad;

                Fix16 xtf=fix16_mul(fix16_sin(angleRad),radius);
                Fix16 ytf=fix16_mul(fix16_cos(angleRad),radius);
                int xt=55+fix16_to_int(xtf);
                int yt=44+fix16_to_int(ytf);

                d.drawLine(55,44,xt,yt);
            }

        }
    }
}

And here the result:

image

It should draw a line starting from the center of the screen every 15 degrees with a radius of 30 pixel.
From my test sin cos output are wrong.
Does anyone use sin cos from fixmath.h before?

Are you sure you’re supposed to be using degrees and radians instead of simply 0-255?

1 Like

I am using it a lot in P-Zero demo. I think I fixed a bug in the sine function. I will come back later when I am at my PC.

1 Like

I believe it accept a Fix16 angle in radians. But without doc is not so clear.

That’s will explain a lot of my problems. Thanks in advance.

Here are two fixed lines:

fix16_t fix16_sin(fix16_t inAngle) {
	fix16_t tempAngle = inAngle % (fix16_pi << 1);

	#ifdef FIXMATH_SIN_LUT
	if(tempAngle < 0)
		tempAngle += (fix16_pi << 1);

	fix16_t tempOut;
	if(tempAngle >= fix16_pi) {
		tempAngle -= fix16_pi;
		if(tempAngle >= (fix16_pi >> 1))
			tempAngle = fix16_pi - tempAngle;
		//tempOut = -(tempAngle >= _fix16_sin_lut_count ? fix16_one : _fix16_sin_lut[tempAngle]);
		tempOut = -(_fix16_sin_lut[(255*tempAngle)/(fix16_pi>>1)]);
	} else {
		if(tempAngle >= (fix16_pi >> 1))
			tempAngle = fix16_pi - tempAngle;
		//tempOut = (tempAngle >= _fix16_sin_lut_count ? fix16_one : _fix16_sin_lut[tempAngle]);
		tempOut = _fix16_sin_lut[(255*tempAngle)/(fix16_pi>>1)];

1 Like

image

Particles goes where they should go now :grin:
a

Thanks!!!
Ok, now why that hack?

My guest is that _fix16_sin_lut the table itself is wrong. Maybe calculated for a different architecture?

4 Likes

The sine function was expecting different number of items than the lut contained.

I will make a PR to GitHub.

2 Likes

Beware just some useless though ahead.

Summary

Don’t you think the fix is suspicious?
From the code it seems fix16_sin is expecting inAngle to be radians, in fact it apply modulo of 2PI at the begin.
But then you have to normalized the tempAngle to 0-255 value, to correctly access the look up array.
The exactly original same code is all scattered in the web if you make a search, how is it possible nobody fix it?

Where is the original fixmath hosted? Is this it?

It could be that it’s been reported but not acted upon.
It could be that the version bundled with the PokittoLib is out of date.
It could be that hardly anyone is actually using the library.

Might as well be using brads (binary radians) from the start.

2 * Pi is Tau, and Tau is better than Pi.

2 Likes

That can’t be true, because the answer to the universe has no Tau:

kuva

If Euler sez its so, then it is so.

Maybe the original implementation used much bigger LUT, but it is at some point optimized for MCU usage.

Ahem

:thinking:

I hope it was not me

:sweat:

I may have accidentally done something to the LUT at some point

:cold_sweat:

But not sure

:blush: :innocent: :crossed_fingers:

3 Likes

I don’t want to derail this, but I need to point this out…

cis(x) = e ^ (i * x) = cos(x) + (i * sin(x))
cos(pi) = -1 and sin(pi) = 0 therefore cis(pi) = -1
cos(tau) = 1 and sin(tau) = 0 therefore cis(tau) = 1
So although cis(pi) + 1 = 0, equally cis(tau) - 1 = 0.

Such is the power of tau. :P

(Either that or I’m really bad at maths, which is probable.)

I have no clue about that Tau thingy :wink: But I made a PR of the fix. This time I tried to make it on-the-go, using only the GitHub web interface: created a branch, edited a file, committed, created a PR. Very handy for small, pre-tested, changes like this!

1 Like

Bingo! Original Lut Table is bigger. Too much for low mem device.
But using

//#define FIXMATH_SIN_LUT
#define FIXMATH_NO_CACHE
#define FIXMATH_FAST_SIN

avoid completely the use of LUT with good result

3 Likes

This is great. Many hours of entertainment reading the Manifesto and following the links therein.

1 Like