💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

199 lines
5.1 KiB

  1. /*
  2. * Copyright (C) 2023 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper source code.
  5. *
  6. * Antkeeper source code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper source code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #ifndef ANTKEEPER_PHYSICS_ORBIT_ANOMALY_HPP
  20. #define ANTKEEPER_PHYSICS_ORBIT_ANOMALY_HPP
  21. #include "math/numbers.hpp"
  22. #include <cmath>
  23. namespace physics {
  24. namespace orbit {
  25. /**
  26. * Orbital anomaly functions.
  27. */
  28. namespace anomaly {
  29. /**
  30. * Derives the eccentric anomaly given eccentricity and true anomaly.
  31. *
  32. * @param ec Eccentricity (e).
  33. * @param ta True anomaly (nu).
  34. * @return Eccentric anomaly (E).
  35. */
  36. template <class T>
  37. T true_to_eccentric(T ec, T ta);
  38. /**
  39. * Derives the mean anomaly given eccentricity and true anomaly.
  40. *
  41. * @param ec Eccentricity (e).
  42. * @param ta True anomaly (nu).
  43. * @return Mean anomaly (M).
  44. */
  45. template <class T>
  46. T true_to_mean(T ec, T ta);
  47. /**
  48. * Derives the true anomaly given eccentricity and eccentric anomaly.
  49. *
  50. * @param ec Eccentricity (e).
  51. * @param ea Eccentric anomaly (E).
  52. * @return True anomaly (nu).
  53. */
  54. template <class T>
  55. T eccentric_to_true(T ec, T ea);
  56. /**
  57. * Derives the mean anomaly given eccentricity and eccentric anomaly.
  58. *
  59. * @param ec Eccentricity (e).
  60. * @param ea Eccentric anomaly (E).
  61. * @return Mean anomaly (M).
  62. */
  63. template <class T>
  64. T eccentric_to_mean(T ec, T ea);
  65. /**
  66. * Iteratively derives the eccentric anomaly given eccentricity and mean anomaly.
  67. *
  68. * @param ec Eccentricity (e).
  69. * @param ma Mean anomaly (M).
  70. * @param iterations Maximum number of iterations.
  71. * @param tolerance Solution error tolerance.
  72. * @return Eccentric anomaly (E).
  73. *
  74. * @see Murison, Marc. (2006). A Practical Method for Solving the Kepler Equation. 10.13140/2.1.5019.6808.
  75. */
  76. template <class T>
  77. T mean_to_eccentric(T ec, T ma, std::size_t iterations, T tolerance);
  78. /**
  79. * Iteratively derives the true anomaly given eccentricity and mean anomaly.
  80. *
  81. * @param ec Eccentricity (e).
  82. * @param ma Mean anomaly (M).
  83. * @param iterations Maximum number of iterations.
  84. * @param tolerance Solution error tolerance.
  85. * @return True anomaly (nu).
  86. */
  87. template <class T>
  88. T mean_to_true(T ec, T ma, std::size_t iterations, T tolerance);
  89. template <class T>
  90. T true_to_eccentric(T ec, T ta)
  91. {
  92. // Parabolic orbit
  93. if (ec == T(1))
  94. return std::tan(ta * T(0.5));
  95. // Hyperbolic orbit
  96. if (ec > T(1))
  97. return std::acosh((ec + std::cos(ta)) / (T(1) + ec * std::cos(ta))) * ((ta < T(0)) ? T(-1) : T(1));
  98. // Elliptic orbit
  99. return std::atan2(std::sqrt(T(1) - ec * ec) * std::sin(ta), std::cos(ta) + ec);
  100. }
  101. template <class T>
  102. T true_to_mean(T ec, T ta)
  103. {
  104. return eccentric_to_mean(ec, true_to_eccentric(ec, ta));
  105. }
  106. template <class T>
  107. T eccentric_to_true(T ec, T ea)
  108. {
  109. // Parabolic orbit
  110. if (ec == T(1))
  111. return std::atan(ea) * T(2);
  112. // Hyperbolic orbit
  113. if (ec > T(1))
  114. return std::atan(std::sqrt((ec + T(1)) / (ec - T(1))) * std::tanh(ea * T(0.5))) * T(2);
  115. // Elliptic orbit
  116. return std::atan2(sqrt(T(1) - ec * ec) * std::sin(ea), std::cos(ea) - ec);
  117. }
  118. template <class T>
  119. T eccentric_to_mean(T ec, T ea)
  120. {
  121. // Parabolic orbit
  122. if (ec == T(1))
  123. return (ea * ea * ea) / T(6) + ea * T(0.5);
  124. // Hyperbolic orbit
  125. if (ec > T(1))
  126. return ec * std::sinh(ea) - ea;
  127. // Elliptic orbit
  128. return ea - ec * std::sin(ea);
  129. }
  130. template <class T>
  131. T mean_to_eccentric(T ec, T ma, std::size_t iterations, T tolerance)
  132. {
  133. // Wrap mean anomaly to `[-pi, pi]`
  134. ma = std::remainder(ma, math::two_pi<T>);
  135. // Third-order approximation of eccentric anomaly starting value, E0
  136. const T t33 = std::cos(ma);
  137. const T t34 = ec * ec;
  138. const T t35 = t34 * ec;
  139. T ea0 = ma + (T(-0.5) * t35 + ec + (t34 + T(1.5) * t33 * t35) * t33) * std::sin(ma);
  140. // Iteratively converge E0 and E1
  141. for (std::size_t i = 0; i < iterations; ++i)
  142. {
  143. // Third-order approximation of eccentric anomaly, E1
  144. const T t1 = std::cos(ea0);
  145. const T t2 = T(-1) + ec * t1;
  146. const T t3 = std::sin(ea0);
  147. const T t4 = ec * t3;
  148. const T t5 = -ea0 + t4 + ma;
  149. const T t6 = t5 / (T(0.5) * t5 * t4 / t2 + t2);
  150. const T ea1 = ea0 - (t5 / ((T(0.5) * t3 - (T(1) / T(6)) * t1 * t6) * ec * t6 + t2));
  151. // Determine solution error
  152. const T error = std::abs(ea1 - ea0);
  153. // Set E0 to E1
  154. ea0 = ea1;
  155. // Break if solution is within error tolerance
  156. if (error < tolerance)
  157. break;
  158. }
  159. return ea0;
  160. }
  161. template <class T>
  162. T mean_to_true(T ec, T ma, std::size_t iterations, T tolerance)
  163. {
  164. eccentric_to_true(ec, mean_to_eccentric(ec, ma, iterations, tolerance));
  165. }
  166. } // namespace anomaly
  167. } // namespace orbit
  168. } // namespace physics
  169. #endif // ANTKEEPER_PHYSICS_ORBIT_ANOMALY_HPP