-
Notifications
You must be signed in to change notification settings - Fork 554
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[BUG] sin/cos integer overflow on 16-bit CPUs #415
Comments
Terrible bug in the fast sin/cos added last year, resulting in rough sine waves and a spike from +1 to -1 at pi/2
The maximum value of an int16 is 32767. For this reason I would expect for a int16 sin calculation the maximum value in the table should be this one. To achieve the highest accuracy the whole table should be recalculated for this value. |
The table is unsigned, so it can go up to 65535. I went with 32768 so the quadrant points would return exactly 1.0 and -1.0, but thinking about it now, the return has a float multiplier so it could use (1.0f/65535.0f) and return the correct amplitude anyway. This is the table generation code: for(int i = 0; i <= 64; i++) fprintf(file, "%i,", (int)(sin((i * M_PI/2) / 64) * 32768 + 0.5)); And here is the result with the constant changed to 65535: I tested it and the speed is no different, but average error and RMS error relative to stdlib sin are also almost no different (about one millionth) so I don't know if we should bother changing it. Theoretically the (1.0f/32768.0f) multiplier should be possible to do faster on FPU-less platforms using integer math on the exponent of the float value, but we were never able to make the compiler do it. ldexp was the best bet, but for some reason it's even slower than a regular multiply. On another note, I was reading through the thread where we developed this code, and runger had already spotted and fixed the 16-bit overflow bug before we ever introduced it to the actual codebase. I don't remember which of us did the initial commit, but apparently whoever it was copy/pasted the wrong version from the thread. |
Fix for #415 sin/cos integer overflow on 16-bit CPUs
In the new release v2.3.4 |
Thanks to ChrisMicro on the forum for finding this bug in the fast sin/cos added last year #285
Forum thread https://community.simplefoc.com/t/simplefoc-sin-calculation/5131
There are two potential solutions:
Solution 1 is to change the lookup table to signed 16-bit and fudge the last entry to 32767 so it doesn't overflow, and add some casts to do part of the interpolation calculation in 32-bit:
return (1.0f/32768.0f) * (t1 + (int)((((int32_t)t2 - t1) * frac) >> 8));
Solution 2 is to change t1 and t2 to int32_t. This will be a few cycles slower on 16-bit platforms, but retain the behavior of returning exactly 1.0 at pi/2 and -1.0 at 3pi/2.
I would be fine with either. I think 1 was my original intent, but after all the iterations testing the speed and accuracy of the calculations, I forgot to make the final edits.
EDIT: No measured speed difference when testing, so I went with solution 2. Pull request #416
The text was updated successfully, but these errors were encountered: