orbital_elements.sf 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. #!/usr/bin/ruby
  2. #
  3. ## https://rosettacode.org/wiki/Orbital_elements
  4. #
  5. func orbital_state_vectors(
  6. semimajor_axis,
  7. eccentricity,
  8. inclination,
  9. longitude_of_ascending_node,
  10. argument_of_periapsis,
  11. true_anomaly
  12. ) {
  13. static vec = frequire('Math::Vector::Real')
  14. var (i, j, k) = (vec.V(1,0,0), vec.V(0,1,0), vec.V(0,0,1))
  15. func muladd(v1, x1, v2, x2) {
  16. v1.mul(x1).add(v2.mul(x2))
  17. }
  18. func rotate(Ref i, Ref j, α) {
  19. (*i, *j) = (
  20. muladd(*i, +cos(α), *j, sin(α)),
  21. muladd(*i, -sin(α), *j, cos(α)),
  22. )
  23. }
  24. rotate(\i, \j, longitude_of_ascending_node)
  25. rotate(\j, \k, inclination)
  26. rotate(\i, \j, argument_of_periapsis)
  27. var l = (eccentricity == 1 ? 2*semimajor_axis
  28. : semimajor_axis*(1 - eccentricity**2))
  29. var (c, s) = with(true_anomaly) { (.cos, .sin) }
  30. var r = l/(1 + eccentricity*c)
  31. var rprime = (s * r**2 / l)
  32. var position = muladd(i, c, j, s).mul(r)
  33. var speed = muladd(i, rprime*c - r*s, j, rprime*s + r*c)
  34. speed.div!(abs(speed))
  35. speed.mul!(sqrt(2/r - 1/semimajor_axis))
  36. struct Result { position, speed }
  37. Result([position,speed].map {|v| [v{:module}[]].map{ Num(_) } }...)
  38. }
  39. var r = orbital_state_vectors(
  40. semimajor_axis: 1,
  41. eccentricity: 0.1,
  42. inclination: 0,
  43. longitude_of_ascending_node: 355/(113*6),
  44. argument_of_periapsis: 0,
  45. true_anomaly: 0,
  46. )
  47. say '['+r.position.join(', ')+']'
  48. say '['+r.speed.join(', ')+']'
  49. assert_eq(r.position, [0.77942284339868, 0.450000034653684, 0])
  50. assert_eq(r.speed, [-0.552770840960444, 0.957427083179761, 0])