AP_Math.cpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. #include "AP_Math.h"
  2. #include <float.h>
  3. #include <AP_InternalError/AP_InternalError.h>
  4. /*
  5. * is_equal(): Integer implementation, provided for convenience and
  6. * compatibility with old code. Expands to the same as comparing the values
  7. * directly
  8. */
  9. template <typename Arithmetic1, typename Arithmetic2>
  10. typename std::enable_if<std::is_integral<typename std::common_type<Arithmetic1, Arithmetic2>::type>::value ,bool>::type
  11. is_equal(const Arithmetic1 v_1, const Arithmetic2 v_2)
  12. {
  13. typedef typename std::common_type<Arithmetic1, Arithmetic2>::type common_type;
  14. return static_cast<common_type>(v_1) == static_cast<common_type>(v_2);
  15. }
  16. /*
  17. * is_equal(): double/float implementation - takes into account
  18. * std::numeric_limits<T>::epsilon() to return if 2 values are equal.
  19. */
  20. template <typename Arithmetic1, typename Arithmetic2>
  21. typename std::enable_if<std::is_floating_point<typename std::common_type<Arithmetic1, Arithmetic2>::type>::value, bool>::type
  22. is_equal(const Arithmetic1 v_1, const Arithmetic2 v_2)
  23. {
  24. #ifdef ALLOW_DOUBLE_MATH_FUNCTIONS
  25. typedef typename std::common_type<Arithmetic1, Arithmetic2>::type common_type;
  26. typedef typename std::remove_cv<common_type>::type common_type_nonconst;
  27. if (std::is_same<double, common_type_nonconst>::value) {
  28. return fabs(v_1 - v_2) < std::numeric_limits<double>::epsilon();
  29. }
  30. #endif
  31. return fabsf(v_1 - v_2) < std::numeric_limits<float>::epsilon();
  32. }
  33. template bool is_equal<int>(const int v_1, const int v_2);
  34. template bool is_equal<short>(const short v_1, const short v_2);
  35. template bool is_equal<long>(const long v_1, const long v_2);
  36. template bool is_equal<float>(const float v_1, const float v_2);
  37. template bool is_equal<double>(const double v_1, const double v_2);
  38. template <typename T>
  39. float safe_asin(const T v)
  40. {
  41. const float f = static_cast<const float>(v);
  42. if (isnan(f)) {
  43. return 0.0f;
  44. }
  45. if (f >= 1.0f) {
  46. return static_cast<float>(M_PI_2);
  47. }
  48. if (f <= -1.0f) {
  49. return static_cast<float>(-M_PI_2);
  50. }
  51. return asinf(f);
  52. }
  53. template float safe_asin<int>(const int v);
  54. template float safe_asin<short>(const short v);
  55. template float safe_asin<float>(const float v);
  56. template float safe_asin<double>(const double v);
  57. template <typename T>
  58. float safe_sqrt(const T v)
  59. {
  60. float ret = sqrtf(static_cast<float>(v));
  61. if (isnan(ret)) {
  62. return 0;
  63. }
  64. return ret;
  65. }
  66. template float safe_sqrt<int>(const int v);
  67. template float safe_sqrt<short>(const short v);
  68. template float safe_sqrt<float>(const float v);
  69. template float safe_sqrt<double>(const double v);
  70. /*
  71. * linear interpolation based on a variable in a range
  72. */
  73. float linear_interpolate(float low_output, float high_output,
  74. float var_value,
  75. float var_low, float var_high)
  76. {
  77. if (var_value <= var_low) {
  78. return low_output;
  79. }
  80. if (var_value >= var_high) {
  81. return high_output;
  82. }
  83. float p = (var_value - var_low) / (var_high - var_low);
  84. return low_output + p * (high_output - low_output);
  85. }
  86. /* cubic "expo" curve generator
  87. * alpha range: [0,1] min to max expo
  88. * input range: [-1,1]
  89. */
  90. float expo_curve(float alpha, float x)
  91. {
  92. return (1.0f - alpha) * x + alpha * x * x * x;
  93. }
  94. /* throttle curve generator
  95. * thr_mid: output at mid stick
  96. * alpha: expo coefficient
  97. * thr_in: [0-1]
  98. */
  99. float throttle_curve(float thr_mid, float alpha, float thr_in)
  100. {
  101. float alpha2 = alpha + 1.25 * (1.0f - alpha) * (0.5f - thr_mid) / 0.5f;
  102. alpha2 = constrain_float(alpha2, 0.0f, 1.0f);
  103. float thr_out = 0.0f;
  104. if (thr_in < 0.5f) {
  105. float t = linear_interpolate(-1.0f, 0.0f, thr_in, 0.0f, 0.5f);
  106. thr_out = linear_interpolate(0.0f, thr_mid, expo_curve(alpha, t), -1.0f, 0.0f);
  107. } else {
  108. float t = linear_interpolate(0.0f, 1.0f, thr_in, 0.5f, 1.0f);
  109. thr_out = linear_interpolate(thr_mid, 1.0f, expo_curve(alpha2, t), 0.0f, 1.0f);
  110. }
  111. return thr_out;
  112. }
  113. template <typename T>
  114. float wrap_180(const T angle, float unit_mod)
  115. {
  116. auto res = wrap_360(angle, unit_mod);
  117. if (res > 180.f * unit_mod) {
  118. res -= 360.f * unit_mod;
  119. }
  120. return res;
  121. }
  122. template float wrap_180<int>(const int angle, float unit_mod);
  123. template float wrap_180<short>(const short angle, float unit_mod);
  124. template float wrap_180<float>(const float angle, float unit_mod);
  125. template float wrap_180<double>(const double angle, float unit_mod);
  126. template <typename T>
  127. auto wrap_180_cd(const T angle) -> decltype(wrap_180(angle, 100.f))
  128. {
  129. return wrap_180(angle, 100.f);
  130. }
  131. template auto wrap_180_cd<float>(const float angle) -> decltype(wrap_180(angle, 100.f));
  132. template auto wrap_180_cd<int>(const int angle) -> decltype(wrap_180(angle, 100.f));
  133. template auto wrap_180_cd<long>(const long angle) -> decltype(wrap_180(angle, 100.f));
  134. template auto wrap_180_cd<short>(const short angle) -> decltype(wrap_180(angle, 100.f));
  135. template auto wrap_180_cd<double>(const double angle) -> decltype(wrap_360(angle, 100.f));
  136. template <typename T>
  137. float wrap_360(const T angle, float unit_mod)
  138. {
  139. const float ang_360 = 360.f * unit_mod;
  140. float res = fmodf(static_cast<float>(angle), ang_360);
  141. if (res < 0) {
  142. res += ang_360;
  143. }
  144. return res;
  145. }
  146. template float wrap_360<int>(const int angle, float unit_mod);
  147. template float wrap_360<short>(const short angle, float unit_mod);
  148. template float wrap_360<long>(const long angle, float unit_mod);
  149. template float wrap_360<float>(const float angle, float unit_mod);
  150. template float wrap_360<double>(const double angle, float unit_mod);
  151. template <typename T>
  152. auto wrap_360_cd(const T angle) -> decltype(wrap_360(angle, 100.f))
  153. {
  154. return wrap_360(angle, 100.f);
  155. }
  156. template auto wrap_360_cd<float>(const float angle) -> decltype(wrap_360(angle, 100.f));
  157. template auto wrap_360_cd<int>(const int angle) -> decltype(wrap_360(angle, 100.f));
  158. template auto wrap_360_cd<long>(const long angle) -> decltype(wrap_360(angle, 100.f));
  159. template auto wrap_360_cd<short>(const short angle) -> decltype(wrap_360(angle, 100.f));
  160. template auto wrap_360_cd<double>(const double angle) -> decltype(wrap_360(angle, 100.f));
  161. template <typename T>
  162. float wrap_PI(const T radian)
  163. {
  164. auto res = wrap_2PI(radian);
  165. if (res > M_PI) {
  166. res -= M_2PI;
  167. }
  168. return res;
  169. }
  170. template float wrap_PI<int>(const int radian);
  171. template float wrap_PI<short>(const short radian);
  172. template float wrap_PI<float>(const float radian);
  173. template float wrap_PI<double>(const double radian);
  174. template <typename T>
  175. float wrap_2PI(const T radian)
  176. {
  177. float res = fmodf(static_cast<float>(radian), M_2PI);
  178. if (res < 0) {
  179. res += M_2PI;
  180. }
  181. return res;
  182. }
  183. template float wrap_2PI<int>(const int radian);
  184. template float wrap_2PI<short>(const short radian);
  185. template float wrap_2PI<float>(const float radian);
  186. template float wrap_2PI<double>(const double radian);
  187. template <typename T>
  188. T constrain_value(const T amt, const T low, const T high)
  189. {
  190. // the check for NaN as a float prevents propagation of floating point
  191. // errors through any function that uses constrain_value(). The normal
  192. // float semantics already handle -Inf and +Inf
  193. if (isnan(amt)) {
  194. AP::internalerror().error(AP_InternalError::error_t::constraining_nan);
  195. return (low + high) / 2;
  196. }
  197. if (amt < low) {
  198. return low;
  199. }
  200. if (amt > high) {
  201. return high;
  202. }
  203. return amt;
  204. }
  205. template int constrain_value<int>(const int amt, const int low, const int high);
  206. template long constrain_value<long>(const long amt, const long low, const long high);
  207. template long long constrain_value<long long>(const long long amt, const long long low, const long long high);
  208. template short constrain_value<short>(const short amt, const short low, const short high);
  209. template float constrain_value<float>(const float amt, const float low, const float high);
  210. template double constrain_value<double>(const double amt, const double low, const double high);
  211. /*
  212. simple 16 bit random number generator
  213. */
  214. uint16_t get_random16(void)
  215. {
  216. static uint32_t m_z = 1234;
  217. static uint32_t m_w = 76542;
  218. m_z = 36969 * (m_z & 0xFFFFu) + (m_z >> 16);
  219. m_w = 18000 * (m_w & 0xFFFFu) + (m_w >> 16);
  220. return ((m_z << 16) + m_w) & 0xFFFF;
  221. }
  222. #if CONFIG_HAL_BOARD == HAL_BOARD_SITL
  223. // generate a random float between -1 and 1, for use in SITL
  224. float rand_float(void)
  225. {
  226. return ((((unsigned)random()) % 2000000) - 1.0e6) / 1.0e6;
  227. }
  228. Vector3f rand_vec3f(void)
  229. {
  230. Vector3f v = Vector3f(rand_float(),
  231. rand_float(),
  232. rand_float());
  233. if (!is_zero(v.length())) {
  234. v.normalize();
  235. }
  236. return v;
  237. }
  238. #endif
  239. bool is_valid_octal(uint16_t octal)
  240. {
  241. // treat "octal" as decimal and test if any decimal digit is > 7
  242. if (octal > 7777) {
  243. return false;
  244. } else if (octal % 10 > 7) {
  245. return false;
  246. } else if ((octal % 100)/10 > 7) {
  247. return false;
  248. } else if ((octal % 1000)/100 > 7) {
  249. return false;
  250. } else if ((octal % 10000)/1000 > 7) {
  251. return false;
  252. }
  253. return true;
  254. }
  255. /*
  256. return true if two rotations are equivalent
  257. This copes with the fact that we have some duplicates, like ROLL_180_YAW_90 and PITCH_180_YAW_270
  258. */
  259. bool rotation_equal(enum Rotation r1, enum Rotation r2)
  260. {
  261. if (r1 == r2) {
  262. return true;
  263. }
  264. Vector3f v(1,2,3);
  265. Vector3f v1 = v;
  266. Vector3f v2 = v;
  267. v1.rotate(r1);
  268. v2.rotate(r2);
  269. return (v1 - v2).length() < 0.001;
  270. }
  271. #if CONFIG_HAL_BOARD == HAL_BOARD_SITL
  272. // fill an array of float with NaN, used to invalidate memory in SITL
  273. void fill_nanf(float *f, uint16_t count)
  274. {
  275. while (count--) {
  276. *f++ = std::numeric_limits<float>::signaling_NaN();
  277. }
  278. }
  279. #endif