linux/lib/math/cordic.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2011 Broadcom Corporation
   3 *
   4 * Permission to use, copy, modify, and/or distribute this software for any
   5 * purpose with or without fee is hereby granted, provided that the above
   6 * copyright notice and this permission notice appear in all copies.
   7 *
   8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15 */
  16#include <linux/module.h>
  17#include <linux/cordic.h>
  18
  19static const s32 arctan_table[] = {
  20        2949120,
  21        1740967,
  22        919879,
  23        466945,
  24        234379,
  25        117304,
  26        58666,
  27        29335,
  28        14668,
  29        7334,
  30        3667,
  31        1833,
  32        917,
  33        458,
  34        229,
  35        115,
  36        57,
  37        29
  38};
  39
  40/*
  41 * cordic_calc_iq() - calculates the i/q coordinate for given angle
  42 *
  43 * theta: angle in degrees for which i/q coordinate is to be calculated
  44 * coord: function output parameter holding the i/q coordinate
  45 */
  46struct cordic_iq cordic_calc_iq(s32 theta)
  47{
  48        struct cordic_iq coord;
  49        s32 angle, valtmp;
  50        unsigned iter;
  51        int signx = 1;
  52        int signtheta;
  53
  54        coord.i = CORDIC_ANGLE_GEN;
  55        coord.q = 0;
  56        angle = 0;
  57
  58        theta = CORDIC_FIXED(theta);
  59        signtheta = (theta < 0) ? -1 : 1;
  60        theta = ((theta + CORDIC_FIXED(180) * signtheta) % CORDIC_FIXED(360)) -
  61                CORDIC_FIXED(180) * signtheta;
  62
  63        if (CORDIC_FLOAT(theta) > 90) {
  64                theta -= CORDIC_FIXED(180);
  65                signx = -1;
  66        } else if (CORDIC_FLOAT(theta) < -90) {
  67                theta += CORDIC_FIXED(180);
  68                signx = -1;
  69        }
  70
  71        for (iter = 0; iter < CORDIC_NUM_ITER; iter++) {
  72                if (theta > angle) {
  73                        valtmp = coord.i - (coord.q >> iter);
  74                        coord.q += (coord.i >> iter);
  75                        angle += arctan_table[iter];
  76                } else {
  77                        valtmp = coord.i + (coord.q >> iter);
  78                        coord.q -= (coord.i >> iter);
  79                        angle -= arctan_table[iter];
  80                }
  81                coord.i = valtmp;
  82        }
  83
  84        coord.i *= signx;
  85        coord.q *= signx;
  86        return coord;
  87}
  88EXPORT_SYMBOL(cordic_calc_iq);
  89
  90MODULE_DESCRIPTION("CORDIC algorithm");
  91MODULE_AUTHOR("Broadcom Corporation");
  92MODULE_LICENSE("Dual BSD/GPL");
  93