Advertisement
Guest User

SimpleOrbitalMechanics0.001

a guest
Aug 16th, 2012
96
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 37.94 KB | None | 0 0
  1. -- SimpleOrbitalMechanics is a purely calculation based lua library, with some constants hardcoded for Kerbal Space Program
  2. -- v0.001
  3. -- to use, put
  4. -- require "SimpleOrbitalMechanics"
  5. -- in your lua script, or run it with
  6. -- dofile("SimpleOrbitalMechanics")
  7. -- Original Work Copyright 2012, Nadrek, insofar as any elements are protectable by copyright
  8. -- licensed under your choice of GPLv2, GPLv3, or Creative Commons Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)  http://www.gnu.org/licenses/gpl-2.0.html  or  http://www.gnu.org/licenses/gpl.html  or  http://creativecommons.org/licenses/by-sa/3.0/
  9. -- KSP specific functions will have KSP in the name; other functions will not, and can be used for real life calculations as well.
  10.  
  11. -- This script is primarily reference material and pure math; there is no dependency on KSP.
  12. -- This script is useful not only for playing with Kerbal Space Program (KSP), but also for calculating
  13. --   actual real life orbital mechanics around a variety of celestial bodies.
  14. -- While there are both RL and KSP data here, all data is entirely hardcoded, and no one kind of data
  15. --   will interfere with other kinds of use - the Real Life (RL) data will not interfere with playing KSP,
  16. --   and the KSP data will not interfere with RL usage.
  17. -- Orbital references include http://what-when-how.com/remote-sensing-from-air-and-space/a-few-standard-orbits-orbital-mechanics-interlude-remote-sensing/
  18. --     http://www.braeunig.us/space/orbmech.htm
  19. --     http://www.faqs.org/faqs/space/math/
  20.  
  21. -- global variables used in this script will be prepended with "globalSom" to avoid conflicts with globals from other scripts.
  22.  
  23. function globalSomOverallInit()
  24.   -- GM is the gravitational parameter (u) (used for orbiting objects of insignificant mass... like your spaceship or satellite)
  25.   -- KSP... refers to objects in Kerbal Space Program
  26.   -- RL... refers to objects in real life
  27.  
  28.  
  29.   -- Initialize our arrays.  Yes, a two dimensional array would be better, but this is very simple to understand and write.
  30.   globalSomCelestialBodyName = {} -- Universe_Galaxy_SolarSystem_BodyOrbitingSun_BodyOrbitingPriorBody
  31.   globalSomCelestialBodyGM = {} -- in m^3/s^2
  32.   globalSomCelestialBodySiderealRotationalPeriod = {} -- in seconds
  33.   globalSomCelestialBodyMinStableAltitude = {} -- in meters
  34.   globalSomCelestialBodyHillSphereOfInfluence = {} -- in meters
  35.   globalSomCelestialBodyEquatorialSurfaceGravity = {} -- in m/s^2
  36.   globalSomCelestialBodyEquatorialRadius = {} -- in meters
  37.  
  38.   -- WARNING: DO NOT DEPEND ON THE OFFSET REMAINING THE SAME!!!  USE THE NAME FIELD INSTEAD!!!
  39.  
  40.   -- KSP_Galaxy1_Kerbol_Kerbin per http://kerbalspaceprogram.com/~kerbalsp/wiki/index.php?title=Kerbin 20120813
  41.   --  and per http://kspwiki.nexisonline.net/wiki/Kerbin 20120813
  42.   globalSomCelestialBodyName[1] = "KSP_Galaxy1_Kerbol_Kerbin"
  43.   globalSomCelestialBodyGM[1] = 3530461000000 -- in m^3/s^2
  44.   globalSomCelestialBodySiderealRotationalPeriod[1] = 21600 -- in seconds (6 hours * 60 min/hr * 60 sec/min)
  45.   globalSomCelestialBodyMinStableAltitude[1] = 70000 -- in meters
  46.   globalSomCelestialBodyHillSphereOfInfluence[1] = 84275000 -- in meters
  47.   globalSomCelestialBodyEquatorialSurfaceGravity[1] = 9.8068 -- in m/s^2
  48.   globalSomCelestialBodyEquatorialRadius[1] = 600000 -- in meters
  49.  
  50.   -- KSP_Galaxy1_Kerbol_Kerbin_Mun per http://kerbalspaceprogram.com/~kerbalsp/wiki/index.php?title=Mun 20120813
  51.   --  and per http://kspwiki.nexisonline.net/wiki/Mun 20120813
  52.   globalSomCelestialBodyName[2] = "KSP_Galaxy1_Kerbol_Kerbin_Mun"
  53.   globalSomCelestialBodyGM[2] = 65136000000 -- in m^3/s^2
  54.   globalSomCelestialBodySiderealRotationalPeriod[2] = 147600 -- in seconds (41 hours * 60 min/hr * 60 sec/min)
  55.   globalSomCelestialBodyMinStableAltitude[2] = 4700 -- in meters
  56.   globalSomCelestialBodyHillSphereOfInfluence[2] = 2430000 -- in meters
  57.   globalSomCelestialBodyEquatorialSurfaceGravity[2] = 1.628 -- in m/s^2
  58.   globalSomCelestialBodyEquatorialRadius[2] = 200000 -- in meters
  59.  
  60.   -- KSP_Galaxy1_Kerbol_Kerbin_Minmus per http://kspwiki.nexisonline.net/wiki/Minmus 20120813
  61.   globalSomCelestialBodyName[3] = "KSP_Galaxy1_Kerbol_Kerbin_Minmus"
  62.   globalSomCelestialBodyGM[3] = 2825505000 -- in m^3/s^2
  63.   globalSomCelestialBodySiderealRotationalPeriod[3] = 1077379 -- in seconds (299.272 hours * 60 min/hr * 60 sec/min, and equal to Orbital Period)
  64.   globalSomCelestialBodyMinStableAltitude[3] = 5900 -- in meters
  65.   globalSomCelestialBodyHillSphereOfInfluence[3] = 2713000  -- in meters
  66.   globalSomCelestialBodyEquatorialSurfaceGravity[3] = 1.628 -- in m/s^2
  67.   globalSomCelestialBodyEquatorialRadius[3] = 60000 -- in meters
  68.  
  69.   -- RL_MilkyWay_Sol_Earth per https://en.wikipedia.org/wiki/Earth 20120813
  70.   --   and per http://www.earthobservatory.nasa.gov/Features/OrbitsCatalog/ 20120813
  71.   globalSomCelestialBodyName[4] = "RL_MilkyWay_Sol_Earth"
  72.   globalSomCelestialBodyGM[4] = 398600441800000 -- in m^3/s^2
  73.   globalSomCelestialBodySiderealRotationalPeriod[4] = 86164.098903691 -- sidereal rotation, stellar day, in seconds ((23 hours * 60 min/hr + 56 min) * 60 sec/min)+4.1 sec
  74.   globalSomCelestialBodyMinStableAltitude[4] = 180000 -- in meters
  75.   globalSomCelestialBodyHillSphereOfInfluence[4] = 1500000000  -- in meters
  76.   globalSomCelestialBodyEquatorialSurfaceGravity[4] = 9.780327 -- in m/s^2
  77.   globalSomCelestialBodyEquatorialRadius[4] = 6378100 -- in meters
  78.  
  79.   -- math.pi will do instead of a global, but if you like, try: globalPi = 3.1415926535897932384 -- a couple more digits than double precision can handle, to near-maximize accuracy
  80.   globale = 2.7182818284590452353 -- a couple more digits than double precision can handle, to near-maximize accuracy
  81. end
  82.  
  83. function globalSomMainBodyReset(MainBodyName)
  84.   -- MainBodyName must be one of RL_MilkyWay_Sol_Earth, KSP_Galaxy1_Kerbol_Kerbin_Mun, KSP_Galaxy1_Kerbol_Kerbin, or KSP_Galaxy1_Kerbol_Kerbin_Minmus
  85.  
  86.   -- in case we don't find the name we're looking for, set to defaults.
  87.   globalSomMainBodyNumber = nil
  88.   globalSomMainBodyName = nil
  89.   globalSomMainBodyGM = nil
  90.   globalSomMainBodySiderealRotationalPeriod = nil
  91.   globalSomMainBodyMinStableAltitude = nil
  92.   globalSomMainBodyHillSphereOfInfluence = nil
  93.   globalSomMainBodyEquatorialSurfaceGravity = nil
  94.   globalSomMainBodyEquatorialRadius = nil
  95.  
  96.  
  97.   local i
  98.   -- Loop through however many known Celestial Body Names we have
  99.   for i = 1, #globalSomCelestialBodyName do
  100.     -- If the name of that celestial body matches the name we were given, let's use that entry's data!
  101.     if MainBodyName == globalSomCelestialBodyName[i] then
  102.       globalSomMainBodyNumber = i + 0 -- this looks strange, but simply assigning = i ends up with #globalSomCelestialBodyName - presumably it acts as pointer assignment instead
  103.       globalSomMainBodyName = MainBodyName
  104.       globalSomMainBodyGM = globalSomCelestialBodyGM[i] -- in km^3/s^2
  105.       globalSomMainBodySiderealRotationalPeriod = globalSomCelestialBodySiderealRotationalPeriod[i] -- in seconds
  106.       globalSomMainBodyMinStableAltitude = globalSomCelestialBodyMinStableAltitude[i] -- in meters
  107.       globalSomMainBodyHillSphereOfInfluence = globalSomCelestialBodyHillSphereOfInfluence[i] -- in meters
  108.       globalSomMainBodyEquatorialSurfaceGravity = globalSomCelestialBodyEquatorialSurfaceGravity[i] -- in m/s^2
  109.       globalSomMainBodyEquatorialRadius = globalSomCelestialBodyEquatorialRadius[i] -- in meters
  110.     end
  111.   end
  112.  
  113.   if globalSomMainBodyNumber == nil then
  114.     print "ERROR: Unknown MainBodyName in globalSomMainBodyReset"
  115.     print "  expecting RL_MilkyWay_Sol_Earth, KSP_Galaxy1_Kerbol_Kerbin, KSP_Galaxy1_Kerbol_Kerbin_Mun, or KSP_Galaxy1_Kerbol_Kerbin_Minmus"
  116.   end
  117.  
  118. end
  119.  
  120.  
  121.  
  122. function calcSomSemiMajorAxisOrbitingSphereFromApPeMbr(Ap, Pe, MainBodyRadius)
  123.   -- Ap is the Apoapsis in meters
  124.   -- Pe is the Periapsis in meters
  125.   -- MainBodyRadius is the equatorial radius of the body being orbited in meters
  126.   -- The semi-major axis (a) of an ellipse (or a circle) is half the longest dimension of the
  127.   --   total ellipse; in other words, for a small body of trivial mass (your spaceship or satellite)
  128.   --   compared to the body it orbits (the mainBody), it's the Apoapsis plus the body it orbit's radius
  129.   --   (since it's assumed to orbit the center of the body), plus the same for Periapsis, divided by two.
  130.   -- This is deliberately coded for maximum readability.
  131.   return ((Ap + MainBodyRadius) + (Pe + MainBodyRadius))/2
  132. end
  133.  
  134.  
  135. function calcSomPeorapFromaAporpeMbr(a, Aporpe, MainBodyRadius)
  136.   -- a is the semi-major axis in meters
  137.   -- Aporpe is either Apoapsis or Periapsis, in meters - this returns the other one.
  138.   -- MainBodyRadius is the equatorial radius of the body being orbited in meters
  139.   -- This returns the opposite apsis from whatever you entered, in meters
  140.   --   i.e. if you feed it Apoapsis, it tells you Periapsis
  141.   --   i.e. if you feed it Periapsis, it tells you Apoapsis
  142.   return (2*a-(Aporpe + MainBodyRadius*2))
  143. end
  144.  
  145. function calcSomSiderealOrbitalPeriodFromaGm(a, GM)
  146.   -- a is the semi-major axis in meters
  147.   -- GM is the standard gravitational parameter in m^3/s^2 (also known as u)
  148.   -- returns the sidereal orbital period in seconds
  149.   -- For the equation, please see http://en.wikipedia.org/wiki/Orbital_period
  150.   return (2 * math.pi * (a^3/GM)^0.5)
  151. end
  152.  
  153. function calcSomSemiMajorAxisFromPeriodGm(Period, GM)
  154.   -- Period in seconds
  155.   -- GM is the standard gravitational parameter in m^3/s^2 (also known as u)
  156.   -- returns the semi-major axis (a) in meters
  157.   -- For the equation, please see http://en.wikipedia.org/wiki/Orbital_period and derive a = ...
  158.   return ((GM*(Period/(2*math.pi))^2)^(1/3))
  159. end
  160.  
  161. function calcSomSiderealOrbitalPeriodFromApPeMbrGm(Ap, Pe, MainBodyRadius, GM)
  162.   -- relies on globalSomOverallInit
  163.   -- Ap is the Apoapsis in meters
  164.   -- Pe is the Periapsis in meters
  165.   -- MainBodyRadius is the equatorial radius of the body being orbited in meters
  166.   -- GM is the standard gravitational parameter in m^3/s^2
  167.   -- returns the sidereal orbital period in seconds
  168.   local semiMajorAxis = calcSomSemiMajorAxisOrbitingSphereFromApPeMbr(Ap, Pe, MainBodyRadius)
  169.   return calcSomSiderealOrbitalPeriodFromaGm(semiMajorAxis, GM)
  170. end
  171.  
  172.  
  173. function calcSomOrbitalVelocityFromaGmRfcb(a, GM, RadiusFromCentralBody)
  174.   -- a is the semi-major axis in meters
  175.   -- GM is the standard gravitational parameter in m^3/s^2 (also known as u)
  176.   -- RadiusFromCentralBody is the distance in meters from the orbiting object to
  177.   --   the center of gravity it's orbiting (i.e. the center of the planet)
  178.   -- returns the orbital velocity in m/s
  179.   return ((GM*(2/RadiusFromCentralBody - 1/a))^0.5)
  180. end
  181.  
  182.  
  183. function calcSomOrbitalVelocityFromaGmAltaslMbr(a, GM, AltitudeASL, MainBodyRadius)
  184.   -- a is the semi-major axis in meters
  185.   -- GM is the standard gravitational parameter in m^3/s^2 (also known as u)
  186.   -- AltitudeASL is the altitude above sea level in meters
  187.   -- MainBodyRadius is the equatorial radius of the body being orbited in meters
  188.   -- returns the orbital velocity in m/s
  189.   local RadiusFromCentralBody = AltitudeASL + MainBodyRadius
  190.   return calcSomOrbitalVelocityFromaGmRfcb(a, GM, RadiusFromCentralBody)
  191. end
  192.  
  193.  
  194. function calcSomGMFromaOvRfcb(a, OrbitalVelocity, RadiusFromCentralBody)
  195.   -- a is the semi-major axis in meters
  196.   -- OrbitalVelocity is the orbital velocity in m/s
  197.   -- RadiusFromCentralBody is the distance in meters from the orbiting object to
  198.   --   the center of gravity it's orbiting (i.e. the center of the planet)
  199.   -- returns GM, the standard gravitational parameter in m^3/s^2 (also known as u)
  200.   return (OrbitalVelocity^2 / (2/RadiusFromCentralBody - 1/a))
  201. end
  202.  
  203.  
  204. function calcSomGMFromaOvAltaslMbr(a, OrbitalVelocity, AltitudeASL, MainBodyRadius)
  205.   -- a is the semi-major axis in meters
  206.   -- OrbitalVelocity is the orbital velocity in m/s
  207.   -- AltitudeASL is the altitude above sea level in meters
  208.   -- MainBodyRadius is the equatorial radius of the body being orbited in meters
  209.   -- returns GM, the standard gravitational parameter in m^3/s^2 (also known as u)
  210.   local RadiusFromCentralBody = AltitudeASL + MainBodyRadius
  211.   return calcSomGMFromaOvRfcb(a, OrbitalVelocity,RadiusFromCentralBody)
  212. end
  213.  
  214.  
  215. function guessSomWhatBodyIsTheMainBodyFromaOvAltaslMoe(a, OrbitalVelocity, AltitudeASL, MarginOfError)
  216.   -- a is the semi-major axis in meters
  217.   -- OrbitalVelocity is the orbital velocity in m/s
  218.   -- AltitudeASL is the altitude above sea level in meters
  219.   -- returns the SimpleOrbitalMechanics name of the body we think we're orbiting.
  220.   --   suitable to pass to globalSomMainBodyReset, or UNKNOWN if it cannot tell
  221.   -- NOTE: This goes through both RL and KSP bodies!
  222.   -- NOTE: You actually have to be in orbit first.
  223.   -- NOTE: Depends on globalSomOverallInit() having parameters for the body in question, and
  224.   --   having been called before now.
  225.   -- This is _extremely_ simplistic - we're just going to go through all the planets
  226.   --   we know about, and check each one.  First one we find that matches closely enough wins!
  227.  
  228.   local i
  229.   -- Loop through however many known Celestial Body Names we have
  230.   for i = 1, #globalSomCelestialBodyName do
  231.     -- If the name of that celestial body matches the name we were given, let's use that entry's data!
  232.     if math.abs((calcSomGMFromaOvAltaslMbr(a, OrbitalVelocity, AltitudeASL, globalSomCelestialBodyEquatorialRadius[i]))/globalSomCelestialBodyGM[i] - 1.0) < MarginOfError then
  233.       return globalSomCelestialBodyName[i]
  234.     end
  235.   end
  236.  
  237.   -- if we got here, it's because we didn't find a match and return with it from inside the for loop
  238.   return "UNKNOWN"
  239. end
  240.  
  241.  
  242.  
  243. function calcSomPeorapFromAporpeMbrGmSop(Aporpe, MainBodyRadius, GM, SiderealOrbitalPeriod)
  244.   -- Aporpe is either Apoapsis or Periapsis, in meters - you don't even need to know which
  245.   -- MainBodyRadius is the equatorial radius of the body being orbited in meters
  246.   -- GM is the standard gravitational parameter in m^3/s^2
  247.   -- SiderealOrbitalPeriod is the sidereal orbital period in seconds you wish the orbit to have
  248.   -- returns the Peorap (if given Apoapsis, returns Periapsis; if given Periapsis, returns Apoapsis
  249.   --   - and if you don't know which you're giving it going in, whichever is bigger at the end is Apoapsis)
  250.   -- This is deliberately coded for maximum readability; even a genius Kerbal should be able to follow
  251.   --   these instructions, if they take then slow and do them one small step at a time.
  252.  
  253.   -- NOTE: Molniya orbits circle twice per day, so the SiderealOrbitalPeriod needs to be half the SiderealRotationalPeriod
  254.   -- NOTE: Tundra orbits circle once per day, so the SiderealOrbitalPeriod needs to be equal to the SiderealRotationalPeriod
  255.  
  256.   -- a is the semi-major axis, which we'll use to calculate the Peorap shortly.
  257.   local a = calcSomSemiMajorAxisFromPeriodGm(SiderealOrbitalPeriod, GM)
  258.  
  259.   -- now that we have the semi-major axis, we can calculate the Peorap
  260.   -- i.e. if we were given the Ap, let's find the Pe.  If we were given the Pe, find the Ap.
  261.   local Peorap = calcSomPeorapFromaAporpeMbr(a, Aporpe, MainBodyRadius)
  262.  
  263.   -- WARNING WARNING WARNING - there's every chance this orbit will kill you or send you out of the local orbit!!!!
  264.   --  Use isSomOrbitStableFromApPeHsoiMsa to check it before using!!!
  265.  
  266.   return Peorap
  267. end
  268.  
  269. function calcSomMolniyaPeorapFromAporpeMbrGmSrp(Aporpe, MainBodyRadius, GM, SiderealRotationalPeriod)
  270.   -- Aporpe is either Apoapsis or Periapsis, in meters - you don't even need to know which
  271.   -- MainBodyRadius is the equatorial radius of the body being orbited in meters
  272.   -- GM is the standard gravitational parameter in m^3/s^2
  273.   -- SiderealRotationalPeriod is the sidereal rotational period in seconds of the body being orbited
  274.   -- returns the Peorap (if given Apoapsis, returns Periapsis; if given Periapsis, returns Apoapsis
  275.   --   - and if you don't know which you're giving it going in, whichever is bigger at the end is Apoapsis)
  276.   --   for a Molniya orbit, i.e. a semisynchronous orbit (two orbits per day)
  277.   -- NOTE: See calcSomPeorapFromAporpeMbrGmSop for details
  278.  
  279.   -- NOTE: Molniya orbits circle twice per day, so the SiderealOrbitalPeriod needs to be half the SiderealRotationalPeriod
  280.   local molniyaSiderealOrbitalPeriod = SiderealRotationalPeriod / 2
  281.   return calcSomPeorapFromAporpeMbrGmSop(Aporpe, MainBodyRadius, GM, molniyaSiderealOrbitalPeriod)
  282.  
  283.   -- WARNING WARNING WARNING - there's every chance this orbit will kill you or send you out of the local orbit!!!!
  284.   --  Use isSomOrbitStableFromApPeHsoiMsa to check it before using!!!
  285.  
  286. end
  287.  
  288. function calcSomApPeFromAporpePeorap(Aporpe, Peorap)
  289.   -- Aporpe is either Apoapsis or Periapsis, in meters - you don't even need to know which
  290.   -- Peorap is either Periapsis or Apoapsis, in meters - you don't even need to know which
  291.   -- returns Ap, Pe
  292.   --[[ Ex:
  293.        do
  294.        local localAp, localPe = calcSomApPeFromAporpePeorap(75000,3095000)
  295.        print("Ap: " .. localAp .. " Pe: " .. localPe)
  296.        end
  297.        ]]
  298.  
  299.   -- We'll find out which is which because the bigger one is the Ap.  If they're equal (perfectly circular orbit), who cares!
  300.   return math.max(Aporpe, Peorap), math.min(Aporpe, Peorap)
  301. end
  302.  
  303.  
  304.  
  305. function calcSomMolniyaApPeFromHsoiMsaMbrGmSrpMoe(HillSphereOfInfluence, MinStableAltitude, MainBodyRadius, GM, SiderealRotationalPeriod, MarginOfError)
  306.   -- HillSphereOfInfluence is the range in meters at which the gravity of the body is effective
  307.   -- MinStableAltitude is the altitude above sea level in meters at which orbiting is safe and stable
  308.   --   i.e. it's above both the atmosphere's effects, and the tallest mountains.
  309.   -- MainBodyRadius is the equatorial radius of the body being orbited in meters
  310.   -- GM is the standard gravitational parameter in m^3/s^2
  311.   -- SiderealRotationalPeriod is the sidereal rotational period in seconds of the body being orbited
  312.   -- MarginOfError 0.001 means allow 0.1% for a "safety zone" above the minimum stable altitude, or below the Hill sphere of influence.
  313.   -- Returns Ap and Pe of the best possible Molniya orbit for a given body
  314.   --   Returns -1, -1 if no stable Molniya orbit is possible
  315.   --[[ ex.
  316.     do
  317.     local localAp, localPe = calcSomMolniyaApPeFromHsoiMsaMbrGmSrpMoe(1500000000, 180000, 6378100, 398600441800000, 86164.098903691, 1.777777777)
  318.     print("Ap " .. localAp .. " Pe " .. localPe)
  319.     end
  320.     ]]
  321.   -- For oblate celestial bodies, of course, the inclination of the actual orbit must be 63.4 or 116.6 degrees, so the effect of the oblate equitorial belt is nullified.
  322.  
  323.   -- First, let's see if we can get a stable Molniya orbit with MinStableAltitude (including MarginOfError) as the Periapsis
  324.   --   this would be the ideal Molniya orbit, with maximum Apoapsis dwell time.
  325.   local Ap = calcSomMolniyaPeorapFromAporpeMbrGmSrp(MinStableAltitude * (1 + MarginOfError), MainBodyRadius, GM, SiderealRotationalPeriod)
  326.   if isSomOrbitStableFromApPeHsoiMsa(Ap, MinStableAltitude  * (1 + MarginOfError), HillSphereOfInfluence, MinStableAltitude) == 0 then
  327.    -- isSomOrbitStableFromApPeHsoiMsa returns 0 for a stable orbit.
  328.    return Ap, MinStableAltitude * (1 + MarginOfError)
  329.   end
  330.  
  331.   -- Well, if we're here, it wasn't a stable orbit.  We've got one more shot; let's see if we can get a crappy Molniya orbit
  332.   --   Perhaps if the Apoapsis is the Hill sphere of influence (minus a 1000 meter buffer), we can get a periapsis that works
  333.   local Pe = calcSomMolniyaPeorapFromAporpeMbrGmSrp(HillSphereOfInfluence  * (1 - MarginOfError), MainBodyRadius, GM, SiderealRotationalPeriod)
  334.   if isSomOrbitStableFromApPeHsoiMsa(HillSphereOfInfluence  * (1 - MarginOfError), Pe, HillSphereOfInfluence, MinStableAltitude) == 0 then
  335.     return HillSphereOfInfluence  * (1 - MarginOfError), Pe
  336.   end
  337.  
  338.   -- And if we made it past both tries, it's just not going to happen.
  339.   return -1, -1
  340.  
  341. end
  342.  
  343.  
  344. function isSomOrbitStableFromApPeHsoiMsa(Ap, Pe, HillSphereOfInfluence, MinStableAltitude)
  345.   -- Ap is the Apoapsis in meters
  346.   -- Pe is the Periapsis in meters
  347.   -- HillSphereOfInfluence is the range in meters at which the gravity of the body is effective
  348.   -- MinStableAltitude is the altitude above sea level in meters at which orbiting is safe and stable
  349.   --   i.e. it's above both the atmosphere's effects, and the tallest mountains.
  350.  
  351.  
  352.   -- technically, this is simple bit flags.  
  353.   -- 0 = stable
  354.   -- 1 = burn up in atmosphere
  355.   -- 2 = escape SOI
  356.   -- 3 = both burn up and escape SOI (whichever comes first)
  357.   -- 4 = your Apoapsis is greater than your Periapsis, which is just wrong.
  358.   returnValueisSomOrbitStableFromApPeHsoiMsa = 0 -- this should be a local, but when set to local scope the additions inside the ifs fail completely.
  359.   if Pe < MinStableAltitude then
  360.     returnValueisSomOrbitStableFromApPeHsoiMsa = returnValueisSomOrbitStableFromApPeHsoiMsa + 1
  361.   end
  362.   if Ap > HillSphereOfInfluence then
  363.     returnValueisSomOrbitStableFromApPeHsoiMsa = returnValueisSomOrbitStableFromApPeHsoiMsa + 2
  364.   end
  365.   if Pe > Ap then
  366.     returnValueisSomOrbitStableFromApPeHsoiMsa = returnValueisSomOrbitStableFromApPeHsoiMsa + 4
  367.   end
  368.   return returnValueisSomOrbitStableFromApPeHsoiMsa
  369.  
  370. end
  371.  
  372.  
  373. function testSomTestHarness()
  374.   -- If you get messages, then something broke!
  375.  
  376.   assert(calcSomSemiMajorAxisOrbitingSphereFromApPeMbr(4501000, 72001, 600000)>=2886500,"calcSomSemiMajorAxisOrbitingSphereFromApPeMbr test 1 Eccentric Kerbin orbit failed")
  377.   assert(calcSomSemiMajorAxisOrbitingSphereFromApPeMbr(4501000, 72001, 600000)<=2886501,"calcSomSemiMajorAxisOrbitingSphereFromApPeMbr test 2 Eccentric Kerbin orbit failed")
  378.  
  379.   assert(calcSomPeorapFromaAporpeMbr(750000, 75000, 600000)==225000,"calcSomPeorapFromaAporpeMbr test 1 Silly Kerbin orbit failed")
  380.  
  381.   assert(calcSomSiderealOrbitalPeriodFromaGm(26378000,398600441800000)>=42633,"calcSomSiderealOrbitalPeriodFromaGm test 1 GPS Earth orbit failed")
  382.   assert(calcSomSiderealOrbitalPeriodFromaGm(26378000,398600441800000)<=42637,"calcSomSiderealOrbitalPeriodFromaGm test 2 GPS Earth orbit failed")
  383.  
  384.   assert(calcSomSemiMajorAxisFromPeriodGm(86164,398600441800000)>=42164138,"calcSomSemiMajorAxisFromPeriodGm test 1 Geosync Earth orbit failed")
  385.   assert(calcSomSemiMajorAxisFromPeriodGm(86164,398600441800000)<=42164142,"calcSomSemiMajorAxisFromPeriodGm test 2 Geosync Earth orbit failed")
  386.  
  387.   assert(calcSomSiderealOrbitalPeriodFromApPeMbrGm(20314000, 20047000, 6378100, 398600441800000)>=43072,"calcSomSiderealOrbitalPeriodFromApPeMbrGm test 1 GPS Earth orbit failed")
  388.   assert(calcSomSiderealOrbitalPeriodFromApPeMbrGm(20314000, 20047000, 6378100, 398600441800000)<=43076,"calcSomSiderealOrbitalPeriodFromApPeMbrGm test 2 GPS Earth orbit failed")
  389.  
  390.   assert(calcSomOrbitalVelocityFromaGmRfcb(750000,3530461000000,750000)>=2169,"calcSomOrbitalVelocityFromaGmRfcb test 1 150km Kerbin circular orbit failed.")
  391.   assert(calcSomOrbitalVelocityFromaGmRfcb(750000,3530461000000,750000)<=2170,"calcSomOrbitalVelocityFromaGmRfcb test 2 150km Kerbin circular orbit failed.")
  392.  
  393.   assert(calcSomOrbitalVelocityFromaGmAltaslMbr(725000,3530461000000,125000,600000)>=2206,"calcSomOrbitalVelocityFromaGmAltaslMbr test 1 125km Kerbin circular orbit failed.")
  394.   assert(calcSomOrbitalVelocityFromaGmAltaslMbr(725000,3530461000000,125000,600000)<=2207,"calcSomOrbitalVelocityFromaGmAltaslMbr test 2 125km Kerbin circular orbit failed.")
  395.  
  396.   assert(calcSomGMFromaOvRfcb(362941.275006862,383.306541880459,399135.253432537)>=65138373282,"calcSomGMFromaOvRfcb test 1 126610-199271m Kerbin Mun orbit failed.")
  397.   assert(calcSomGMFromaOvRfcb(362941.275006862,383.306541880459,399135.253432537)<=65138373302,"calcSomGMFromaOvRfcb test 2 126610-199271m Kerbin Mun orbit failed.")
  398.   assert(calcSomGMFromaOvAltaslMbr(468746.649196013,407.483188333337,227130.402050318,200000)>=65138680733,"calcSomGMFromaOvAltaslMbr test 1 197405-340087km Kerbin Mun orbit failed.")
  399.   assert(calcSomGMFromaOvAltaslMbr(468746.649196013,407.483188333337,227130.402050318,200000)<=65138680753,"calcSomGMFromaOvAltaslMbr test 2 197405-340087km Kerbin Mun orbit failed.")
  400.  
  401.   assert(guessSomWhatBodyIsTheMainBodyFromaOvAltaslMoe(468780,394.1,242942,0.01)=="KSP_Galaxy1_Kerbol_Kerbin_Mun","guessSomWhatBodyIsTheMainBodyFromaOvAltaslMoe test 1 Kerbin Mun failed.")
  402.   assert(guessSomWhatBodyIsTheMainBodyFromaOvAltaslMoe(65955,207.0,5950,0.01)=="KSP_Galaxy1_Kerbol_Kerbin_Minmus","guessSomWhatBodyIsTheMainBodyFromaOvAltaslMoe test 2 Kerbin Minmus failed.")
  403.   assert(guessSomWhatBodyIsTheMainBodyFromaOvAltaslMoe(2187000,1130.4,1839000,0.01)=="KSP_Galaxy1_Kerbol_Kerbin","guessSomWhatBodyIsTheMainBodyFromaOvAltaslMoe test 3 Kerbin failed.")
  404.   assert(guessSomWhatBodyIsTheMainBodyFromaOvAltaslMoe(42164138,3075,35786000,0.01)=="RL_MilkyWay_Sol_Earth","guessSomWhatBodyIsTheMainBodyFromaOvAltaslMoe test 4 Earth Geosync failed.")
  405.   assert(guessSomWhatBodyIsTheMainBodyFromaOvAltaslMoe(5,5,5,0.0001)=="UNKNOWN","guessSomWhatBodyIsTheMainBodyFromaOvAltaslMoe test 5 Unknown orbit failed.")
  406.  
  407.   assert(calcSomPeorapFromAporpeMbrGmSop(703000, 6378100, 398600441800000, 5928)>=699653,"calcSomMolniyaPeorapFromAporpeMbrGmSrp test 1 Classic Earth Landsat failed")
  408.   assert(calcSomPeorapFromAporpeMbrGmSop(703000, 6378100, 398600441800000, 5928)<=699657,"calcSomMolniyaPeorapFromAporpeMbrGmSrp test 2 Classic Earth Landsat failed")
  409.   assert(calcSomMolniyaPeorapFromAporpeMbrGmSrp(500000, 6378100, 398600441800000, 86164.098903691)>=39867327,"calcSomMolniyaPeorapFromAporpeMbrGmSrp test 1 Classic Earth Molniya failed")
  410.   assert(calcSomMolniyaPeorapFromAporpeMbrGmSrp(500000, 6378100, 398600441800000, 86164.098903691)<=39867330,"calcSomMolniyaPeorapFromAporpeMbrGmSrp test 2 Classic Earth Molniya failed")
  411.   assert(calcSomMolniyaPeorapFromAporpeMbrGmSrp(39867328.3148597, 6378100, 398600441800000, 86164.098903691)>=499998,"calcSomMolniyaPeorapFromAporpeMbrGmSrp test 3 Classic Earth Molniya failed")
  412.   assert(calcSomMolniyaPeorapFromAporpeMbrGmSrp(39867328.3148597, 6378100, 398600441800000, 86164.098903691)<=500002,"calcSomMolniyaPeorapFromAporpeMbrGmSrp test 4 Classic Earth Molniya failed")
  413.   do
  414.     local localAp, localPe = calcSomApPeFromAporpePeorap(75000,3095000)
  415.     assert(localAp==3095000,"calcSomApPeFromAporpePeorap test 1 Pe first failed")
  416.     assert(localPe==75000,"calcSomApPeFromAporpePeorap test 2 Pe first failed")
  417.     local localAp, localPe = calcSomApPeFromAporpePeorap(2,1)
  418.     assert(localAp==2,"calcSomApPeFromAporpePeorap test 3 Ap first failed")
  419.     assert(localPe==1,"calcSomApPeFromAporpePeorap test 4 Ap first failed")
  420.   end
  421.  
  422.   do
  423.     local localAp, localPe = calcSomMolniyaApPeFromHsoiMsaMbrGmSrpMoe(1500000000, 180000, 6378100, 398600441800000, 86164.098903691, 1.777777777)
  424.     assert(localAp>=39867318,"calcSomMolniyaApPeFromHsoiMsaMbrGmSrpMoe test 1 Earth classic Molniya failed.")
  425.     assert(localAp<=39867338,"calcSomMolniyaApPeFromHsoiMsaMbrGmSrpMoe test 2 Earth classic Molniya failed.")
  426.     assert(localPe>=499998,"calcSomMolniyaApPeFromHsoiMsaMbrGmSrpMoe test 3 Earth classic Molniya failed.")
  427.     assert(localPe<=500002,"calcSomMolniyaApPeFromHsoiMsaMbrGmSrpMoe test 4 Earth classic Molniya failed.")
  428.     local localAp, localPe = calcSomMolniyaApPeFromHsoiMsaMbrGmSrpMoe(2430000, 4700, 200000, 65136000000, 147600, 0.01)
  429.     assert(localAp>=2405690,"calcSomMolniyaApPeFromHsoiMsaMbrGmSrpMoe test 5 Kerbin Mun crappy Molniya failed.")
  430.     assert(localAp<=2405710,"calcSomMolniyaApPeFromHsoiMsaMbrGmSrpMoe test 6 Kerbin Mun crappy Molniya failed.")
  431.     assert(localPe>=1352323,"calcSomMolniyaApPeFromHsoiMsaMbrGmSrpMoe test 7 Kerbin Mun crappy Molniya failed.")
  432.     assert(localPe<=1352343,"calcSomMolniyaApPeFromHsoiMsaMbrGmSrpMoe test 8 Kerbin Mun crappy Molniya failed.")
  433.     local localAp, localPe = calcSomMolniyaApPeFromHsoiMsaMbrGmSrpMoe(2130000, 4700, 200000, 65136000000, 197600, 0.01)
  434.     assert(localAp == (-1),"calcSomMolniyaApPeFromHsoiMsaMbrGmSrpMoe test 9 Impossible Molniya failed.") -- parenthesis around the -1 is required to get the desired  error
  435.     assert(localPe == (-1),"calcSomMolniyaApPeFromHsoiMsaMbrGmSrpMoe test 10 Impossible Molniya failed.") -- parenthesis around the -1 is required to get the desired  error
  436.   end
  437.  
  438.  
  439.   assert(isSomOrbitStableFromApPeHsoiMsa(100000,10000,200000,5000)==0,"isSomOrbitStableFromApPeHsoiMsa test 1 (stable orbit) failed")
  440.   assert(isSomOrbitStableFromApPeHsoiMsa(100000,10000,200000,10001)==1,"isSomOrbitStableFromApPeHsoiMsa test 2 (areobrake orbit) failed")
  441.   assert(isSomOrbitStableFromApPeHsoiMsa(200001,10000,200000,5000)==2,"isSomOrbitStableFromApPeHsoiMsa test 3 (escape orbit) failed")
  442.   assert(isSomOrbitStableFromApPeHsoiMsa(200001,10000,200000,10001)==3,"isSomOrbitStableFromApPeHsoiMsa test 4 (deathtrap orbit) failed")
  443.   assert(isSomOrbitStableFromApPeHsoiMsa(20000,30000,200000,5000)==4,"isSomOrbitStableFromApPeHsoiMsa test 5 (stupid orbit) failed")
  444.   print "Tests complete."
  445. end
  446.  
  447.  
  448.  
  449. function helpSomSimpleOrbitalMechanics1()
  450.   print "Usage: globalSomOverallInit()"
  451.   print "   Initializes unchanging global variables"
  452.   print "Usage: globalSomMainBodyReset(MainBodyName)"
  453.   print "   Initialized global variables that change based on the body"
  454.   print "   that is being orbited."
  455.   print "   MainBodyName must be one of RL_MilkyWay_Sol_Earth, KSP_Galaxy1_Kerbol_Kerbin_Mun, KSP_Galaxy1_Kerbol_Kerbin, or KSP_Galaxy1_Kerbol_Kerbin_Minmus"
  456.   print "Usage: calcSomSemiMajorAxisOrbitingSphereFromApPeMbr(Ap, Pe, MainBodyRadius)"
  457.   print "   Returns the semi-major axis based on Ap the Apoapsis,"
  458.   print "   Pe the Periapsis, and MainBodyRadius, the equatorial radius"
  459.   print "   of the body being orbited (assumed to be a sphere; at this time"
  460.   print "   the effects of a highly oblate body with a high inclination"
  461.   print "   orbit have not been investigated."
  462.   print "   All units must be the same.  I.e. for a 50x125km orbit around"
  463.   print "   Kerbin, calcSomSemiMajorAxisOrbitingSphereFromApPeMbr(125000,50000,600000)"
  464.   print "Usage: calcSomPeorapFromaAporpeMbr(a, Aporpe, MainBodyRadius)"
  465.   print "   a is the semi-major axis in meters"
  466.   print "   Aporpe is either Apoapsis or Periapsis, in meters"
  467.   print "   MainBodyRadius is the equatorial radius of the body being orbited in meters"
  468.   print "   This returns the opposite apsis from whatever you entered, in meters"
  469.   print "   i.e. if you feed it Apoapsis, it tells you Periapsis"
  470.   print "   i.e. if you feed it Periapsis, it tells you Apoapsis"
  471.   print "Usage: calcSomSiderealOrbitalPeriodFromaGm(a, GM)"
  472.   print "   Returns the period in seconds of the orbit, given a,"
  473.   print "   the semi-major axis in meters, and GM, the gravitational"
  474.   print "   parameter in m^3/s^2 of the body being orbited."
  475.   print "Usage: calcSomSemiMajorAxisFromPeriodGm(Period, GM)"
  476.   print "  Period in seconds"
  477.   print "  GM is the standard gravitational parameter in m^3/s^2"
  478.   print "  returns the semi-major axis (a) in meters"
  479. end
  480.  
  481. function helpSomSimpleOrbitalMechanics2()
  482.   print "Usage: calcSomSiderealOrbitalPeriodFromApPeMbrGm(Ap, Pe, MainBodyRadius, GM)"
  483.   print "   Returns the period in seconds of the orbit, given Ap"
  484.   print "   the Apoapsis, Pe the Periapsis, and GM the gravitational"
  485.   print "   parameter of the body being orbited."
  486.   print "Usage: calcSomOrbitalVelocityFromaGmRfcb(a, GM, RadiusFromCentralBody)"
  487.   print "   a is the semi-major axis in meters"
  488.   print "   GM is the standard gravitational parameter in m^3/s^2 (also known as u)"
  489.   print "   RadiusFromCentralBody is the distance in meters from the orbiting object"
  490.   print "     to the center of gravity it's orbiting (i.e. the center of the planet)"
  491.   print "   returns the orbital velocity in m/s"
  492.   print "Usage: calcSomOrbitalVelocityFromaGmAltaslMbr(a, GM, AltitudeASL, MainBodyRadius)"
  493.   print "   a is the semi-major axis in meters"
  494.   print "   GM is the standard gravitational parameter in m^3/s^2 (also known as u)"
  495.   print "   AltitudeASL is the altitude above sea level in meters"
  496.   print "   MainBodyRadius is the equatorial radius of the body being orbited in meters"
  497.   print "Usage: calcSomGMFromaOvRfcb(a, OrbitalVelocity, RadiusFromCentralBody)"
  498.   print "   a is the semi-major axis in meters"
  499.   print "   OrbitalVelocity is the orbital velocity in m/s"
  500.   print "   RadiusFromCentralBody is the distance in meters from the orbiting object to"
  501.   print "     the center of gravity it's orbiting (i.e. the center of the planet)"
  502.   print "   returns GM, the standard gravitational parameter in m^3/s^2 (also known as u)"
  503. end
  504.  
  505. function helpSomSimpleOrbitalMechanics3()  
  506.   print "Usage: calcSomGMFromaOvAltaslMbr(a, OrbitalVelocity, AltitudeASL, MainBodyRadius)"
  507.   print "   a is the semi-major axis in meters"
  508.   print "   OrbitalVelocity is the orbital velocity in m/s"
  509.   print "   AltitudeASL is the altitude above sea level in meters"
  510.   print "   MainBodyRadius is the equatorial radius of the body being orbited in meters"
  511.   print "   returns GM, the standard gravitational parameter in m^3/s^2 (also known as u)"
  512.   print "Usage: guessSomWhatBodyIsTheMainBodyFromaOvAltaslMoe(a, OrbitalVelocity, AltitudeASL, MarginOfError)"
  513.   print "   a is the semi-major axis in meters"
  514.   print "   OrbitalVelocity is the orbital velocity in m/s"
  515.   print "   AltitudeASL is the altitude above sea level in meters"
  516.   print "   returns the SimpleOrbitalMechanics name of the body we think we're orbiting."
  517.   print "     suitable to pass to globalSomMainBodyReset, or UNKNOWN if it cannot tell"
  518.   print "Usage: calcSomPeorapFromAporpeMbrGmSop(Aporpe, MainBodyRadius, GM, SiderealOrbitalPeriod)"
  519.   print "   Aporpe is either Apoapsis or Periapsis, in meters - you don't even need to know which"
  520.   print "   MainBodyRadius is the equatorial radius of the body being orbited in meters"
  521.   print "   GM is the standard gravitational parameter in m^3/s^2"
  522.   print "   SiderealOrbitalPeriod is the sidereal orbital period in seconds you wish the orbit to have"
  523.   print "   returns the Peorap (if given Apoapsis, returns Periapsis; if given Periapsis, returns Apoapsis"
  524.   print "      and if you don't know which you're giving it going in, whichever is bigger at the end is Apoapsis)"
  525.   print "   WARNING WARNING WARNING - there's every chance this orbit will kill you or send you out of the local orbit!!!!"
  526.   print "      Use isSomOrbitStableFromApPeHsoiMsa to check your orbit before using!!!"
  527. end
  528.  
  529. function helpSomSimpleOrbitalMechanics4()  
  530.   print "Usage: calcSomMolniyaPeorapFromAporpeMbrGmSrp(Aporpe, MainBodyRadius, GM, SiderealRotationalPeriod)"
  531.   print "   Aporpe is either Apoapsis or Periapsis, in meters - you don't even need to know which"
  532.   print "   MainBodyRadius is the equatorial radius of the body being orbited in meters"
  533.   print "   GM is the standard gravitational parameter in m^3/s^2"
  534.   print "   SiderealRotationalPeriod is the sidereal rotational period in seconds of the body being orbited"
  535.   print "   returns the Peorap (if given Apoapsis, returns Periapsis; if given Periapsis, returns Apoapsis"
  536.   print "      and if you don't know which you're giving it going in, whichever is bigger at the end is Apoapsis)"
  537.   print "      for a Molniya orbit, i.e. a semisynchronous orbit (two orbits per day)"
  538.   print "   WARNING WARNING WARNING - there's every chance this orbit will kill you or send you out of the local orbit!!!!"
  539.   print "      Use isSomOrbitStableFromApPeHsoiMsa to check your orbit before using!!!"
  540.   print "Usage: calcSomApPeFromAporpePeorap(Aporpe, Peorap)"
  541.   print "   Aporpe is either Apoapsis or Periapsis, in meters - you don't even need to know which"
  542.   print "   Peorap is either Periapsis or Apoapsis, in meters - you don't even need to know which"
  543.   print "   returns Ap, Pe"
  544.   print "   Ex: "
  545.   print "       local localAp, localPe = calcSomApPeFromAporpePeorap(75000,3095000)"
  546.   print "       print(\"Ap: \" .. localAp .. \" Pe: \" .. localPe)"
  547.   print "Usage: testSomTestHarness()"
  548.   print "   Just run it - if you get a message, something's broken.  Read this code for usage guidance!!!"
  549.   print "Usage: isSomOrbitStableFromApPeHsoiMsa(Ap, Pe, HillSphereOfInfluence, MinStableAltitude)"
  550.   print "   Returns 0 for stable, 1 for burn up in atmosphere, 2 for escape"
  551.   print "   sphere of influence (SOI), and 3 for burn up AND escape SOI"
  552.   print "   All values must be in the same units, including Ap Apoapsis,"
  553.   print "   Pe Periapsis, HillSphereOfInfluence the Hill sphere of"
  554.   print "   gravitational influence, and MinStableAltitude, the minimum"
  555.   print "   altitude to be out of the atmosphere and above the highest"
  556.   print "   mountain."
  557. end
  558.  
  559. function helpSomSimpleOrbitalMechanics5()
  560.   print "Usage: calcSomMolniyaApPeFromHsoiMsaMbrGmSrpMoe(HillSphereOfInfluence, MinStableAltitude, MainBodyRadius, GM, SiderealRotationalPeriod, MarginOfError)"
  561.   print "   HillSphereOfInfluence is the range in meters at which the gravity of the body is effective"
  562.   print "   MinStableAltitude is the altitude above sea level in meters at which orbiting is safe and stable"
  563.   print "     i.e. it's above both the atmosphere's effects, and the tallest mountains."
  564.   print "   MainBodyRadius is the equatorial radius of the body being orbited in meters"
  565.   print "   GM is the standard gravitational parameter in m^3/s^2"
  566.   print "   SiderealRotationalPeriod is the sidereal rotational period in seconds of the body being orbited"
  567.   print "   MarginOfError 0.001 means allow 0.1% for a \"safety zone\" above the minimum stable altitude, or below the Hill sphere of influence."
  568.   print "   Returns Ap and Pe of the best possible Molniya orbit for a given body"
  569.   print "     Returns -1, -1 if no stable Molniya orbit is possible"
  570.   print "   ex."
  571.   print "       do"
  572.   print "       local localAp, localPe = calcSomMolniyaApPeFromHsoiMsaMbrGmSrpMoe(1500000000, 180000, 6378100, 398600441800000, 86164.098903691, 1.777777777)"
  573.   print "       print(\"Ap \" .. localAp .. \" Pe \" .. localPe)"
  574.   print "       end"
  575.   print "   For oblate celestial bodies, of course, the inclination of the actual orbit must be 63.4 or 116.6 degrees, so the effect"
  576.   print "     of the oblate equitorial belt is nullified."
  577. end
  578.  
  579. globalSomOverallInit() -- initialize required variables up front
  580.  
  581. print "Usage: helpSomSimpleOrbitalMechanics1() through helpSomSimpleOrbitalMechanics5()"
  582. print "   gives detailed help on all Som functions."
  583. print "   Som functions relate to orbital mechanics as a whole, in real life and in KSP."
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement