Ticket #2109: atan2cordic.patch

File atan2cordic.patch, 2.8 KB (added by fsincos, 8 years ago)
  • source/maths/Fixed.cpp

    diff --git a/source/maths/Fixed.cpp b/source/maths/Fixed.cpp
    index e9e3c8c..d2ecf33 100644
    a b CStr8 CFixed_15_16::ToString() const  
    143143    return r.str();
    144144}
    145145
    146 // Based on http://www.dspguru.com/dsp/tricks/fixed-point-atan2-with-self-normalization
    147146CFixed_15_16 atan2_approx(CFixed_15_16 y, CFixed_15_16 x)
    148147{
    149     CFixed_15_16 zero;
     148    // Error <= arctan(1/16)/2 ~ 1.788 degrees.
    150149
    151     // Special case to avoid division-by-zero
    152     if (x.IsZero() && y.IsZero())
    153         return zero;
     150    // Binary search using the following angles:
     151    // 45, 26.565, 14.036, 7.125, 3.576 degrees (= arctan(1/2^n))
     152    // Idea: [1, 2^(-n); -2^(-n), 1] are multiples of the rotation matrices for these angles.
     153    i32 tan_angle_table_rad[5] = {51472, 30386, 16055, 8150, 4091};
    154154
    155     CFixed_15_16 c1;
    156     c1.SetInternalValue(51472); // pi/4 << 16
     155    i32 angleint = 2045; // = 1/2*arctan(1/16) << 16
     156    i32 xint = x.GetInternalValue(), yint = y.GetInternalValue(), tmpint;
    157157
    158     CFixed_15_16 c2;
    159     c2.SetInternalValue(154415); // 3*pi/4 << 16
     158    // Handle the case (0,0).
     159    if (xint == 0 && yint == 0)
     160        return CFixed_15_16::FromInt(0);
    160161
    161     CFixed_15_16 abs_y = y.Absolute();
     162    // Reduce the problem to the case x,y >= 0, i.e. 0 <= angle <= pi/2
     163    if (yint >= 0) // (0, pi)
     164    {
     165        if (xint < 0) // (pi/2, pi)
     166        {
     167            // (x, y) -> (y, -x)
     168            tmpint = xint;
     169            xint = yint;
     170            yint = -tmpint;
     171            angleint = 102944+2045; // pi/2 << 16
     172        }
     173    }
     174    else // (-pi, 0)
     175    {
     176        if (xint < 0) // (-pi, -pi/2)
     177        {
     178            // (x, y) -> (-x, -y)
     179            xint *= -1;
     180            yint *= -1;
     181            angleint = -205887+2045; // -pi << 16
     182        }
     183        else // (-pi/2, 0)
     184        {
     185            // (x, y) -> (-y, x)
     186            tmpint = xint;
     187            xint = -yint;
     188            yint = tmpint;
     189            angleint = -102944+2045; // -pi/2 << 16
     190        }
     191    }
    162192
    163     CFixed_15_16 angle;
    164     if (x >= zero)
     193    // Scale up / down to prevent massive rounding errors / overflows.
     194    if (xint < 64 && yint < 64)
     195    {
     196        xint <<= 6;
     197        yint <<= 6;
     198    }
     199    else if (xint >= 8192 || yint >= 8192)
    165200    {
    166         CFixed_15_16 r = (x - abs_y) / (x + abs_y);
    167         angle = c1 - c1.Multiply(r);
     201        xint >>= 4;
     202        yint >>= 4;
    168203    }
    169     else
     204    for (u8 loop_var = 0; loop_var < 5; ++loop_var)
    170205    {
    171         CFixed_15_16 r = (x + abs_y) / (abs_y - x);
    172         angle = c2 - c1.Multiply(r);
     206        tmpint = xint >> loop_var;
     207        // If remaining angle > arctan(1/2^n) "rotate" counterclockwise.
     208        if (yint >= tmpint)
     209        {
     210            // (x,y) -> (x,y) + 1/2^n * (-y,x)
     211            xint += yint >> loop_var;
     212            yint -= tmpint;
     213            angleint += tan_angle_table_rad[loop_var];
     214        }
    173215    }
     216    // Remaining angle is in [0,arctan(1/16)], arctan(1/16)/2 is the best possible approximation.
    174217
    175     if (y < zero)
    176         return -angle;
    177     else
    178         return angle;
     218    // If needed, get the value into the desired interval of length 2*pi.
     219
     220    CFixed_15_16 angle;
     221    angle.SetInternalValue(angleint);
     222    return angle;
    179223}
    180224
    181225template<>