Cordic Algorithm for ATAN -- what to do with cases where x and/or y == 0?
Zoot
Posts: 2,227
Hello all -- I've got a balance 'bot I'm working on and I'm using some ATAN code that Bean wrote for SX/B.
I'm not posting this in the SX forum, because my code works perfectly well and I don't have a technical question per se.
Rather, I am unsure about one operation in the Cordic routine -- where the x and y coordinates are normalized before running the cordic loop.
In Bean's code, he normalizes x and y to be 4096 <= val <= 8192.
But if that's true, then if x == 0 or y == 0, then this version of the Cordic algorithm goes into an infinite loop when trying to normalize the value to be >= 4096.
To solve the hang, I tried two versions -- one where I initialized x or y to 1 if they were 0, the other where I just skipped the minimum normalization altogether for zero value cases.
In practice, both gave me similar results when calculating rotation from a 3-axis accelerometer, but then I realized I would be better served finding out what should be done with such edge cases (or if this code version of Cordic is missing something?).
The full routine is below, but the relevant snippet is here:
Full routine:
I'm not posting this in the SX forum, because my code works perfectly well and I don't have a technical question per se.
Rather, I am unsure about one operation in the Cordic routine -- where the x and y coordinates are normalized before running the cordic loop.
In Bean's code, he normalizes x and y to be 4096 <= val <= 8192.
But if that's true, then if x == 0 or y == 0, then this version of the Cordic algorithm goes into an infinite loop when trying to normalize the value to be >= 4096.
To solve the hang, I tried two versions -- one where I initialized x or y to 1 if they were 0, the other where I just skipped the minimum normalization altogether for zero value cases.
In practice, both gave me similar results when calculating rotation from a 3-axis accelerometer, but then I realized I would be better served finding out what should be done with such edge cases (or if this code version of Cordic is missing something?).
The full routine is below, but the relevant snippet is here:
' obviously, the loop below will hang if either xcoord == 0 or ycoord == 0
DO
IF yCoord > 4096 THEN EXIT
IF xCoord > 4096 THEN EXIT
yCoord = yCoord << 1
xCoord = xCoord << 1
LOOP
Full routine:
' -------------------------------------------------------------------------
' Subroutine Code
' -------------------------------------------------------------------------
ATAN:
' Get parameters
xCoord = __WPARAM12
yCoord = __WPARAM34
' Initialize angle
angle = 0
' Get sign of yCoord
yNegative = yCoordSign
' If yCoord was negative then rotate coordinate
IF yNegative = 1 THEN
yCoord = -yCoord
xCoord = -xCoord
ENDIF
' Get sign of xCoord
xNegative = xCoordSign
' If xCoord was negative then rotate coordinate
IF xNegative = 1 THEN
wTemp1 = yCoord
yCoord = -xCoord
xCoord = wTemp1
ENDIF
' Scale xCoord and yCoord
DO
IF yCoord < 8192 THEN
IF xCoord < 8192 THEN EXIT
ENDIF
yCoord = yCoord >> 1
xCoord = xCoord >> 1
LOOP
' obviously, the loop below will hang if either xcoord == 0 or ycoord == 0
DO
IF yCoord > 4096 THEN EXIT
IF xCoord > 4096 THEN EXIT
yCoord = yCoord << 1
xCoord = xCoord << 1
LOOP
' Main CORDIC loop
FOR cnt=0 to 14
' Get Absolute value of yCoord
wTemp1 = yCoord
IF yCoordSign = 1 THEN
wTemp1 = -wTemp1
ENDIF
' Get Absolute value of xCoord
wTemp2 = xCoord
IF xCoordSign = 1 THEN
wTemp2 = -wTemp2
ENDIF
' Shift temp1 and temp2 right (cnt) times
wTemp1 = wTemp1 >> cnt
wTemp2 = wTemp2 >> cnt
' Remember sign of xCoord before it is adjusted
xSign = xCoordSign
' Adjust xCoord
xCoord = xCoord + wTemp1
' Get ATAN from table
cnt = cnt << 1
READ ATAN_Table + cnt, wTemp1
cnt = cnt >> 1
' Adjust angle
IF yCoordSign = 1 THEN
angle = angle - wTemp1
ELSE
angle = angle + wTemp1
ENDIF
' Adjust yCoord; If signs are equal then subtract, if signs are different then add
IF yCoordSign = xSign THEN
yCoord = yCoord - wTemp2
ELSE
yCoord = yCoord + wTemp2
ENDIF
NEXT
' CORDIC loop done
' Adjust angle
IF yNegative = 1 THEN
angle = angle + 32768
ENDIF
IF xNegative = 1 THEN
angle = angle + 16384
ENDIF
RETURN angle
' -------------------------------------------------------------------------
' Data Tables
' -------------------------------------------------------------------------
ATAN_Table: ' 15 Word entries; Atan(1/(2^position)) in brads * 256
WDATA 8192, 4836, 2555, 1297, 651, 326, 163, 81, 41, 20, 10, 5, 3, 1, 1

Comments
y=0, x>0 --> theta=0°
y=0, x<0 --> theta = -180° (but in brads)
y>0, x=0 --> theta = +90°
y<0, x=0 --> theta = -90°
y=0, x=0 --> theta undefined (no vector for a point at the origen)
Dispose of those cases at the top of the algorithm, before attempting to scale.