DFTrig

DFTrig is a simple C library for efficient calculation of basic trigonometric functions (sine/cosine) by lookup table, table generator included.

Description

Some time ago, I needed to draw a watch dial on the small display of car trip computer. I decided to calculate sine / cosine values by lookup table, and I was very surprised when I failed to find a ready-made universal tool for that. So I had to write such tool myself.

DFTrig consists of two parts:

  • Lookup table generator tablegen (written in Java, but that doesn't matter much) that receives several options and produces C code (const struct with lookup table)
  • Small C module that works with lookup table generated by tablegen.

Of course, lookup table contains only minimal information: sine values for just a single quadrant, i.e. [0, 90] degrees. That is fairly enough to calculate sine / cosine for any angle.

The behavior is quite customizable. You may specify:

  • Factor by which each item in the lookup table is multiplied (on per-table basis);
  • Step in degrees between each item in the table (on per-table basis);
  • Type of items in the table (common for the whole C project).

So, depending on your needs, you may:

  • Generate single table for the whole application with max factor, so that any subsystem of your C project may use that single table, providing desired factor, and it will be recalculated if requested factor is other than that of the table;
  • Generate multiple tables, each with ad hoc factor, and each subsystem of your C project uses its dedicated table. Then, values can be returned from table as is, without recalculation; that works faster.

More, if you don't need for 1-degree resolution in some particular table, you may specify step other than 1. Say, in my case with watch dial, I needed for 1 minute resolution, i.e. 6 degrees. This reduces the size of table dramatically (six times), which may be considerable in the embedded world.

Usage

C module needs to be configured by file dftrig_cfg.h; currently there is just one option: DFTRIG_VALUE_TYPE, it represents type of the values in the lookup table. There is default configuration file provided: dftrig_cfg_default.h, so, initially just copy it as dftrig_cfg.h and edit accordingly to your needs.

The library archive (see download links at the bottom) contains source of both Java tablegen and C module, as well as precompiled tablegen.jar.

Example: generate table of integers with step 6 and max factor that may fit in one byte (255) :

java -jar tablegen.jar --type int --factor 255 --step 6

Tablegen will generate the file dftrig_lookup_tbl_255.c with the following contents:

/*
 * This structure is auto-generated by dftrig's tablegen utility.
 * Exact command: java -jar tablegen.jar --type int --factor 255 --step 6
 * Please don't edit it by hand! Use tablegen instead.
 */
const T_DFTrigLookupTbl dftrig_lookup_tbl_255 = {
   .factor = 255,
   .step = 6,
   .table = {
      [0] = 0,  /*    sin(0 degrees) * 255    */
      [1] = 27,  /*    sin(6 degrees) * 255    */
      [2] = 53,  /*    sin(12 degrees) * 255    */
      [3] = 79,  /*    sin(18 degrees) * 255    */
      [4] = 104,  /*    sin(24 degrees) * 255    */
      [5] = 127,  /*    sin(30 degrees) * 255    */
      [6] = 150,  /*    sin(36 degrees) * 255    */
      [7] = 171,  /*    sin(42 degrees) * 255    */
      [8] = 190,  /*    sin(48 degrees) * 255    */
      [9] = 206,  /*    sin(54 degrees) * 255    */
      [10] = 221,  /*    sin(60 degrees) * 255    */
      [11] = 233,  /*    sin(66 degrees) * 255    */
      [12] = 243,  /*    sin(72 degrees) * 255    */
      [13] = 249,  /*    sin(78 degrees) * 255    */
      [14] = 254,  /*    sin(84 degrees) * 255    */
      [15] = 255,  /*    sin(90 degrees) * 255    */
   },
};

Now you should copy contents of that file and paste it somewhere in your project, and then you may get sine like that:

//-- get sin(30) * 255   (returns 127)
dftrig__sin__get_by_deg(&dftrig_lookup_tbl_255, 30, 255);
 
//-- get sin(78) * 100   (returns 98)
dftrig__sin__get_by_deg(&dftrig_lookup_tbl_255, 78, 100);

In the former case, requested factor 255 matches that of table, so, value is returned from table as is without recalculation, that works fast. In the latter case, requested factor 100 is different, so, value from table is recalculated before returning. If you want to avoid recalculation, you may generate second table, with factor 100, and probably step 3:

/*
 * This structure is auto-generated by dftrig's tablegen utility.
 * Exact command: java -jar tablegen.jar --type int --factor 100 --step 3
 * Please don't edit it by hand! Use tablegen instead.
 */
const T_DFTrigLookupTbl dftrig_lookup_tbl_100 = {
   .factor = 100,
   .step = 3,
   .table = {
      [0] = 0,  /*    sin(0 degrees) * 100    */
      [1] = 5,  /*    sin(3 degrees) * 100    */
      [2] = 10,  /*    sin(6 degrees) * 100    */
      [3] = 16,  /*    sin(9 degrees) * 100    */
      [4] = 21,  /*    sin(12 degrees) * 100    */
      [5] = 26,  /*    sin(15 degrees) * 100    */
      [6] = 31,  /*    sin(18 degrees) * 100    */
      [7] = 36,  /*    sin(21 degrees) * 100    */
      [8] = 41,  /*    sin(24 degrees) * 100    */
      [9] = 45,  /*    sin(27 degrees) * 100    */
      [10] = 50,  /*    sin(30 degrees) * 100    */
      [11] = 54,  /*    sin(33 degrees) * 100    */
      [12] = 59,  /*    sin(36 degrees) * 100    */
      [13] = 63,  /*    sin(39 degrees) * 100    */
      [14] = 67,  /*    sin(42 degrees) * 100    */
      [15] = 71,  /*    sin(45 degrees) * 100    */
      [16] = 74,  /*    sin(48 degrees) * 100    */
      [17] = 78,  /*    sin(51 degrees) * 100    */
      [18] = 81,  /*    sin(54 degrees) * 100    */
      [19] = 84,  /*    sin(57 degrees) * 100    */
      [20] = 87,  /*    sin(60 degrees) * 100    */
      [21] = 89,  /*    sin(63 degrees) * 100    */
      [22] = 91,  /*    sin(66 degrees) * 100    */
      [23] = 93,  /*    sin(69 degrees) * 100    */
      [24] = 95,  /*    sin(72 degrees) * 100    */
      [25] = 97,  /*    sin(75 degrees) * 100    */
      [26] = 98,  /*    sin(78 degrees) * 100    */
      [27] = 99,  /*    sin(81 degrees) * 100    */
      [28] = 99,  /*    sin(84 degrees) * 100    */
      [29] = 100,  /*    sin(87 degrees) * 100    */
      [30] = 100,  /*    sin(90 degrees) * 100    */
   },
};

And use that table for calculation with factor 100. There is always a tradeoff between performance / memory.

License

License: BSD.

Download

Library is hosted at bitbucket: https://bitbucket.org/dfrank/dftrig

Discussion

Enter your comment (please, English only). Wiki syntax is allowed:
  _____   __    _  __   _  __  _____
 / ___/  / /   / |/ /  | |/_/ / ___/
/ /__   / /__ /    /  _>  <  / /__  
\___/  /____//_/|_/  /_/|_|  \___/
 
projects/dftrig.txt · Last modified: 2015/09/09 08:42 by dfrank
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0