1 /* ----------------------------------------------------------------------
2  * Project:      CMSIS DSP Library
3  * Title:        arm_atan2_q31.c
4  * Description:  q31 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.29 */
40 #define ATANHALF_Q29 0xed63383
41 #define PIHALF_Q29 0x3243f6a9
42 #define PIQ29 0x6487ed51
43 
44 #define ATAN2_NB_COEFS_Q31 13
45 
46 static const q31_t atan2_coefs_q31[ATAN2_NB_COEFS_Q31]={0x00000000
47 ,0x7ffffffe
48 ,0x000001b6
49 ,0xd555158e
50 ,0x00036463
51 ,0x1985f617
52 ,0x001992ae
53 ,0xeed53a7f
54 ,0xf8f15245
55 ,0x2215a3a4
56 ,0xe0fab004
57 ,0x0cdd4825
58 ,0xfddbc054
59 };
60 
61 
arm_atan_limited_q31(q31_t x)62 __STATIC_FORCEINLINE q31_t arm_atan_limited_q31(q31_t x)
63 {
64     q63_t res=(q63_t)atan2_coefs_q31[ATAN2_NB_COEFS_Q31-1];
65     int i=1;
66     for(i=1;i<ATAN2_NB_COEFS_Q31;i++)
67     {
68         res = ((q63_t) x * res) >> 31U;
69         res = res + ((q63_t) atan2_coefs_q31[ATAN2_NB_COEFS_Q31-1-i]) ;
70     }
71 
72     return(clip_q63_to_q31(res>>2));
73 }
74 
75 
arm_atan_q31(q31_t y,q31_t x)76 __STATIC_FORCEINLINE q31_t arm_atan_q31(q31_t y,q31_t x)
77 {
78    int sign=0;
79    q31_t res=0;
80 
81    if (y<0)
82    {
83     /* Negate y */
84 #if defined (ARM_MATH_DSP)
85     y = __QSUB(0, y);
86 #else
87     y = (y == INT32_MIN) ? INT32_MAX : -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 = __QSUB(0, x);
100 #else
101     x = (x == INT32_MIN) ? INT32_MAX : -x;
102 #endif
103    }
104 
105    if (y > x)
106    {
107     q31_t ratio;
108     int16_t shift;
109 
110     arm_divide_q31(x,y,&ratio,&shift);
111 
112     /* Shift ratio by shift */
113     if (shift >= 0)
114     {
115          ratio = clip_q63_to_q31((q63_t) ratio << shift);
116     }
117     else
118     {
119          ratio = (ratio >> -shift);
120     }
121 
122     res = PIHALF_Q29 - arm_atan_limited_q31(ratio);
123 
124    }
125    else
126    {
127     q31_t ratio;
128     int16_t shift;
129 
130     arm_divide_q31(y,x,&ratio,&shift);
131 
132     /* Shift ratio by shift */
133     if (shift >= 0)
134     {
135          ratio = clip_q63_to_q31((q63_t) ratio << shift);
136     }
137     else
138     {
139          ratio = (ratio >> -shift);
140     }
141 
142 
143     res = arm_atan_limited_q31(ratio);
144 
145    }
146 
147 
148    if (sign)
149    {
150      /* Negate res */
151 #if defined (ARM_MATH_DSP)
152      res = __QSUB(0, res);
153 #else
154      res = (res == INT32_MIN) ? INT32_MAX : -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.29
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_q31(q31_t y,q31_t x,q31_t * result)185 ARM_DSP_ATTRIBUTE arm_status arm_atan2_q31(q31_t y,q31_t x,q31_t *result)
186 {
187     if (x > 0)
188     {
189         *result=arm_atan_q31(y,x);
190         return(ARM_MATH_SUCCESS);
191     }
192     if (x < 0)
193     {
194         if (y > 0)
195         {
196            *result=arm_atan_q31(y,x) + PIQ29;
197         }
198         else if (y < 0)
199         {
200            *result=arm_atan_q31(y,x) - PIQ29;
201         }
202         else
203         {
204            *result= PIQ29;
205         }
206         return(ARM_MATH_SUCCESS);
207     }
208     if (x == 0)
209     {
210         if (y > 0)
211         {
212             *result=PIHALF_Q29;
213             return(ARM_MATH_SUCCESS);
214         }
215         if (y < 0)
216         {
217             *result=-PIHALF_Q29;
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