2 * This file is part of Cleanflight.
4 * Cleanflight is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * Cleanflight is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
25 #include "quaternion.h"
32 // http://lolengine.net/blog/2011/12/21/better-function-approximations
33 // Chebyshev http://stackoverflow.com/questions/345085/how-do-trigonometric-functions-work/345117#345117
34 // Thanks for ledvinap for making such accuracy possible! See: https://github.com/cleanflight/cleanflight/issues/940#issuecomment-110323384
35 // https://github.com/Crashpilot1000/HarakiriWebstore1/blob/master/src/mw.c#L1235
36 #if defined(FAST_MATH) || defined(VERY_FAST_MATH)
37 #if defined(VERY_FAST_MATH)
38 #define sinPolyCoef3 -1.666568107e-1f
39 #define sinPolyCoef5 8.312366210e-3f
40 #define sinPolyCoef7 -1.849218155e-4f
41 #define sinPolyCoef9 0
43 #define sinPolyCoef3 -1.666665710e-1f // Double: -1.666665709650470145824129400050267289858e-1
44 #define sinPolyCoef5 8.333017292e-3f // Double: 8.333017291562218127986291618761571373087e-3
45 #define sinPolyCoef7 -1.980661520e-4f // Double: -1.980661520135080504411629636078917643846e-4
46 #define sinPolyCoef9 2.600054768e-6f // Double: 2.600054767890361277123254766503271638682e-6
49 float sin_approx(float x
)
52 if (xint
< -32 || xint
> 32) return 0.0f
; // Stop here on error input (5 * 360 Deg)
53 while (x
> M_PIf
) x
-= (2.0f
* M_PIf
); // always wrap input angle to -PI..PI
54 while (x
< -M_PIf
) x
+= (2.0f
* M_PIf
);
55 if (x
> (0.5f
* M_PIf
)) x
= (0.5f
* M_PIf
) - (x
- (0.5f
* M_PIf
)); // We just pick -90..+90 Degree
56 else if (x
< -(0.5f
* M_PIf
)) x
= -(0.5f
* M_PIf
) - ((0.5f
* M_PIf
) + x
);
58 return x
+ x
* x2
* (sinPolyCoef3
+ x2
* (sinPolyCoef5
+ x2
* (sinPolyCoef7
+ x2
* sinPolyCoef9
)));
61 float cos_approx(float x
)
63 return sin_approx(x
+ (0.5f
* M_PIf
));
66 // https://github.com/Crashpilot1000/HarakiriWebstore1/blob/396715f73c6fcf859e0db0f34e12fe44bace6483/src/mw.c#L1292
67 // http://http.developer.nvidia.com/Cg/atan2.html (not working correctly!)
68 // Poly coefficients by @ledvinap (https://github.com/cleanflight/cleanflight/pull/1107)
69 // Max absolute error 0,000027 degree
70 float atan2_approx(float y
, float x
)
72 #define atanPolyCoef1 3.14551665884836e-07f
73 #define atanPolyCoef2 0.99997356613987f
74 #define atanPolyCoef3 0.14744007058297684f
75 #define atanPolyCoef4 0.3099814292351353f
76 #define atanPolyCoef5 0.05030176425872175f
77 #define atanPolyCoef6 0.1471039133652469f
78 #define atanPolyCoef7 0.6444640676891548f
80 float res
, absX
, absY
;
83 res
= MAX(absX
, absY
);
84 if (res
) res
= MIN(absX
, absY
) / res
;
86 res
= -((((atanPolyCoef5
* res
- atanPolyCoef4
) * res
- atanPolyCoef3
) * res
- atanPolyCoef2
) * res
- atanPolyCoef1
) / ((atanPolyCoef7
* res
+ atanPolyCoef6
) * res
+ 1.0f
);
87 if (absY
> absX
) res
= (M_PIf
/ 2.0f
) - res
;
88 if (x
< 0) res
= M_PIf
- res
;
89 if (y
< 0) res
= -res
;
93 // http://http.developer.nvidia.com/Cg/acos.html
94 // Handbook of Mathematical Functions
95 // M. Abramowitz and I.A. Stegun, Ed.
96 // Absolute error <= 6.7e-5
97 float acos_approx(float x
)
100 float result
= fast_fsqrtf(1.0f
- xa
) * (1.5707288f
+ xa
* (-0.2121144f
+ xa
* (0.0742610f
+ (-0.0187293f
* xa
))));
102 return M_PIf
- result
;
108 int gcd(int num
, int denom
)
114 return gcd(denom
, num
% denom
);
117 int32_t wrap_18000(int32_t angle
)
126 int16_t wrap_180(int16_t angle
)
135 int32_t wrap_36000(int32_t angle
)
144 int32_t applyDeadband(int32_t value
, int32_t deadband
)
146 if (ABS(value
) < deadband
) {
148 } else if (value
> 0) {
150 } else if (value
< 0) {
156 int32_t applyDeadbandRescaled(int32_t value
, int32_t deadband
, int32_t min
, int32_t max
)
158 if (ABS(value
) < deadband
) {
160 } else if (value
> 0) {
161 value
= scaleRange(value
- deadband
, 0, max
- deadband
, 0, max
);
162 } else if (value
< 0) {
163 value
= scaleRange(value
+ deadband
, min
+ deadband
, 0, min
, 0);
168 int32_t constrain(int32_t amt
, int32_t low
, int32_t high
)
178 float constrainf(float amt
, float low
, float high
)
188 void devClear(stdev_t
*dev
)
193 void devPush(stdev_t
*dev
, float x
)
197 dev
->m_oldM
= dev
->m_newM
= x
;
200 dev
->m_newM
= dev
->m_oldM
+ (x
- dev
->m_oldM
) / dev
->m_n
;
201 dev
->m_newS
= dev
->m_oldS
+ (x
- dev
->m_oldM
) * (x
- dev
->m_newM
);
202 dev
->m_oldM
= dev
->m_newM
;
203 dev
->m_oldS
= dev
->m_newS
;
207 float devVariance(stdev_t
*dev
)
209 return ((dev
->m_n
> 1) ? dev
->m_newS
/ (dev
->m_n
- 1) : 0.0f
);
212 float devStandardDeviation(stdev_t
*dev
)
214 return fast_fsqrtf(devVariance(dev
));
217 float degreesToRadians(int16_t degrees
)
219 return degrees
* RAD
;
222 int scaleRange(int x
, int srcMin
, int srcMax
, int destMin
, int destMax
) {
223 long int a
= ((long int) destMax
- (long int) destMin
) * ((long int) x
- (long int) srcMin
);
224 long int b
= (long int) srcMax
- (long int) srcMin
;
225 return ((a
/ b
) + destMin
);
228 float scaleRangef(float x
, float srcMin
, float srcMax
, float destMin
, float destMax
) {
229 float a
= (destMax
- destMin
) * (x
- srcMin
);
230 float b
= srcMax
- srcMin
;
231 return ((a
/ b
) + destMin
);
234 // Build rMat from Tait–Bryan angles (convention X1, Y2, Z3)
235 void rotationMatrixFromAngles(fpMat3_t
* rmat
, const fp_angles_t
* angles
)
237 float cosx
, sinx
, cosy
, siny
, cosz
, sinz
;
238 float coszcosx
, sinzcosx
, coszsinx
, sinzsinx
;
240 cosx
= cos_approx(angles
->angles
.roll
);
241 sinx
= sin_approx(angles
->angles
.roll
);
242 cosy
= cos_approx(angles
->angles
.pitch
);
243 siny
= sin_approx(angles
->angles
.pitch
);
244 cosz
= cos_approx(angles
->angles
.yaw
);
245 sinz
= sin_approx(angles
->angles
.yaw
);
247 coszcosx
= cosz
* cosx
;
248 sinzcosx
= sinz
* cosx
;
249 coszsinx
= sinx
* cosz
;
250 sinzsinx
= sinx
* sinz
;
252 rmat
->m
[0][X
] = cosz
* cosy
;
253 rmat
->m
[0][Y
] = -cosy
* sinz
;
254 rmat
->m
[0][Z
] = siny
;
255 rmat
->m
[1][X
] = sinzcosx
+ (coszsinx
* siny
);
256 rmat
->m
[1][Y
] = coszcosx
- (sinzsinx
* siny
);
257 rmat
->m
[1][Z
] = -sinx
* cosy
;
258 rmat
->m
[2][X
] = (sinzsinx
) - (coszcosx
* siny
);
259 rmat
->m
[2][Y
] = (coszsinx
) + (sinzcosx
* siny
);
260 rmat
->m
[2][Z
] = cosy
* cosx
;
263 void rotationMatrixFromAxisAngle(fpMat3_t
* rmat
, const fpAxisAngle_t
* a
)
265 const float sang
= sin_approx(a
->angle
);
266 const float cang
= cos_approx(a
->angle
);
267 const float C
= 1.0f
- cang
;
269 const float xC
= a
->axis
.x
* C
;
270 const float yC
= a
->axis
.y
* C
;
271 const float zC
= a
->axis
.z
* C
;
272 const float xxC
= a
->axis
.x
* xC
;
273 const float yyC
= a
->axis
.y
* yC
;
274 const float zzC
= a
->axis
.z
* zC
;
275 const float xyC
= a
->axis
.x
* yC
;
276 const float yzC
= a
->axis
.y
* zC
;
277 const float zxC
= a
->axis
.z
* xC
;
278 const float xs
= a
->axis
.x
* sang
;
279 const float ys
= a
->axis
.y
* sang
;
280 const float zs
= a
->axis
.z
* sang
;
282 rmat
->m
[0][X
] = xxC
+ cang
;
283 rmat
->m
[0][Y
] = xyC
- zs
;
284 rmat
->m
[0][Z
] = zxC
+ ys
;
286 rmat
->m
[1][X
] = zxC
+ ys
;
287 rmat
->m
[1][Y
] = yyC
+ cang
;
288 rmat
->m
[1][Z
] = yzC
- xs
;
290 rmat
->m
[2][X
] = zxC
- ys
;
291 rmat
->m
[2][Y
] = yzC
+ xs
;
292 rmat
->m
[2][Z
] = zzC
+ cang
;
295 // Quick median filter implementation
296 // (c) N. Devillard - 1998
297 // http://ndevilla.free.fr/median/median.pdf
298 #define QMF_SORT(type,a,b) { if ((a)>(b)) QMF_SWAP(type, (a),(b)); }
299 #define QMF_SWAP(type,a,b) { type temp=(a);(a)=(b);(b)=temp; }
301 int32_t quickMedianFilter3(int32_t * v
)
304 memcpy(p
, v
, sizeof(p
));
306 QMF_SORT(int32_t, p
[0], p
[1]); QMF_SORT(int32_t, p
[1], p
[2]); QMF_SORT(int32_t, p
[0], p
[1]) ;
310 int16_t quickMedianFilter3_16(int16_t * v
)
313 memcpy(p
, v
, sizeof(p
));
315 QMF_SORT(int16_t, p
[0], p
[1]); QMF_SORT(int16_t, p
[1], p
[2]); QMF_SORT(int16_t, p
[0], p
[1]) ;
319 int32_t quickMedianFilter5(int32_t * v
)
322 memcpy(p
, v
, sizeof(p
));
324 QMF_SORT(int32_t, p
[0], p
[1]); QMF_SORT(int32_t, p
[3], p
[4]); QMF_SORT(int32_t, p
[0], p
[3]);
325 QMF_SORT(int32_t, p
[1], p
[4]); QMF_SORT(int32_t, p
[1], p
[2]); QMF_SORT(int32_t, p
[2], p
[3]);
326 QMF_SORT(int32_t, p
[1], p
[2]);
330 int16_t quickMedianFilter5_16(int16_t * v
)
333 memcpy(p
, v
, sizeof(p
));
335 QMF_SORT(int16_t, p
[0], p
[1]); QMF_SORT(int16_t, p
[3], p
[4]); QMF_SORT(int16_t, p
[0], p
[3]);
336 QMF_SORT(int16_t, p
[1], p
[4]); QMF_SORT(int16_t, p
[1], p
[2]); QMF_SORT(int16_t, p
[2], p
[3]);
337 QMF_SORT(int16_t, p
[1], p
[2]);
341 int32_t quickMedianFilter7(int32_t * v
)
344 memcpy(p
, v
, sizeof(p
));
346 QMF_SORT(int32_t, p
[0], p
[5]); QMF_SORT(int32_t, p
[0], p
[3]); QMF_SORT(int32_t, p
[1], p
[6]);
347 QMF_SORT(int32_t, p
[2], p
[4]); QMF_SORT(int32_t, p
[0], p
[1]); QMF_SORT(int32_t, p
[3], p
[5]);
348 QMF_SORT(int32_t, p
[2], p
[6]); QMF_SORT(int32_t, p
[2], p
[3]); QMF_SORT(int32_t, p
[3], p
[6]);
349 QMF_SORT(int32_t, p
[4], p
[5]); QMF_SORT(int32_t, p
[1], p
[4]); QMF_SORT(int32_t, p
[1], p
[3]);
350 QMF_SORT(int32_t, p
[3], p
[4]);
354 int32_t quickMedianFilter9(int32_t * v
)
357 memcpy(p
, v
, sizeof(p
));
359 QMF_SORT(int32_t, p
[1], p
[2]); QMF_SORT(int32_t, p
[4], p
[5]); QMF_SORT(int32_t, p
[7], p
[8]);
360 QMF_SORT(int32_t, p
[0], p
[1]); QMF_SORT(int32_t, p
[3], p
[4]); QMF_SORT(int32_t, p
[6], p
[7]);
361 QMF_SORT(int32_t, p
[1], p
[2]); QMF_SORT(int32_t, p
[4], p
[5]); QMF_SORT(int32_t, p
[7], p
[8]);
362 QMF_SORT(int32_t, p
[0], p
[3]); QMF_SORT(int32_t, p
[5], p
[8]); QMF_SORT(int32_t, p
[4], p
[7]);
363 QMF_SORT(int32_t, p
[3], p
[6]); QMF_SORT(int32_t, p
[1], p
[4]); QMF_SORT(int32_t, p
[2], p
[5]);
364 QMF_SORT(int32_t, p
[4], p
[7]); QMF_SORT(int32_t, p
[4], p
[2]); QMF_SORT(int32_t, p
[6], p
[4]);
365 QMF_SORT(int32_t, p
[4], p
[2]);
369 void arraySubInt32(int32_t *dest
, int32_t *array1
, int32_t *array2
, int count
)
371 for (int i
= 0; i
< count
; i
++) {
372 dest
[i
] = array1
[i
] - array2
[i
];
377 * Sensor offset calculation code based on Freescale's AN4246
378 * Initial implementation by @HaukeRa
379 * Modified to be re-usable by @DigitalEntity
381 void sensorCalibrationResetState(sensorCalibrationState_t
* state
)
383 for (int i
= 0; i
< 4; i
++){
384 for (int j
= 0; j
< 4; j
++){
385 state
->XtX
[i
][j
] = 0;
392 void sensorCalibrationPushSampleForOffsetCalculation(sensorCalibrationState_t
* state
, float sample
[3])
394 state
->XtX
[0][0] += sample
[0] * sample
[0];
395 state
->XtX
[0][1] += sample
[0] * sample
[1];
396 state
->XtX
[0][2] += sample
[0] * sample
[2];
397 state
->XtX
[0][3] += sample
[0];
399 state
->XtX
[1][0] += sample
[1] * sample
[0];
400 state
->XtX
[1][1] += sample
[1] * sample
[1];
401 state
->XtX
[1][2] += sample
[1] * sample
[2];
402 state
->XtX
[1][3] += sample
[1];
404 state
->XtX
[2][0] += sample
[2] * sample
[0];
405 state
->XtX
[2][1] += sample
[2] * sample
[1];
406 state
->XtX
[2][2] += sample
[2] * sample
[2];
407 state
->XtX
[2][3] += sample
[2];
409 state
->XtX
[3][0] += sample
[0];
410 state
->XtX
[3][1] += sample
[1];
411 state
->XtX
[3][2] += sample
[2];
412 state
->XtX
[3][3] += 1;
414 float squareSum
= (sample
[0] * sample
[0]) + (sample
[1] * sample
[1]) + (sample
[2] * sample
[2]);
415 state
->XtY
[0] += sample
[0] * squareSum
;
416 state
->XtY
[1] += sample
[1] * squareSum
;
417 state
->XtY
[2] += sample
[2] * squareSum
;
418 state
->XtY
[3] += squareSum
;
421 void sensorCalibrationPushSampleForScaleCalculation(sensorCalibrationState_t
* state
, int axis
, float sample
[3], int target
)
423 for (int i
= 0; i
< 3; i
++) {
424 float scaledSample
= (float)sample
[i
] / (float)target
;
425 state
->XtX
[axis
][i
] += scaledSample
* scaledSample
;
426 state
->XtX
[3][i
] += scaledSample
* scaledSample
;
429 state
->XtX
[axis
][3] += 1;
430 state
->XtY
[axis
] += 1;
434 static void sensorCalibration_gaussLR(float mat
[4][4]) {
437 for (i
= 0; i
< 4; i
++) {
439 for (j
= i
; j
< 4; j
++) {
440 for (k
= 0; k
< i
; k
++) {
441 mat
[i
][j
] -= mat
[i
][k
] * mat
[k
][j
];
445 for (j
= i
+ 1; j
< n
; j
++) {
446 for (k
= 0; k
< i
; k
++) {
447 mat
[j
][i
] -= mat
[j
][k
] * mat
[k
][i
];
449 mat
[j
][i
] /= mat
[i
][i
];
454 void sensorCalibration_ForwardSubstitution(float LR
[4][4], float y
[4], float b
[4]) {
456 for (i
= 0; i
< 4; ++i
) {
458 for (k
= 0; k
< i
; ++k
) {
459 y
[i
] -= LR
[i
][k
] * y
[k
];
461 //y[i] /= MAT_ELEM_AT(LR,i,i); //Do not use, LR(i,i) is 1 anyways and not stored in this matrix
465 void sensorCalibration_BackwardSubstitution(float LR
[4][4], float x
[4], float y
[4]) {
467 for (i
= 3 ; i
>= 0; --i
) {
469 for (k
= i
+ 1; k
< 4; ++k
) {
470 x
[i
] -= LR
[i
][k
] * x
[k
];
476 // solve linear equation
477 // https://en.wikipedia.org/wiki/Gaussian_elimination
478 static void sensorCalibration_SolveLGS(float A
[4][4], float x
[4], float b
[4]) {
482 sensorCalibration_gaussLR(A
);
484 for (i
= 0; i
< 4; ++i
) {
488 sensorCalibration_ForwardSubstitution(A
, y
, b
);
489 sensorCalibration_BackwardSubstitution(A
, x
, y
);
492 bool sensorCalibrationValidateResult(const float result
[3])
494 // Validate that result is not INF and not NAN
495 for (int i
= 0; i
< 3; i
++) {
496 if (isnan(result
[i
]) && isinf(result
[i
])) {
504 bool sensorCalibrationSolveForOffset(sensorCalibrationState_t
* state
, float result
[3])
507 sensorCalibration_SolveLGS(state
->XtX
, beta
, state
->XtY
);
509 for (int i
= 0; i
< 3; i
++) {
510 result
[i
] = beta
[i
] / 2;
513 return sensorCalibrationValidateResult(result
);
516 bool sensorCalibrationSolveForScale(sensorCalibrationState_t
* state
, float result
[3])
519 sensorCalibration_SolveLGS(state
->XtX
, beta
, state
->XtY
);
521 for (int i
= 0; i
< 3; i
++) {
522 result
[i
] = fast_fsqrtf(beta
[i
]);
525 return sensorCalibrationValidateResult(result
);
528 float gaussian(const float x
, const float mu
, const float sigma
) {
529 return exp(-pow((double)(x
- mu
), 2) / (2 * pow((double)sigma
, 2)));
532 float bellCurve(const float x
, const float curveWidth
)
534 return gaussian(x
, 0.0f
, curveWidth
);
538 * @brief Calculate the attenuation of a value using a Gaussian function.
539 * Retuns 1 for input 0 and ~0 for input width.
540 * @param input The input value.
541 * @param width The width of the Gaussian function.
542 * @return The attenuation of the input value.
544 float attenuation(const float input
, const float width
) {
545 const float sigma
= width
/ 2.35482f
; // Approximately width / sqrt(2 * ln(2))
546 return gaussian(input
, 0.0f
, sigma
);
549 float fast_fsqrtf(const float value
) {
552 arm_sqrt_f32(value
, &ret
);
563 // function to calculate the normalization (pythagoras) of a 2-dimensional vector
564 float NOINLINE
calc_length_pythagorean_2D(const float firstElement
, const float secondElement
)
566 return fast_fsqrtf(sq(firstElement
) + sq(secondElement
));
569 // function to calculate the normalization (pythagoras) of a 3-dimensional vector
570 float NOINLINE
calc_length_pythagorean_3D(const float firstElement
, const float secondElement
, const float thirdElement
)
572 return fast_fsqrtf(sq(firstElement
) + sq(secondElement
) + sq(thirdElement
));
578 * @brief Floating-point vector subtraction, equivalent of CMSIS arm_sub_f32.
586 for (uint32_t i
= 0; i
< blockSize
; i
++) {
587 pDst
[i
] = pSrcA
[i
] - pSrcB
[i
];
592 * @brief Floating-point vector scaling, equivalent of CMSIS arm_scale_f32.
600 for (uint32_t i
= 0; i
< blockSize
; i
++) {
601 pDst
[i
] = pSrc
[i
] * scale
;
606 * @brief Floating-point vector multiplication, equivalent of CMSIS arm_mult_f32.
614 for (uint32_t i
= 0; i
< blockSize
; i
++) {
615 pDst
[i
] = pSrcA
[i
] * pSrcB
[i
];