root/modules/cordic_math.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cordic
  2. cordic_abs
  3. cordic_sign
  4. muldivScaled
  5. mulScaled
  6. divScaled
  7. cathetus
  8. sincosCordic
  9. atanhypCordic
  10. sinCordic
  11. cosCordic
  12. tanCordic
  13. recCordic
  14. asinCordic
  15. acosCordic
  16. atanCordic
  17. polCordic
  18. sind
  19. cosd
  20. tand
  21. recd
  22. asind
  23. acosd
  24. atand
  25. pold
  26. sinr
  27. cosr
  28. tanr
  29. recr
  30. asinr
  31. acosr
  32. atanr
  33. polr
  34. fint
  35. fceil
  36. ffloor
  37. fround
  38. floatToFixed
  39. intToFixed
  40. fixedToInt

   1 /*
   2 CORDIC LIBRARY
   3 integer based trigonometric mathematics
   4 all values scaled by 100000 (CORDIC_SCALE)
   5 
   6 based on http://www.andreadrian.de/c-workshop/index.html
   7 
   8 (c)2012/2013 rudi from CHDK[-DE] forum
   9 License GPL 2.0
  10 */
  11 
  12 #include "stdlib.h"
  13 #include "luaconf.h"
  14 #include "math.h"
  15 #include "cordic_math.h"
  16 
  17 fixed atan_tab[][M] = {
  18     {0x1921f, 0xed63, 0x7d6d, 0x3fab, 0x1ff5, 0xffe, 0x7ff, 0x3ff, 0x1ff},
  19     {0x5a0000, 0x35214e, 0x1c128e, 0xe4002, 0x72715, 0x3946f, 0x1ca54, 0xe52d, 0x7297}
  20 };
  21 fixed INV_GAIN_CIRCLE[] = {0x136e9, 0x136e8};   // {0.60725, 0.60724}
  22 fixed FULL_CIRCLE[]     = {0xc90fd, 0x2d00000}; // {6.28318, 360.00000}
  23 fixed HALF_CIRCLE[]     = {0x6487e, 0x1680000}; // {3.14159, 180.00000}
  24 fixed QUART_CIRCLE[]    = {0x3243f, 0xb40000};  // {1.57079, 90.00000}
  25 fixed ATAN_LIMIT        = 0x36f602be;           // 7035.00536
  26 fixed FIXED_MAX         = 16383.99999;
  27 
  28 // CORDIC main routine
  29 static void cordic(tangle t, fcordic f, fixed *x, fixed *y, fixed *z) {
  30     long *patan_tab = atan_tab[t];
  31     long xstep, ystep, zstep = 1;
  32     int i;
  33     for (i = 0; i < N; ++i) {
  34         xstep = *x >> i;
  35         ystep = *y >> i;
  36         if (i < M) {
  37             zstep = *patan_tab;
  38             ++patan_tab;
  39         } else zstep >>= 1;
  40         int f1 = (f) ? *y >= 0 : *z < 0;
  41         *x = (f1) ? *x + ystep : *x - ystep;
  42         *y = (f1) ? *y - xstep : *y + xstep;
  43         *z = (f1) ? *z + zstep : *z - zstep;
  44     }
  45 }
  46 
  47 // abs(INT_MIN) doesn't work
  48 static int cordic_abs(int a) {
  49     if (a < -INT_MAX) a = -INT_MAX;
  50     return abs(a);
  51 }
  52 
  53 static int cordic_sign(int a) {
  54     return (a < 0)? -1 : 1;
  55 }
  56 
  57 // a x b / c
  58 LUALIB_API fixed muldivScaled(fixed a, fixed b, fixed c) {
  59     double res;
  60     if (c != 0) {
  61         int sign = cordic_sign(a) * cordic_sign(b) / cordic_sign(c);
  62         res = FLOAT(cordic_abs(a)) * FLOAT(cordic_abs(b)) / FLOAT(cordic_abs(c));
  63         if (res > INT_MAX) {
  64             // error overflow
  65             res = INT_MAX;
  66         } else { res = sign * res; }
  67     } else {
  68         // error div 0
  69         res = 0;
  70     }
  71     return FIXED(res);
  72 }
  73 
  74 static fixed mulScaled(fixed a, fixed b) {
  75     return muldivScaled(a, b, CORDIC_SCALE);
  76 }
  77 
  78 static fixed divScaled(fixed a, fixed b) {
  79     return muldivScaled(CORDIC_SCALE, a, b);
  80 }
  81 
  82 static fixed cathetus(fixed x) {
  83     return FIXED(sqrt((1 + FLOAT(x)) * (1 - FLOAT(x))));
  84 }
  85 
  86 // base CIRCULAR mode, ROTATE
  87 static void sincosCordic(tangle t, fixed phi, fixed *sinphi, fixed *cosphi) {
  88     // convert to quadrant 1
  89     phi = (phi % FULL_CIRCLE[t] + FULL_CIRCLE[t]) % FULL_CIRCLE[t];
  90     int q = phi / QUART_CIRCLE[t] + 1;
  91     switch(q) {
  92         case 2: phi = HALF_CIRCLE[t] - phi; break;
  93         case 3: phi = phi - HALF_CIRCLE[t]; break;
  94         case 4: phi = FULL_CIRCLE[t] - phi; break;
  95     }
  96     fixed x = INV_GAIN_CIRCLE[t], y = 0, z = phi;
  97     cordic(t, ROTATE, &x, &y, &z);
  98     // convert to original quadrant
  99     if ((q == 2) || (q == 3)) { x = -x; }
 100     if ((q == 3) || (q == 4)) { y = -y; }
 101     *sinphi = y;
 102     *cosphi = x;
 103 }
 104 
 105 // base CIRCULAR mode, VECTOR
 106 static void atanhypCordic(tangle t, fixed px, fixed py, fixed *phi, fixed *hyp) {
 107     // convert to quadrant 1
 108     int fy = (py >= 0);
 109     int q = 1;
 110     if (px < 0) {
 111         if (fy)
 112             q = 2;
 113         else
 114             q = 3;
 115     } else if (!fy) {
 116         q = 4;
 117     }
 118     px = cordic_abs(px);
 119     py = cordic_abs(py);
 120 
 121     int f = 0;
 122     while (px > ATAN_LIMIT || py > ATAN_LIMIT) {
 123         px /= 2;
 124         py /= 2;
 125         f = 1;
 126     }
 127     if (px == 0 && py == 0) {
 128         // error input vales
 129         *phi = 0;
 130         *hyp = 0;
 131     } else {
 132         fixed x = px, y = py, z = 0;
 133         cordic(t, VECTOR, &x, &y, &z);
 134         // convert to original quadrant
 135         switch(q) {
 136             case 2: z = HALF_CIRCLE[t] - z; break;
 137             case 3: z = z - HALF_CIRCLE[t]; break;
 138             case 4: z = -z; break;
 139         }
 140         *phi = z;
 141         *hyp = (f)? 0 : x;
 142     }
 143 }
 144 
 145 // functions in CIRCULAR mode, ROTATE
 146 static fixed sinCordic(tangle t, fixed phi) {
 147     fixed _sin, _cos;
 148     sincosCordic(t, phi, &_sin, &_cos);
 149     return _sin;
 150 }
 151 
 152 static fixed cosCordic(tangle t, fixed phi) {
 153     fixed _sin, _cos;
 154     sincosCordic(t, phi, &_sin, &_cos);
 155     return _cos;
 156 }
 157 
 158 static fixed tanCordic(tangle t, fixed phi) {
 159     fixed _sin, _cos;
 160     sincosCordic(t, phi, &_sin, &_cos);
 161     return divScaled(_sin, _cos);
 162 }
 163 
 164 static void recCordic(tangle t, fixed r, fixed theta, fixed *px, fixed *py) {
 165     fixed _sin, _cos;
 166     sincosCordic(t, theta, &_sin, &_cos);
 167     *px = mulScaled(r, _cos);
 168     *py = mulScaled(r, _sin);
 169 }
 170 
 171 // functions in CIRCULAR mode, VECTOR
 172 static fixed asinCordic(tangle t, fixed x) {
 173     fixed phi, hyp;
 174     fixed _cos = cathetus(x);
 175     atanhypCordic(t, _cos, x, &phi, &hyp);
 176     return phi;
 177 }
 178 
 179 static fixed acosCordic(tangle t, fixed x) {
 180     fixed phi, hyp;
 181     fixed _sin = cathetus(x);
 182     atanhypCordic(t, x, _sin, &phi, &hyp);
 183     return phi;
 184 }
 185 
 186 static fixed atanCordic(tangle t, fixed x) {
 187     fixed phi, hyp;
 188     atanhypCordic(t, CORDIC_SCALE, x, &phi, &hyp);
 189     return phi;
 190 }
 191 
 192 static void polCordic(tangle t, fixed px, fixed py, fixed *r, fixed *theta) {
 193     fixed phi, hyp;
 194     atanhypCordic(t, px, py, &phi, &hyp);
 195     *theta = phi;
 196     *r = mulScaled(hyp, INV_GAIN_CIRCLE[t]);
 197 }
 198 
 199 // extern functions
 200 // DEG
 201 LUALIB_API fixed sind(fixed phi) {
 202     return sinCordic(DEG, phi);
 203 }
 204 
 205 LUALIB_API fixed cosd(fixed phi) {
 206     return cosCordic(DEG, phi);
 207 }
 208 
 209 LUALIB_API fixed tand(fixed phi) {
 210     return tanCordic(DEG, phi);
 211 }
 212 
 213 LUALIB_API void recd(fixed r, fixed theta, fixed *px, fixed *py) {
 214     recCordic(DEG, r, theta, px, py);
 215 }
 216 
 217 LUALIB_API fixed asind(fixed x) {
 218     return asinCordic(DEG, x);
 219 }
 220 
 221 LUALIB_API fixed acosd(fixed x) {
 222     return acosCordic(DEG, x);
 223 }
 224 
 225 LUALIB_API fixed atand(fixed x) {
 226     return atanCordic(DEG, x);
 227 }
 228 
 229 LUALIB_API void pold(fixed px, fixed py, fixed *r, fixed *theta) {
 230     polCordic(DEG, px, py, r, theta);
 231 }
 232 
 233 // RAD
 234 LUALIB_API fixed sinr(fixed phi) {
 235     return sinCordic(RAD, phi);
 236 }
 237 
 238 LUALIB_API fixed cosr(fixed phi) {
 239     return cosCordic(RAD, phi);
 240 }
 241 
 242 LUALIB_API fixed tanr(fixed phi) {
 243     return tanCordic(RAD, phi);
 244 }
 245 
 246 LUALIB_API void recr(fixed r, fixed theta, fixed *px, fixed *py) {
 247     recCordic(RAD, r, theta, px, py);
 248 }
 249 
 250 LUALIB_API fixed asinr(fixed x) {
 251     return asinCordic(RAD, x);
 252 }
 253 
 254 LUALIB_API fixed acosr(fixed x) {
 255     return acosCordic(RAD, x);
 256 }
 257 
 258 LUALIB_API fixed atanr(fixed x) {
 259     return atanCordic(RAD, x);
 260 }
 261 
 262 LUALIB_API void polr(fixed px, fixed py, fixed *r, fixed *theta) {
 263     polCordic(RAD, px, py, r, theta);
 264 }
 265 
 266 //additional math functions
 267 LUALIB_API fixed fint(fixed a) {
 268     return cordic_sign(a) * (cordic_abs(a) & CORDIC_INTEGER);
 269 }
 270 
 271 LUALIB_API fixed fceil(fixed a) {
 272     fixed int_a = fint(a);
 273     return (a < 0 || a == int_a)? int_a: int_a + CORDIC_SCALE;
 274 }
 275 
 276 LUALIB_API fixed ffloor(fixed a) {
 277     fixed int_a = fint(a);
 278     return (a > 0 || a == int_a)? int_a: int_a - CORDIC_SCALE;
 279 }
 280 
 281 LUALIB_API fixed fround(fixed a) {
 282     return ffloor(a + CORDIC_SCALE / 2);
 283 }
 284 
 285 // convert functions
 286 LUALIB_API fixed floatToFixed(double a) {
 287     int sign = 1;
 288     if (a < 0) {
 289         sign = -1;
 290         a = -a;
 291     }
 292     if (a > FIXED_MAX) {
 293         // error fixed overflow
 294         a = FIXED_MAX;
 295     }
 296     return a * CORDIC_SCALE * sign;
 297 }
 298 
 299 LUALIB_API fixed intToFixed(int4b a, int round) {
 300     double res = cordic_abs(a);
 301     if (round) res = res + 0.5;
 302     res = res * CORDIC_SCALE / INT_SCALE;
 303     if (res > INT_MAX) {
 304         // error fixed overflow
 305         res = INT_MAX;
 306     }
 307     return cordic_sign(a) * res;
 308 }
 309 
 310 LUALIB_API int4b fixedToInt(fixed a, int round) {
 311     double res = cordic_abs(a);
 312     if (res > INT_MAX) {
 313         // error int4b overflow
 314         res = INT_MAX;
 315     }
 316     res = res * INT_SCALE / CORDIC_SCALE;
 317     if (round) res = res + 0.5;
 318     return cordic_sign(a) * res;
 319 }

/* [<][>][^][v][top][bottom][index][help] */