Calculer atan2 sans fonctions std ou C99

Je calcule les angles à partir d’un accéléromètre à 3 axes, mais mon compilateur n’a pas de fonction atan ou atan2. Il a une fente de mémoire réservée, mais il appelle une fonction que je ne trouve dans aucun fichier.

Mon compilateur est Keil µVision 4 utilisant le compilateur ARMCC. La compilation a le fichier math.h, mais la fonction est extern et n’existe pas:

extern _ARMABI double atan2(double /*y*/, double /*x*/); 

Existe-t-il une bibliothèque ou une fonction que je peux inclure et ayant la fonction arctan implémentée? Ou existe-t-il une autre fonction permettant de calculer les angles à partir de l’accéléromètre? J’ai besoin d’une calibration complète des angles sur 3 axes.

Edit: J’espérais éviter un tableau plein de valeurs pré-calculées.

Ce n’est pas très difficile d’implémenter votre propre arctan2 . Convertissez arctan2 en arctan utilisant cette formule. Et vous pouvez ensuite calculer arctan utilisant cette série infinie . Si vous additionnez un nombre suffisant de termes de cette série infinie, vous vous rapprocherez de ce que fait la fonction de bibliothèque arctan2 .

Voici une implémentation similaire pour exp() que vous pourriez utiliser comme référence.

Le code suivant utilise une approximation rationnelle pour obtenir l’arctangente normalisée à l’intervalle [0 1) (vous pouvez multiplier le résultat par Pi / 2 pour obtenir l’arctangente réel).

normalized_atan (x) ~ (bx + x ^ 2) / (1 + 2 bx + x ^ 2)

où b = 0,596227

L’erreur maximale est de 0.1620º

 #include  #include  // Approximates atan(x) normalized to the [-1,1] range // with a maximum error of 0.1620 degrees. float normalized_atan( float x ) { static const uint32_t sign_mask = 0x80000000; static const float b = 0.596227f; // Extract the sign bit uint32_t ux_s = sign_mask & (uint32_t &)x; // Calculate the arctangent in the first quadrant float bx_a = ::fabs( b * x ); float num = bx_a + x * x; float atan_1q = num / ( 1.f + bx_a + num ); // Restore the sign bit uint32_t atan_2q = ux_s | (uint32_t &)atan_1q; return (float &)atan_2q; } // Approximates atan2(y, x) normalized to the [0,4) range // with a maximum error of 0.1620 degrees float normalized_atan2( float y, float x ) { static const uint32_t sign_mask = 0x80000000; static const float b = 0.596227f; // Extract the sign bits uint32_t ux_s = sign_mask & (uint32_t &)x; uint32_t uy_s = sign_mask & (uint32_t &)y; // Determine the quadrant offset float q = (float)( ( ~ux_s & uy_s ) >> 29 | ux_s >> 30 ); // Calculate the arctangent in the first quadrant float bxy_a = ::fabs( b * x * y ); float num = bxy_a + y * y; float atan_1q = num / ( x * x + bxy_a + num ); // Translate it to the proper quadrant uint32_t uatan_2q = (ux_s ^ uy_s) | (uint32_t &)atan_1q; return q + (float &)uatan_2q; } 

Si vous avez besoin de plus de précision, il existe une fonction rationnelle du 3ème ordre:

normalized_atan (x) ~ (cx + x ^ 2 + x ^ 3) / (1 + (c + 1) x + (c + 1) x ^ 2 + x ^ 3)

où c = (1 + sqrt (17)) / 8

qui a une erreur d’approximation maximum de 0.00811º

Il existe une implémentation open source ici .

Les implémentations réelles des fonctions mathématiques (ou des stubs du HWFPU s’il en existe un) devraient être dans libm. Avec GCC, ceci est indiqué en passant -lm au compilateur, mais je ne sais pas comment cela se fait avec vos outils spécifiques.