ISSDK  1.7
IoT Sensing Software Development Kit
approximations.c
Go to the documentation of this file.
1 /*
2  * The Clear BSD License
3  * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc.
4  * Copyright 2016-2017 NXP
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without modification,
8  * are permitted (subject to the limitations in the disclaimer below) provided
9  * that the following conditions are met:
10  *
11  * o Redistributions of source code must retain the above copyright notice, this list
12  * of conditions and the following disclaimer.
13  *
14  * o Redistributions in binary form must reproduce the above copyright notice, this
15  * list of conditions and the following disclaimer in the documentation and/or
16  * other materials provided with the distribution.
17  *
18  * o Neither the name of the copyright holder nor the names of its
19  * contributors may be used to endorse or promote products derived from this
20  * software without specific prior written permission.
21  *
22  * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE.
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
27  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 
36 /*! \file approximations.c
37  \brief Math approximations file
38 
39  Significant efficiencies were found by creating a set of trig functions
40  which trade off precision for improved power/CPU performance. Full details
41  are included in Application Note AN5015: Trigonometry Approximations
42 */
43 
44 #include "math.h"
45 #include "stdlib.h"
46 #include "stdint.h"
47 
48 #include "approximations.h"
49 
50 // function returns an approximation to angle(deg)=asin(x) for x in the range -1 <= x <= 1
51 // and returns -90 <= angle <= 90 deg
52 
53 // maximum error is 10.29E-6 deg
54 float fasin_deg(float x)
55 {
56  // for robustness, check for invalid argument
57  if (x >= 1.0F) return 90.0F;
58  if (x <= -1.0F) return -90.0F;
59 
60  // call the atan which will return an angle in the correct range -90 to 90 deg
61  // this line cannot fail from division by zero or negative square root since |x| < 1
62  return (fatan_deg(x / sqrtf(1.0F - x * x)));
63 }
64 
65 // function returns an approximation to angle(deg)=acos(x) for x in the range -1 <= x <= 1
66 // and returns 0 <= angle <= 180 deg
67 
68 // maximum error is 14.67E-6 deg
69 float facos_deg(float x)
70 {
71  // for robustness, check for invalid arguments
72  if (x >= 1.0F) return 0.0F;
73  if (x <= -1.0F) return 180.0F;
74 
75  // call the atan which will return an angle in the incorrect range -90 to 90 deg
76  // these lines cannot fail from division by zero or negative square root
77  if (x == 0.0F) return 90.0F;
78  if (x > 0.0F) return fatan_deg((sqrtf(1.0F - x * x) / x));
79  return 180.0F + fatan_deg((sqrtf(1.0F - x * x) / x));
80 }
81 
82 // function returns angle in range -90 to 90 deg
83 
84 // maximum error is 9.84E-6 deg
85 float fatan_deg(float x)
86 {
87  float fangledeg; // compute computed (deg)
88  int8_t ixisnegative; // argument x is negative
89  int8_t ixexceeds1; // argument x is greater than 1.0
90  int8_t ixmapped; // argument in range tan(15 deg) to tan(45 deg)=1.0
91 #define TAN15DEG 0.26794919243F // tan(15 deg) = 2 - sqrt(3)
92 #define TAN30DEG 0.57735026919F // tan(30 deg) = 1/sqrt(3)
93  // reset all flags
94  ixisnegative = ixexceeds1 = ixmapped = 0;
95 
96  // test for negative argument to allow use of tan(-x)=-tan(x)
97  if (x < 0.0F)
98  {
99  x = -x;
100  ixisnegative = 1;
101  }
102 
103  // test for argument above 1 to allow use of atan(x)=pi/2-atan(1/x)
104  if (x > 1.0F)
105  {
106  x = 1.0F / x;
107  ixexceeds1 = 1;
108  }
109 
110  // at this point, x is in the range 0 to 1 inclusive
111  // map argument onto range -tan(15 deg) to tan(15 deg)
112  // using tan(angle-30deg) = (tan(angle)-tan(30deg)) / (1 + tan(angle)tan(30deg))
113  // tan(15deg) maps to tan(-15 deg) = -tan(15 deg)
114  // 1. maps to (sqrt(3) - 1) / (sqrt(3) + 1) = 2 - sqrt(3) = tan(15 deg)
115  if (x > TAN15DEG)
116  {
117  x = (x - TAN30DEG) / (1.0F + TAN30DEG * x);
118  ixmapped = 1;
119  }
120 
121  // call the atan estimator to obtain -15 deg <= angle <= 15 deg
122  fangledeg = fatan_15deg(x);
123 
124  // undo the distortions applied earlier to obtain -90 deg <= angle <= 90 deg
125  if (ixmapped) fangledeg += 30.0F;
126  if (ixexceeds1) fangledeg = 90.0F - fangledeg;
127  if (ixisnegative) fangledeg = -fangledeg;
128 
129  return (fangledeg);
130 }
131 
132 // function returns approximate atan2 angle in range -180 to 180 deg
133 
134 // maximum error is 14.58E-6 deg
135 float fatan2_deg(float y, float x)
136 {
137  // check for zero x to avoid division by zero
138  if (x == 0.0F)
139  {
140  // return 90 deg for positive y
141  if (y > 0.0F) return 90.0F;
142 
143  // return -90 deg for negative y
144  if (y < 0.0F) return -90.0F;
145 
146  // otherwise y= 0.0 and return 0 deg (invalid arguments)
147  return 0.0F;
148  }
149 
150  // from here onwards, x is guaranteed to be non-zero
151  // compute atan2 for quadrant 1 (0 to 90 deg) and quadrant 4 (-90 to 0 deg)
152  if (x > 0.0F) return (fatan_deg(y / x));
153 
154  // compute atan2 for quadrant 2 (90 to 180 deg)
155  if ((x < 0.0F) && (y > 0.0F)) return (180.0F + fatan_deg(y / x));
156 
157  // compute atan2 for quadrant 3 (-180 to -90 deg)
158  return (-180.0F + fatan_deg(y / x));
159 }
160 
161 // approximation to inverse tan function (deg) for x in range
162 // -tan(15 deg) to tan(15 deg) giving an output -15 deg <= angle <= 15 deg
163 
164 // using modified Pade[3/2] approximation
165 float fatan_15deg(float x)
166 {
167  float x2; // x^2
168 #define PADE_A 96.644395816F // theoretical Pade[3/2] value is 5/3*180/PI=95.49296
169 #define PADE_B 25.086941612F // theoretical Pade[3/2] value is 4/9*180/PI=25.46479
170 #define PADE_C 1.6867633134F // theoretical Pade[3/2] value is 5/3=1.66667
171  // compute the approximation to the inverse tangent
172  // the function is anti-symmetric as required for positive and negative arguments
173  x2 = x * x;
174  return (x * (PADE_A + x2 * PADE_B) / (PADE_C + x2));
175 }
float fatan_deg(float x)
float fasin_deg(float x)
#define TAN30DEG
float fatan_15deg(float x)
Math approximations file.
#define PADE_C
#define TAN15DEG
#define PADE_A
#define PADE_B
float facos_deg(float x)
float fatan2_deg(float y, float x)