1 /* SPDX-License-Identifier: BSD-3-Clause
2 *
3 * Copyright(c) 2016 Intel Corporation. All rights reserved.
4 *
5 * Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
6 * Liam Girdwood <liam.r.girdwood@linux.intel.com>
7 * Keyon Jie <yang.jie@linux.intel.com>
8 * Shriram Shastry <malladi.sastry@linux.intel.com>
9 */
10
11 #ifndef __SOF_MATH_TRIG_H__
12 #define __SOF_MATH_TRIG_H__
13
14 #include <stdint.h>
15
16 #ifndef UNIT_CORDIC_TEST
17 #define CONFIG_CORDIC_TRIGONOMETRY_FIXED
18 #endif
19
20 #define PI_DIV2_Q4_28 421657428
21 #define PI_DIV2_Q3_29 843314856
22 #define PI_Q4_28 843314857
23 #define PI_MUL2_Q4_28 1686629713
24 #define CORDIC_31B_TABLE_SIZE 31
25 #define CORDIC_15B_TABLE_SIZE 15
26 #define CORDIC_30B_ITABLE_SIZE 30
27 #define CORDIC_16B_ITABLE_SIZE 16
28
29 typedef enum {
30 EN_32B_CORDIC_SINE,
31 EN_32B_CORDIC_COSINE,
32 EN_32B_CORDIC_CEXP,
33 EN_16B_CORDIC_SINE,
34 EN_16B_CORDIC_COSINE,
35 EN_16B_CORDIC_CEXP,
36 } cordic_cfg;
37
38 struct cordic_cmpx {
39 int32_t re;
40 int32_t im;
41 };
42
43 void cordic_approx(int32_t th_rad_fxp, int32_t a_idx, int32_t *sign, int32_t *b_yn, int32_t *xn,
44 int32_t *th_cdc_fxp);
45 int32_t is_scalar_cordic_acos(int32_t realvalue, int16_t numiters);
46 int32_t is_scalar_cordic_asin(int32_t realvalue, int16_t numiters);
47 void cmpx_cexp(int32_t sign, int32_t b_yn, int32_t xn, cordic_cfg type, struct cordic_cmpx *cexp);
48 /* Input is Q4.28, output is Q1.31 */
49 /**
50 * Compute fixed point cordicsine with table lookup and interpolation
51 * The cordic sine algorithm converges, when the angle is in the range
52 * [-pi/2, pi/2).If an angle is outside of this range, then a multiple of
53 * pi/2 is added or subtracted from the angle until it is within the range
54 * [-pi/2,pi/2).Start with the angle in the range [-2*pi, 2*pi) and output
55 * has range in [-1.0 to 1.0]
56 * +------------------+-----------------+--------+--------+
57 * | thRadFxp | cdcsinth |thRadFxp|cdcsinth|
58 * +----+-----+-------+----+----+-------+--------+--------+
59 * |WLen| FLen|Signbit|WLen|FLen|Signbit| Qformat| Qformat|
60 * +----+-----+-------+----+----+-------+--------+--------+
61 * | 32 | 28 | 1 | 32 | 31 | 1 | 4.28 | 1.31 |
62 * +------------------+-----------------+--------+--------+
63 */
sin_fixed_32b(int32_t th_rad_fxp)64 static inline int32_t sin_fixed_32b(int32_t th_rad_fxp)
65 {
66 int32_t th_cdc_fxp;
67 int32_t sign;
68 int32_t b_yn;
69 int32_t xn;
70 cordic_approx(th_rad_fxp, CORDIC_31B_TABLE_SIZE, &sign, &b_yn, &xn, &th_cdc_fxp);
71
72 th_cdc_fxp = sign * b_yn;
73 /*convert Q2.30 to Q1.31 format*/
74 return sat_int32(Q_SHIFT_LEFT((int64_t)th_cdc_fxp, 30, 31));
75 }
76
77 /**
78 * Compute fixed point cordicsine with table lookup and interpolation
79 * The cordic cosine algorithm converges, when the angle is in the range
80 * [-pi/2, pi/2).If an angle is outside of this range, then a multiple of
81 * pi/2 is added or subtracted from the angle until it is within the range
82 * [-pi/2,pi/2).Start with the angle in the range [-2*pi, 2*pi) and output
83 * has range in [-1.0 to 1.0]
84 * +------------------+-----------------+--------+--------+
85 * | thRadFxp | cdccosth |thRadFxp|cdccosth|
86 * +----+-----+-------+----+----+-------+--------+--------+
87 * |WLen| FLen|Signbit|WLen|FLen|Signbit| Qformat| Qformat|
88 * +----+-----+-------+----+----+-------+--------+--------+
89 * | 32 | 28 | 1 | 32 | 31 | 1 | 4.28 | 1.31 |
90 * +------------------+-----------------+--------+--------+
91 */
cos_fixed_32b(int32_t th_rad_fxp)92 static inline int32_t cos_fixed_32b(int32_t th_rad_fxp)
93 {
94 int32_t th_cdc_fxp;
95 int32_t sign;
96 int32_t b_yn;
97 int32_t xn;
98 cordic_approx(th_rad_fxp, CORDIC_31B_TABLE_SIZE, &sign, &b_yn, &xn, &th_cdc_fxp);
99
100 th_cdc_fxp = sign * xn;
101 /*convert Q2.30 to Q1.31 format*/
102 return sat_int32(Q_SHIFT_LEFT((int64_t)th_cdc_fxp, 30, 31));
103 }
104
105 /* Input is Q4.28, output is Q1.15 */
106 /**
107 * Compute fixed point cordic sine with table lookup and interpolation
108 * The cordic sine algorithm converges, when the angle is in the range
109 * [-pi/2, pi/2).If an angle is outside of this range, then a multiple of
110 * pi/2 is added or subtracted from the angle until it is within the range
111 * [-pi/2,pi/2).Start with the angle in the range [-2*pi, 2*pi) and output
112 * has range in [-1.0 to 1.0]
113 * +------------------+-----------------+--------+------------+
114 * | thRadFxp | cdcsinth |thRadFxp| cdcsinth|
115 * +----+-----+-------+----+----+-------+--------+------------+
116 * |WLen| FLen|Signbit|WLen|FLen|Signbit| Qformat| Qformat |
117 * +----+-----+-------+----+----+-------+--------+------------+
118 * | 32 | 28 | 1 | 32 | 15 | 1 | 4.28 | 1.15 |
119 * +------------------+-----------------+--------+------------+
120 */
sin_fixed_16b(int32_t th_rad_fxp)121 static inline int16_t sin_fixed_16b(int32_t th_rad_fxp)
122 {
123 int32_t th_cdc_fxp;
124 int32_t sign;
125 int32_t b_yn;
126 int32_t xn;
127
128 cordic_approx(th_rad_fxp, CORDIC_15B_TABLE_SIZE, &sign, &b_yn, &xn, &th_cdc_fxp);
129
130 th_cdc_fxp = sign * b_yn;
131 /*convert Q2.30 to Q1.15 format*/
132 return sat_int16(Q_SHIFT_RND(th_cdc_fxp, 30, 15));
133 }
134
135 /**
136 * Compute fixed point cordic cosine with table lookup and interpolation
137 * The cordic cos algorithm converges, when the angle is in the range
138 * [-pi/2, pi/2).If an angle is outside of this range, then a multiple of
139 * pi/2 is added or subtracted from the angle until it is within the range
140 * [-pi/2,pi/2).Start with the angle in the range [-2*pi, 2*pi) and output
141 * has range in [-1.0 to 1.0]
142 * +------------------+-----------------+--------+------------+
143 * | thRadFxp | cdccosth |thRadFxp| cdccosth|
144 * +----+-----+-------+----+----+-------+--------+------------+
145 * |WLen| FLen|Signbit|WLen|FLen|Signbit| Qformat| Qformat |
146 * +----+-----+-------+----+----+-------+--------+------------+
147 * | 32 | 28 | 1 | 32 | 15 | 1 | 4.28 | 1.15 |
148 * +------------------+-----------------+--------+------------+
149 */
cos_fixed_16b(int32_t th_rad_fxp)150 static inline int16_t cos_fixed_16b(int32_t th_rad_fxp)
151 {
152 int32_t th_cdc_fxp;
153 int32_t sign;
154 int32_t b_yn;
155 int32_t xn;
156
157 cordic_approx(th_rad_fxp, CORDIC_15B_TABLE_SIZE, &sign, &b_yn, &xn, &th_cdc_fxp);
158
159 th_cdc_fxp = sign * xn;
160 /*convert Q2.30 to Q1.15 format*/
161 return sat_int16(Q_SHIFT_RND(th_cdc_fxp, 30, 15));
162 }
163
164 /**
165 * CORDIC-based approximation of complex exponential e^(j*THETA).
166 * computes COS(THETA) + j*SIN(THETA) using CORDIC algorithm
167 * approximation and returns the complex result.
168 * THETA values must be in the range [-2*pi, 2*pi). The cordic
169 * exponential algorithm converges, when the angle is in the
170 * range [-pi/2, pi/2).If an angle is outside of this range,
171 * then a multiple of pi/2 is added or subtracted from the
172 * angle until it is within the range [-pi/2,pi/2).Start
173 * with the angle in the range [-2*pi, 2*pi) and output has
174 * range in [-1.0 to 1.0]
175 * Error (max = 0.000000015832484), THD+N = -167.082852232808847
176 * +------------------+-----------------+--------+------------+
177 * | thRadFxp |cdccexpth |thRadFxp| cdccexpth|
178 * +----+-----+-------+----+----+-------+--------+------------+
179 * |WLen| FLen|Signbit|WLen|FLen|Signbit| Qformat| Qformat |
180 * +----+-----+-------+----+----+-------+--------+------------+
181 * | 32 | 28 | 1 | 32 | 15 | 1 | 4.28 | 2.30 |
182 * +------------------+-----------------+--------+------------+
183 */
cmpx_exp_32b(int32_t th_rad_fxp,struct cordic_cmpx * cexp)184 static inline void cmpx_exp_32b(int32_t th_rad_fxp, struct cordic_cmpx *cexp)
185 {
186 int32_t th_cdc_fxp;
187 int32_t sign;
188 int32_t b_yn;
189 int32_t xn;
190
191 cordic_approx(th_rad_fxp, CORDIC_31B_TABLE_SIZE, &sign, &b_yn, &xn, &th_cdc_fxp);
192 cmpx_cexp(sign, b_yn, xn, EN_32B_CORDIC_CEXP, cexp);
193 /* return the complex(re & im) result in Q2.30*/
194 }
195
196 /**
197 * CORDIC-based approximation of complex exponential e^(j*THETA).
198 * computes COS(THETA) + j*SIN(THETA) using CORDIC algorithm
199 * approximation and returns the complex result.
200 * THETA values must be in the range [-2*pi, 2*pi). The cordic
201 * exponential algorithm converges, when the angle is in the
202 * range [-pi/2, pi/2).If an angle is outside of this range,
203 * then a multiple of pi/2 is added or subtracted from the
204 * angle until it is within the range [-pi/2,pi/2).Start
205 * with the angle in the range [-2*pi, 2*pi) and output has
206 * range in [-1.0 to 1.0]
207 * Error (max = 0.000060862861574), THD+N = -89.049303454077403
208 * +------------------+-----------------+--------+------------+
209 * | thRadFxp |cdccexpth |thRadFxp| cdccexpth|
210 * +----+-----+-------+----+----+-------+--------+------------+
211 * |WLen| FLen|Signbit|WLen|FLen|Signbit| Qformat| Qformat |
212 * +----+-----+-------+----+----+-------+--------+------------+
213 * | 32 | 28 | 1 | 32 | 15 | 1 | 4.28 | 1.15 |
214 * +------------------+-----------------+--------+------------+
215 */
cmpx_exp_16b(int32_t th_rad_fxp,struct cordic_cmpx * cexp)216 static inline void cmpx_exp_16b(int32_t th_rad_fxp, struct cordic_cmpx *cexp)
217 {
218 int32_t th_cdc_fxp;
219 int32_t sign;
220 int32_t b_yn;
221 int32_t xn;
222
223 /* compute coeff from angles */
224 cordic_approx(th_rad_fxp, CORDIC_15B_TABLE_SIZE, &sign, &b_yn, &xn, &th_cdc_fxp);
225 cmpx_cexp(sign, b_yn, xn, EN_16B_CORDIC_CEXP, cexp);
226 /* return the complex(re & im) result in Q1.15*/
227 }
228
229 /**
230 * CORDIC-based approximation of inverse sine
231 * inverse sine of cdc_asin_theta based on a CORDIC approximation.
232 * asin(cdc_asin_th) inverse sine angle values in radian produces using the DCORDIC
233 * (Double CORDIC) algorithm.
234 * Inverse sine angle values in rad
235 * Q2.30 cdc_asin_th, value in between range of [-1 to 1]
236 * Q2.30 th_asin_fxp, output value range [-1.5707963258028 to 1.5707963258028]
237 * LUT size set type 15
238 * Error (max = 0.000000027939677), THD+N = -157.454534077921551 (dBc)
239 */
asin_fixed_32b(int32_t cdc_asin_th)240 static inline int32_t asin_fixed_32b(int32_t cdc_asin_th)
241 {
242 int32_t th_asin_fxp;
243
244 if (cdc_asin_th >= 0)
245 th_asin_fxp = is_scalar_cordic_asin(cdc_asin_th,
246 CORDIC_31B_TABLE_SIZE);
247 else
248 th_asin_fxp = -is_scalar_cordic_asin(-cdc_asin_th,
249 CORDIC_31B_TABLE_SIZE);
250
251 return th_asin_fxp; /* Q2.30 */
252 }
253
254 /**
255 * CORDIC-based approximation of inverse cosine
256 * inverse cosine of cdc_acos_theta based on a CORDIC approximation
257 * acos(cdc_acos_th) inverse cosine angle values in radian produces using the DCORDIC
258 * (Double CORDIC) algorithm.
259 * Q2.30 cdc_acos_th , input value range [-1 to 1]
260 * Q3.29 th_acos_fxp, output value range [3.14159265346825 to 0]
261 * LUT size set type 31
262 * Error (max = 0.000000026077032), THD+N = -157.948952635422842 (dBc)
263 */
acos_fixed_32b(int32_t cdc_acos_th)264 static inline int32_t acos_fixed_32b(int32_t cdc_acos_th)
265 {
266 int32_t th_acos_fxp;
267
268 if (cdc_acos_th >= 0)
269 th_acos_fxp = is_scalar_cordic_acos(cdc_acos_th,
270 CORDIC_31B_TABLE_SIZE);
271 else
272 th_acos_fxp =
273 PI_MUL2_Q4_28 - is_scalar_cordic_acos(-cdc_acos_th,
274 CORDIC_31B_TABLE_SIZE);
275
276 return th_acos_fxp; /* Q3.29 */
277 }
278
279 /**
280 * CORDIC-based approximation of inverse sine
281 * inverse sine of cdc_asin_theta based on a CORDIC approximation.
282 * asin(cdc_asin_th) inverse sine angle values in radian produces using the DCORDIC
283 * (Double CORDIC) algorithm.
284 * Inverse sine angle values in rad
285 * Q2.30 cdc_asin_th, value in between range of [-1 to 1]
286 * Q2.14 th_asin_fxp, output value range [-1.5707963258028 to 1.5707963258028]
287 * LUT size set type 31
288 * number of iteration 15
289 * Error (max = 0.000059800222516), THD+N = -89.824282520774048 (dBc)
290 */
asin_fixed_16b(int32_t cdc_asin_th)291 static inline int16_t asin_fixed_16b(int32_t cdc_asin_th)
292 {
293 int32_t th_asin_fxp;
294
295 if (cdc_asin_th >= 0)
296 th_asin_fxp = is_scalar_cordic_asin(cdc_asin_th,
297 CORDIC_16B_ITABLE_SIZE);
298 else
299 th_asin_fxp = -is_scalar_cordic_asin(-cdc_asin_th,
300 CORDIC_16B_ITABLE_SIZE);
301 /*convert Q2.30 to Q2.14 format*/
302 return sat_int16(Q_SHIFT_RND(th_asin_fxp, 30, 14));
303 }
304
305 /**
306 * CORDIC-based approximation of inverse cosine
307 * inverse cosine of cdc_acos_theta based on a CORDIC approximation
308 * acos(cdc_acos_th) inverse cosine angle values in radian produces using the DCORDIC
309 * (Double CORDIC) algorithm.
310 * Q2.30 cdc_acos_th , input value range [-1 to 1]
311 * Q3.13 th_acos_fxp, output value range [3.14159265346825 to 0]
312 * LUT size set type 31
313 * number of iteration 15
314 * Error (max = 0.000059799232976), THD+N = -89.824298401466635 (dBc)
315 */
acos_fixed_16b(int32_t cdc_acos_th)316 static inline int16_t acos_fixed_16b(int32_t cdc_acos_th)
317 {
318 int32_t th_acos_fxp;
319
320 if (cdc_acos_th >= 0)
321 th_acos_fxp = is_scalar_cordic_acos(cdc_acos_th,
322 CORDIC_16B_ITABLE_SIZE);
323 else
324 th_acos_fxp =
325 PI_MUL2_Q4_28 - is_scalar_cordic_acos(-cdc_acos_th,
326 CORDIC_16B_ITABLE_SIZE);
327
328 /*convert Q3.29 to Q3.13 format*/
329 return sat_int16(Q_SHIFT_RND(th_acos_fxp, 29, 13));
330 }
331
332 #endif /* __SOF_MATH_TRIG_H__ */
333