1 /* ----------------------------------------------------------------------
2  * Project:      CMSIS DSP Library
3  * Title:        arm_atan2_q15.c
4  * Description:  q15 Arc tangent of y/x
5  *
6  * $Date:        22 April 2022
7  * $Revision:    V1.10.0
8  *
9  * Target Processor: Cortex-M and Cortex-A cores
10  * -------------------------------------------------------------------- */
11 /*
12  * Copyright (C) 2010-2022 ARM Limited or its affiliates. All rights reserved.
13  *
14  * SPDX-License-Identifier: Apache-2.0
15  *
16  * Licensed under the Apache License, Version 2.0 (the License); you may
17  * not use this file except in compliance with the License.
18  * You may obtain a copy of the License at
19  *
20  * www.apache.org/licenses/LICENSE-2.0
21  *
22  * Unless required by applicable law or agreed to in writing, software
23  * distributed under the License is distributed on an AS IS BASIS, WITHOUT
24  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25  * See the License for the specific language governing permissions and
26  * limitations under the License.
27  */
28 
29 #include "dsp/fast_math_functions.h"
30 #include "dsp/utils.h"
31 
32 /*
33 
34 atan for argument between in [0, 1.0]
35 
36 */
37 
38 
39 /* Q2.13 */
40 #define ATANHALFQ13 0xed6
41 #define PIHALFQ13 0x3244
42 #define PIQ13 0x6488
43 
44 #define ATAN2_NB_COEFS_Q15 10
45 
46 static const q15_t atan2_coefs_q15[ATAN2_NB_COEFS_Q15]={
47      0, // 0x0000
48  32767, // 0x7fff
49     -1, // 0xffff
50 -10905, // 0xd567
51   -144, // 0xff70
52   7085, // 0x1bad
53   -680, // 0xfd58
54  -5719, // 0xe9a9
55   4393, // 0x1129
56  -1061  // 0xfbdb
57 };
58 
arm_atan_limited_q15(q15_t x)59 __STATIC_FORCEINLINE q15_t arm_atan_limited_q15(q15_t x)
60 {
61     q31_t res=(q31_t)atan2_coefs_q15[ATAN2_NB_COEFS_Q15-1];
62     int i=1;
63     for(i=1;i<ATAN2_NB_COEFS_Q15;i++)
64     {
65         res = ((q31_t) x * res) >> 15U;
66         res = res + ((q31_t) atan2_coefs_q15[ATAN2_NB_COEFS_Q15-1-i]) ;
67     }
68 
69     res = __SSAT(res>>2,16);
70 
71 
72     return(res);
73 }
74 
75 
arm_atan_q15(q15_t y,q15_t x)76 __STATIC_FORCEINLINE q15_t arm_atan_q15(q15_t y,q15_t x)
77 {
78    int sign=0;
79    q15_t res=0;
80 
81    if (y<0)
82    {
83      /* Negate y */
84 #if defined (ARM_MATH_DSP)
85      y = __QSUB16(0, y);
86 #else
87      y = (y == (q15_t) 0x8000) ? (q15_t) 0x7fff : -y;
88 #endif
89 
90      sign=1-sign;
91    }
92 
93    if (x < 0)
94    {
95       sign=1 - sign;
96 
97       /* Negate x */
98 #if defined (ARM_MATH_DSP)
99      x = __QSUB16(0, x);
100 #else
101      x = (x == (q15_t) 0x8000) ? (q15_t) 0x7fff : -x;
102 #endif
103    }
104 
105    if (y > x)
106    {
107     q15_t ratio;
108     int16_t shift;
109 
110     arm_divide_q15(x,y,&ratio,&shift);
111 
112     /* Shift ratio by shift */
113     if (shift >=0)
114     {
115        ratio = __SSAT(((q31_t) ratio << shift), 16);
116     }
117     else
118     {
119        ratio = (ratio >> -shift);
120     }
121 
122     res = PIHALFQ13 - arm_atan_limited_q15(ratio);
123 
124    }
125    else
126    {
127     q15_t ratio;
128     int16_t shift;
129 
130     arm_divide_q15(y,x,&ratio,&shift);
131 
132     /* Shift ratio by shift */
133     if (shift >=0)
134     {
135        ratio = __SSAT(((q31_t) ratio << shift), 16);
136     }
137     else
138     {
139        ratio = (ratio >> -shift);
140     }
141 
142 
143     res = arm_atan_limited_q15(ratio);
144 
145    }
146 
147 
148    if (sign)
149    {
150      /* Negate res */
151 #if defined (ARM_MATH_DSP)
152      res = __QSUB16(0, res);
153 #else
154      res = (res == (q15_t) 0x8000) ? (q15_t) 0x7fff : -res;
155 #endif
156    }
157 
158    return(res);
159 }
160 
161 
162 /**
163   @ingroup groupFastMath
164  */
165 
166 
167 /**
168   @addtogroup atan2
169   @{
170  */
171 
172 /**
173   @brief       Arc Tangent of y/x using sign of y and x to get right quadrant
174   @param[in]   y  y coordinate
175   @param[in]   x  x coordinate
176   @param[out]  result  Result in Q2.13
177   @return  error status.
178 
179   @par         Compute the Arc tangent of y/x:
180                    The sign of y and x are used to determine the right quadrant
181                    and compute the right angle. Returned value is between -Pi and Pi.
182 */
183 
184 
arm_atan2_q15(q15_t y,q15_t x,q15_t * result)185 ARM_DSP_ATTRIBUTE arm_status arm_atan2_q15(q15_t y,q15_t x,q15_t *result)
186 {
187     if (x > 0)
188     {
189         *result=arm_atan_q15(y,x);
190         return(ARM_MATH_SUCCESS);
191     }
192     if (x < 0)
193     {
194         if (y > 0)
195         {
196            *result=arm_atan_q15(y,x) + PIQ13;
197         }
198         else if (y < 0)
199         {
200            *result=arm_atan_q15(y,x) - PIQ13;
201         }
202         else
203         {
204             *result= PIQ13;
205         }
206         return(ARM_MATH_SUCCESS);
207     }
208     if (x == 0)
209     {
210         if (y > 0)
211         {
212             *result=PIHALFQ13;
213             return(ARM_MATH_SUCCESS);
214         }
215         if (y < 0)
216         {
217             *result=-PIHALFQ13;
218             return(ARM_MATH_SUCCESS);
219         }
220     }
221 
222 
223     return(ARM_MATH_NANINF);
224 
225 }
226 
227 /**
228   @} end of atan2 group
229  */
230