mirror of
https://github.com/RobTillaart/Arduino.git
synced 2024-10-03 18:09:02 -04:00
0.2.0 FastTrig
This commit is contained in:
parent
febfc3d3ad
commit
e27fc5652e
@ -22,7 +22,7 @@ compile:
|
||||
# - leonardo
|
||||
- m4
|
||||
- esp32
|
||||
# - esp8266
|
||||
- esp8266
|
||||
# - mega2560
|
||||
- rpipico
|
||||
|
||||
|
@ -6,14 +6,23 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
|
||||
## [0.2.0] - 2022-12-02
|
||||
- merged PR #16 for ESP_IDF support
|
||||
- added <stdint.h>
|
||||
- added <stdbool.h>
|
||||
- renamed isinTable to sinTable for readability (breaking change)
|
||||
- edits code for readability
|
||||
- fix itan(90) now returns NAN instead of 0.
|
||||
|
||||
----
|
||||
|
||||
## [0.1.11] - 2022-11-02
|
||||
- add changelog.md
|
||||
- add rp2040 to build-CI
|
||||
- moved version info from readme.md to changelog
|
||||
- no functional changes
|
||||
|
||||
|
||||
## [0.1.10 2022-04-15
|
||||
## [0.1.10] - 2022-04-15
|
||||
- fix #12
|
||||
- split .h in .h and .cpp Needed in case of more complex projects.
|
||||
|
||||
|
4
libraries/FastTrig/CMakeLists.txt
Normal file
4
libraries/FastTrig/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
||||
idf_component_register(SRCS "FastTrig.cpp"
|
||||
INCLUDE_DIRS .)
|
||||
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
|
@ -1,7 +1,7 @@
|
||||
//
|
||||
// FILE: FastTrig.cpp
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.1.11
|
||||
// VERSION: 0.2.0
|
||||
// PURPOSE: Arduino library for a faster approximation of sin() and cos()
|
||||
// DATE: 2011-08-18
|
||||
// URL: https://github.com/RobTillaart/FastTrig
|
||||
@ -13,7 +13,7 @@
|
||||
|
||||
// 91 x 2 bytes ==> 182 bytes
|
||||
// use 65535.0 as divider
|
||||
uint16_t isinTable16[] = {
|
||||
uint16_t sinTable16[] = {
|
||||
0,
|
||||
1145, 2289, 3435, 4572, 5716, 6853, 7989, 9125, 10255, 11385,
|
||||
12508, 13631, 14745, 15859, 16963, 18067, 19165, 20253, 21342, 22417,
|
||||
@ -29,7 +29,7 @@ uint16_t isinTable16[] = {
|
||||
|
||||
|
||||
/* 0.1.4 table
|
||||
uint16_t isinTable16[] = {
|
||||
uint16_t sinTable16[] = {
|
||||
0,
|
||||
1145, 2289, 3435, 4571, 5715, 6852, 7988, 9125, 10254, 11385,
|
||||
12508, 13630, 14745, 15859, 16963, 18067, 19165, 20253, 21342, 22416,
|
||||
@ -46,7 +46,7 @@ uint16_t isinTable16[] = {
|
||||
|
||||
|
||||
// use 255.0 as divider
|
||||
uint8_t isinTable8[] = {
|
||||
uint8_t sinTable8[] = {
|
||||
0, 4, 9, 13, 18, 22, 27, 31, 35, 40, 44,
|
||||
49, 53, 57, 62, 66, 70, 75, 79, 83, 87,
|
||||
91, 96, 100, 104, 108, 112, 116, 120, 124, 128,
|
||||
@ -66,47 +66,47 @@ uint8_t isinTable8[] = {
|
||||
//
|
||||
float isin(float f)
|
||||
{
|
||||
boolean pos = true; // positive
|
||||
if (f < 0)
|
||||
bool negative = (f < 0);
|
||||
if (negative)
|
||||
{
|
||||
f = -f;
|
||||
pos = !pos;
|
||||
negative = true;
|
||||
}
|
||||
|
||||
long x = f;
|
||||
uint8_t r = (f - x) * 256;
|
||||
long whole = f;
|
||||
uint8_t remain = (f - whole) * 256;
|
||||
|
||||
if (x >= 360) x %= 360;
|
||||
if (whole >= 360) whole %= 360;
|
||||
|
||||
int y = x; // 16 bit math is faster than 32 bit
|
||||
int y = whole; // 16 bit math is faster than 32 bit
|
||||
|
||||
if (y >= 180)
|
||||
{
|
||||
y -= 180;
|
||||
pos = !pos;
|
||||
negative = !negative;
|
||||
}
|
||||
|
||||
if (y >= 90)
|
||||
{
|
||||
y = 180 - y;
|
||||
if (r != 0)
|
||||
if (remain != 0)
|
||||
{
|
||||
r = 255 - r;
|
||||
remain = 255 - remain;
|
||||
y--;
|
||||
}
|
||||
}
|
||||
|
||||
// float v improves ~4% on avg error for ~60 bytes.
|
||||
uint16_t v = isinTable16[y];
|
||||
// float value improves ~4% on avg error for ~60 bytes.
|
||||
uint16_t value = sinTable16[y];
|
||||
|
||||
// interpolate if needed
|
||||
if (r > 0)
|
||||
if (remain > 0)
|
||||
{
|
||||
v = v + ((isinTable16[y + 1] - v) / 8 * r) /32; // == * r / 256
|
||||
value = value + ((sinTable16[y + 1] - value) / 8 * remain) / 32; // == * remain / 256
|
||||
}
|
||||
float g = v * 0.0000152590219; // = /65535.0
|
||||
if (pos) return g;
|
||||
return -g;
|
||||
float g = value * 0.0000152590219; // = / 65535.0
|
||||
if (negative) return -g;
|
||||
return g;
|
||||
}
|
||||
|
||||
|
||||
@ -126,39 +126,39 @@ float itan(float f)
|
||||
// so no divide by 65535
|
||||
|
||||
// FOLDING
|
||||
bool mir = false;
|
||||
bool neg = (f < 0);
|
||||
if (neg) f = -f;
|
||||
bool mirror = false;
|
||||
bool negative = (f < 0);
|
||||
if (negative) f = -f;
|
||||
|
||||
long x = f;
|
||||
float rem = f - x;
|
||||
if (x >= 180) x %= 180;
|
||||
float v = rem + x; // normalised value 0..179.9999
|
||||
if (v > 90)
|
||||
long whole = f;
|
||||
float remain = f - whole;
|
||||
if (whole >= 180) whole %= 180;
|
||||
float value = remain + whole; // normalised value 0..179.9999
|
||||
if (value > 90)
|
||||
{
|
||||
v = 180 - v;
|
||||
neg = !neg;
|
||||
mir = true;
|
||||
value = 180 - value;
|
||||
negative = !negative;
|
||||
mirror = true;
|
||||
}
|
||||
uint8_t d = v;
|
||||
if (d == 90) return 0;
|
||||
uint8_t d = value;
|
||||
if (d == 90) return NAN;
|
||||
|
||||
// COS FIRST
|
||||
uint8_t p = 90 - d;
|
||||
float co = isinTable16[p];
|
||||
if (rem != 0)
|
||||
float co = sinTable16[p];
|
||||
if (remain != 0)
|
||||
{
|
||||
float delta = (isinTable16[p] - isinTable16[p - 1]);
|
||||
if (mir) co = isinTable16[p - 1] + rem * delta;
|
||||
else co = isinTable16[p] - rem * delta;
|
||||
float delta = (sinTable16[p] - sinTable16[p - 1]);
|
||||
if (mirror) co = sinTable16[p - 1] + remain * delta;
|
||||
else co = sinTable16[p] - remain * delta;
|
||||
}
|
||||
else if (co == 0) return 0;
|
||||
|
||||
float si = isinTable16[d];
|
||||
if (rem != 0) si += rem * (isinTable16[d + 1] - isinTable16[d]);
|
||||
float si = sinTable16[d];
|
||||
if (remain != 0) si += remain * (sinTable16[d + 1] - sinTable16[d]);
|
||||
|
||||
float ta = si/co;
|
||||
if (neg) return -ta;
|
||||
if (negative) return -ta;
|
||||
return ta;
|
||||
}
|
||||
|
||||
@ -166,50 +166,43 @@ float itan(float f)
|
||||
// some problem at 0 but at least we have a icot(x) cotangent.
|
||||
float icot(float f)
|
||||
{
|
||||
float t = itan(f);
|
||||
if (t == 0) return NAN;
|
||||
return 1.0 / t;
|
||||
float ta = itan(f);
|
||||
if (ta == 0) return NAN;
|
||||
return 1.0 / ta;
|
||||
}
|
||||
|
||||
|
||||
// missing function...
|
||||
// float cot(float f)
|
||||
// {
|
||||
// return 1.0/tan(f);
|
||||
// }
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
//
|
||||
// INVERSE GONIO LOOKUP
|
||||
//
|
||||
float iasin(float f)
|
||||
{
|
||||
bool neg = (f < 0);
|
||||
if (neg)
|
||||
bool negative = (f < 0);
|
||||
if (negative)
|
||||
{
|
||||
f = -f;
|
||||
neg = true;
|
||||
negative = true;
|
||||
}
|
||||
uint16_t val = round(f * 65535);
|
||||
uint16_t value = round(f * 65535);
|
||||
uint8_t lo = 0;
|
||||
uint8_t hi = 90;
|
||||
|
||||
while (hi - lo > 1)
|
||||
{
|
||||
uint8_t mi = (lo + hi) / 2;
|
||||
if (isinTable16[mi] == val)
|
||||
if (sinTable16[mi] == value)
|
||||
{
|
||||
if (neg) return -mi;
|
||||
if (negative) return -mi;
|
||||
return mi;
|
||||
}
|
||||
if (isinTable16[mi] < val) lo = mi;
|
||||
if (sinTable16[mi] < value) lo = mi;
|
||||
else hi = mi;
|
||||
}
|
||||
float delta = val - isinTable16[lo];
|
||||
uint16_t range = isinTable16[hi] - isinTable16[lo];
|
||||
float delta = value - sinTable16[lo];
|
||||
uint16_t range = sinTable16[hi] - sinTable16[lo];
|
||||
delta /= range;
|
||||
if (neg) return -(lo + delta);
|
||||
if (negative) return -(lo + delta);
|
||||
return (lo + delta);
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
//
|
||||
// FILE: FastTrig.h
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.1.11
|
||||
// VERSION: 0.2.0
|
||||
// PURPOSE: Arduino library for a faster approximation of sin() and cos()
|
||||
// DATE: 2011-08-18
|
||||
// URL: https://github.com/RobTillaart/FastTrig
|
||||
@ -11,14 +11,25 @@
|
||||
// HISTORY: see changelog.md
|
||||
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#else
|
||||
#include "Arduino.h"
|
||||
#endif
|
||||
|
||||
|
||||
#define FAST_TRIG_LIB_VERSION (F("0.1.11"))
|
||||
#define FAST_TRIG_LIB_VERSION (F("0.2.0"))
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
extern uint16_t sinTable16[];
|
||||
extern uint8_t sinTable8[];
|
||||
|
||||
extern uint16_t isinTable16[];
|
||||
extern uint8_t isinTable8[];
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
//
|
||||
@ -30,12 +41,9 @@ float icos(float x);
|
||||
|
||||
float itan(float f);
|
||||
|
||||
// some problem at 0 but at least we have a icot(x) cotangent.
|
||||
// 0 returns NAN but we have a icot(x) cotangent.
|
||||
float icot(float f);
|
||||
|
||||
// missing function...
|
||||
// float cot(float f);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
//
|
||||
@ -45,8 +53,13 @@ float iasin(float f);
|
||||
|
||||
float iacos(float f);
|
||||
|
||||
// PLACEHOLDER no good implementation
|
||||
// PLACEHOLDER no good implementation (do not use).
|
||||
float iatan(float f);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
|
@ -44,10 +44,10 @@ This generator sketch can also generate tables with different resolution e.g. 24
|
||||
So depending on the application these tables can be ideal, but verify they meet your requirements.
|
||||
|
||||
The lookup tables used by **isin()** can be used directly in your program, the names are:
|
||||
- **isinTable16\[\]** index 0..90, values need to be (float) divided by 65535.0
|
||||
- **isinTable8\[\]** index 0..90, values need to be (float) divided by 255.0
|
||||
- **sinTable16\[\]** index 0..90, values need to be (float) divided by 65535.0
|
||||
- **sinTable8\[\]** index 0..90, values need to be (float) divided by 255.0
|
||||
|
||||
The **isinTable8** is not really for doing accurate math,
|
||||
The **sinTable8** is not really for doing accurate math,
|
||||
however it is great to use in a LEDstrip or motor movements when less accuracy is needed.
|
||||
|
||||
Although the tables can be written to, it is advised not to do so.
|
||||
|
@ -68,7 +68,7 @@ void generate_bit_sin(int t)
|
||||
|
||||
Serial.print("uint");
|
||||
Serial.print(t > 16 ? 32 : t > 8 ? 16 : 8);
|
||||
Serial.print("_t isinTable");
|
||||
Serial.print("_t sinTable");
|
||||
Serial.print(t);
|
||||
Serial.print("[] = {\n ");
|
||||
for (int i = 0; i <= 90; i++)
|
||||
@ -99,7 +99,7 @@ void generate_bit_cos(int t)
|
||||
|
||||
Serial.print("uint");
|
||||
Serial.print(t > 16 ? 32 : t > 8 ? 16 : 8);
|
||||
Serial.print("_t icosTable");
|
||||
Serial.print("_t cosTable");
|
||||
Serial.print(t);
|
||||
Serial.print("[] = {\n ");
|
||||
for (int i = 0; i <= 90; i++)
|
||||
@ -130,7 +130,7 @@ void generate_bit_tan(int t)
|
||||
|
||||
Serial.print("uint");
|
||||
Serial.print(t > 16 ? 32 : t > 8 ? 16 : 8);
|
||||
Serial.print("_t itanTable");
|
||||
Serial.print("_t tanTable");
|
||||
Serial.print(t);
|
||||
Serial.print("[] = {\n ");
|
||||
for (int i = 0; i <= 90; i++)
|
||||
|
@ -32,7 +32,7 @@ void setup()
|
||||
// print the table
|
||||
for (int i = 0; i <= 90; i++)
|
||||
{
|
||||
Serial.print(isinTable16[i]);
|
||||
Serial.print(sinTable16[i]);
|
||||
Serial.print(", ");
|
||||
if (i % 10 == 0) Serial.println();
|
||||
}
|
||||
@ -52,14 +52,14 @@ int optimize()
|
||||
int rv = 0;
|
||||
for (int i = 1; i < 90; i++) // for every angle
|
||||
{
|
||||
int t = isinTable16[i];
|
||||
int t = sinTable16[i];
|
||||
int idx = 0;
|
||||
float minError = getError(i); // what is the current error
|
||||
bool flag = false;
|
||||
for (int j = -2; j <= 2; j++) // try if adjacent numbers in table give less error.
|
||||
{
|
||||
if (j == 0) continue;
|
||||
isinTable16[i] = t + j;
|
||||
sinTable16[i] = t + j;
|
||||
float e = getError(i);
|
||||
if (e < minError) // if less than we can update the table.
|
||||
{
|
||||
@ -70,8 +70,8 @@ int optimize()
|
||||
}
|
||||
}
|
||||
if (flag) Serial.print('*'); // comment if you do not want see changes.
|
||||
isinTable16[i] = t + idx;
|
||||
Serial.print(isinTable16[i]);
|
||||
sinTable16[i] = t + idx;
|
||||
Serial.print(sinTable16[i]);
|
||||
Serial.print(", ");
|
||||
if (i % 10 == 0) Serial.println();
|
||||
}
|
||||
|
@ -31,7 +31,7 @@
|
||||
// tables generated with other sketch.
|
||||
|
||||
|
||||
uint32_t isinTable24[] = {
|
||||
uint32_t sinTable24[] = {
|
||||
0,
|
||||
292803, 585516, 878052, 1170319, 1462231, 1753697, 2044628, 2334937, 2624535, 2913333,
|
||||
3201244, 3488179, 3774052, 4058776, 4342263, 4624427, 4905183, 5184445, 5462127, 5738146,
|
||||
@ -45,7 +45,7 @@ uint32_t isinTable24[] = {
|
||||
};
|
||||
|
||||
|
||||
uint32_t isinTable20[] = {
|
||||
uint32_t sinTable20[] = {
|
||||
0,
|
||||
18300, 36595, 54878, 73145, 91389, 109606, 127789, 145933, 164033, 182083,
|
||||
200078, 218011, 235878, 253673, 271391, 289026, 306574, 324028, 341383, 358634,
|
||||
@ -59,7 +59,7 @@ uint32_t isinTable20[] = {
|
||||
};
|
||||
|
||||
|
||||
uint16_t isinTable16[] = {
|
||||
uint16_t sinTable16[] = {
|
||||
0,
|
||||
1144, 2287, 3430, 4571, 5712, 6850, 7987, 9121, 10252, 11380,
|
||||
12505, 13625, 14742, 15854, 16962, 18064, 19161, 20251, 21336, 22414,
|
||||
@ -93,9 +93,9 @@ void test_accuracy()
|
||||
for (int i = 0; i <= 90; i++)
|
||||
{
|
||||
float a = sin(i * (PI / 180));
|
||||
float b = (1.0 * isinTable16[i]) / 65535;
|
||||
float c = (1.0 * isinTable20[i]) / 1048575;
|
||||
// float c = (1.0 * isinTable24[i]) / 16777215;
|
||||
float b = (1.0 * sinTable16[i]) / 65535;
|
||||
float c = (1.0 * sinTable20[i]) / 1048575;
|
||||
// float c = (1.0 * sinTable24[i]) / 16777215;
|
||||
Serial.print(a, 8);
|
||||
Serial.print('\t');
|
||||
Serial.print(abs(a - b), 8);
|
||||
@ -134,7 +134,7 @@ void test_performance()
|
||||
start = micros();
|
||||
for (int i = 0; i <= 90; i++)
|
||||
{
|
||||
sum += isinTable16[i] * (1 / 65535.0);
|
||||
sum += sinTable16[i] * (1 / 65535.0);
|
||||
}
|
||||
Serial.println(micros() - start);
|
||||
Serial.println(sum, 8);
|
||||
@ -144,7 +144,7 @@ void test_performance()
|
||||
start = micros();
|
||||
for (int i = 0; i <= 90; i++)
|
||||
{
|
||||
sum += isinTable20[i] * (1 / 1048575.0);
|
||||
sum += sinTable20[i] * (1 / 1048575.0);
|
||||
}
|
||||
Serial.println(micros() - start);
|
||||
Serial.println(sum, 8);
|
||||
@ -154,7 +154,7 @@ void test_performance()
|
||||
start = micros();
|
||||
for (int i = 0; i <= 90; i++)
|
||||
{
|
||||
sum += isinTable24[i] * (1 / 16777215.0);
|
||||
sum += sinTable24[i] * (1 / 16777215.0);
|
||||
}
|
||||
Serial.println(micros() - start);
|
||||
Serial.println(sum, 8);
|
||||
|
@ -15,7 +15,7 @@
|
||||
"type": "git",
|
||||
"url": "https://github.com/RobTillaart/FastTrig"
|
||||
},
|
||||
"version": "0.1.11",
|
||||
"version": "0.2.0",
|
||||
"license": "MIT",
|
||||
"frameworks": "*",
|
||||
"platforms": "*",
|
||||
|
@ -1,5 +1,5 @@
|
||||
name=FastTrig
|
||||
version=0.1.11
|
||||
version=0.2.0
|
||||
author=Rob Tillaart <rob.tillaart@gmail.com><pete.thompson@yahoo.com>
|
||||
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
|
||||
sentence=Arduino library with interpolated lookup for sin() and cos()
|
||||
|
@ -39,55 +39,53 @@ unittest_teardown()
|
||||
}
|
||||
|
||||
|
||||
unittest(test_isinTable16)
|
||||
unittest(test_sinTable16)
|
||||
{
|
||||
fprintf(stderr,"Table16 error is < 0.1%% \n");
|
||||
const float degrees2radians = PI/180.0;
|
||||
const float degrees2radians = PI / 180.0;
|
||||
for (int i = 0; i < 91; i++)
|
||||
{
|
||||
assertEqualFloat(sin(i * degrees2radians), isinTable16[i] / 65535.0, 0.001);
|
||||
assertEqualFloat(sin(i * degrees2radians), sinTable16[i] / 65535.0, 0.001);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unittest(test_isinTable8)
|
||||
unittest(test_sinTable8)
|
||||
{
|
||||
fprintf(stderr,"Table8 error is < 1%% \n");
|
||||
const float degrees2radians = PI/180.0;
|
||||
fprintf(stderr,"Table8 error is < 1.0%% \n");
|
||||
const float degrees2radians = PI / 180.0;
|
||||
for (int i = 0; i < 91; i++)
|
||||
{
|
||||
assertEqualFloat(sin(i * degrees2radians), isinTable8[i] / 255.0, 0.01);
|
||||
assertEqualFloat(sin(i * degrees2radians), sinTable8[i] / 255.0, 0.01);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unittest(test_max_error_table16)
|
||||
{
|
||||
fprintf(stderr,"Table16 max error: ");
|
||||
const float degrees2radians = PI/180.0;
|
||||
float m = 0;
|
||||
const float degrees2radians = PI / 180.0;
|
||||
float maxError = 0;
|
||||
for (int i = 0; i < 91; i++)
|
||||
{
|
||||
float t = abs(sin(i * degrees2radians) - (isinTable16[i] / 65535.0));
|
||||
if (t > m) m = t;
|
||||
float t = abs(sin(i * degrees2radians) - (sinTable16[i] / 65535.0));
|
||||
if (t > maxError) maxError = t;
|
||||
}
|
||||
fprintf(stderr,"%2.4f\n", m);
|
||||
assertEqualFloat(0, m, 0.001);
|
||||
fprintf(stderr,"Table16 max error: %2.5f\n", maxError);
|
||||
assertEqualFloat(0, maxError, 0.001);
|
||||
}
|
||||
|
||||
|
||||
unittest(test_max_error_table8)
|
||||
{
|
||||
fprintf(stderr,"Table8 max error: ");
|
||||
const float degrees2radians = PI/180.0;
|
||||
float m = 0;
|
||||
const float degrees2radians = PI / 180.0;
|
||||
float maxError = 0;
|
||||
for (int i = 0; i < 91; i++)
|
||||
{
|
||||
float t = abs(sin(i * degrees2radians) - (isinTable8[i] / 255.0));
|
||||
if (t > m) m = t;
|
||||
float t = abs(sin(i * degrees2radians) - (sinTable8[i] / 255.0));
|
||||
if (t > maxError) maxError = t;
|
||||
}
|
||||
fprintf(stderr,"%2.4f\n", m);
|
||||
assertEqualFloat(0, m, 0.01);
|
||||
fprintf(stderr,"Table8 max error: %2.5f\n", maxError);
|
||||
assertEqualFloat(0, maxError, 0.01);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user