Bug in Teensy3 version of CMSIS DSP (v1.1.0) arm_sin_cos_f32()

joepasquariello

Well-known member
I've been working on a T3.5/T3.6 project with some floating-point DSP, and found that there is a bug in the T3 version of arm_sin_cos_f32(). This function is not used anywhere in the T3 core or any TeensyDuino libraries, which use the fixed-point functions, but I wanted to document the issue with the f32 functions in case someone else runs into it.

Teensy3 uses CMSIS DSP v1.1.0 dated 02/15/12
Teensy4 uses CMSIS DSP v1.5.1 dated 01/27/17

In both versions of CMSIS DSP, the source code for functions arm_sin_cos_f32(), arm_sin_f32(), and arm_cos_f32() are each in a separate file. In DSP v1.1.0, each file contains its own lookup
table. The table for arm_sin_cos_f32() is a 360-element table indexed by angle in degrees. The tables in arm_sin_f32() and arm_cos_f32() are 260 elements indexed by the angle in radians. In DSP v1.5.1, all 3 of these functions share a single 512-element table (sinTable_f32) in file arm_common_tables.c.

The DSP v1.1.0 version of arm_sin_cos_f32() has a bug in its table lookup that causes the function to return an incorrect value for small negative angles. Also, it's not well-documented, but the angle argument is in units of degrees, and MUST be in the range -180..180. Angles outside that range will cause incorrect results. The v1.1.0 versions of arm_sin_f32() and arm_cos_f32() take an angle argument in radians, and MUST be in the range 0..2*PI, also returning incorrect results for angles outside that range.

The DSP v1.5.1 version of arm_sin_cos_f32() fixes the bug in the v1.1.0 version. The angle argument is still degrees, but is not restricted to the range -180..180. arm_sin_f32(). The 1.5.1 versions of arm_sin_f32() and arm_cos_f32() still take angle in radians, but are not restricted to the range 0..2*PI. These are all nice improvements.

I wanted to use the new versions in Teensy3 without trying to switch entirely to the newer CMSIS DSP version, so I took 5 source files from DSP v1.5.1 and modified them as follows:

- renamed arm_common_tables.[ch] to arm_sintable_f32.[ch]
- deleted everything from arm_sintable_f32.[ch] except sinTable_f32[]
- add macro FAST_MATH_TABLE_SIZE (512) to arm_sintable_f32.h (all of the functions need it)
- in arm_sin_cos_f32.c, arm_sin_f32.c, and arm_cos_f32.c
replace #include "arm_common_tables.h" with #include "arm_sintable_f32.h"

These 5 files can be added to any Teensy3 project, and if the project uses those functions, the newer versions files will be linked rather than the older versions in the pre-built library in TeensyDuino. No code changes are necessary in the sketch, because the new (v1.5.1) functions have the same signatures are the old ones, so #include "arm_math.h" has the proper declarations.

The advantages of the DSP 1.5.1 versions of these functions over the 1.1.0 versions are:

- 1.5.1 arm_sin_cos_f32() fixes the bug in the v1.1.0 version
- 1.5.1 arm_sin_f32() and arm_cos_f32() are faster because they use linear interpolation rather than polar
- 1.5.1 functions use less code space in total because they share a single lookup table

If you're using T3.5 or T3.6, you can also use standard math library functions sinf() and cosf(), which are actually a bit faster than the CMSIS functions. I didn't test on T3.2, but I think the CMSIS lookup-based versions would be quite a bit faster there, with no FPU.
 

Attachments

  • arm_cos_f32.c
    4.4 KB · Views: 44
  • arm_sin_cos_f32.c
    5.8 KB · Views: 38
  • arm_sin_f32.c
    4.4 KB · Views: 37
  • arm_sintable_f32.c
    9.7 KB · Views: 47
  • arm_sintable_f32.h
    2.4 KB · Views: 42
Back
Top