====== std.astro.orbit — Bahnmechanik ====== ''import std.astro.orbit;'' Vis-Viva und alles, was daraus folgt: Geschwindigkeiten, Energie, Bahnelemente aus einem Zustand, Hohmann-Transfer, Fluchtbahnen und Ebenenänderungen. Alle Winkel in Radiant, alle Längen in Metern. → [[lyx_-_programmiersprache:units:astro|std.astro (Übersicht)]] · [[lyx_-_programmiersprache:units:astro:state|std.astro.state]] · [[lyx_-_programmiersprache:units:astro:insertion|std.astro.insertion]] ---- ===== 1. Zentralkörper ===== Die Werte stehen als **Funktionen**, nicht als Konstanten — so sind sie in Ausdrücken überall verwendbar. ^ Funktion ^ Wert ^ Einheit ^ | ''AMuEarth()'' | 3.986004418e14 | m³/s² | | ''AMuSun()'' | 1.32712440018e20 | m³/s² | | ''AMuMoon()'' | 4.902800118e12 | m³/s² | | ''AMuMars()'' | 4.2828372e13 | m³/s² | | ''ARadiusEarth()'' | 6378137.0 | m (Äquator) | | ''ARadiusMoon()'' | 1737400.0 | m | | ''ARadiusMars()'' | 3396200.0 | m | | ''AGravConstant()'' | 6.6743e−11 | m³/(kg·s²) | ^ Funktion ^ Rückgabe ^ Bedeutung ^ | ''AMuFromMass(m)'' | ''f64'' | ''G · m'' für einen Körper, der oben nicht steht | | ''ASurfaceGravity(mu, R)'' | ''f64'' [m/s²] | ''mu/R²'' — für die Erde 9.7983 (am Äquator, ohne Fliehkraft) | ===== 2. Geschwindigkeiten ===== ^ Funktion ^ Rückgabe ^ Bedeutung ^ NaN wenn ^ | ''AVisViva(mu, r, a)'' | ''f64'' [m/s] | ''v² = mu·(2/r − 1/a)'' — die Gleichung, aus der fast alles folgt | ''mu≤0'', ''r≤0'', ''a=0'' oder Radikand < 0 (Ort liegt gar nicht auf der Bahn) | | ''ACircularSpeed(mu, r)'' | ''f64'' | Kreisbahn, der Sonderfall ''a = r'' | ''mu≤0'' oder ''r≤0'' | | ''AEscapeSpeed(mu, r)'' | ''f64'' | Bahnenergie wird 0; immer ''√2'' mal Kreisbahntempo | dito | ===== 3. Flucht und Hyperbelbahn ===== ^ Funktion ^ Rückgabe ^ Bedeutung ^ | ''AHyperbolicExcess(mu, r, v)'' | ''f64'' [m/s] | ''v_∞'' — was vom Tempo unendlich weit draußen übrig bleibt. **NaN, wenn ''v'' unter der Fluchtgeschwindigkeit liegt** | | ''AC3(mu, r, v)'' | ''f64'' [m²/s²] | charakteristische Energie ''= v_∞² = 2E''; anders als ''v_∞'' auch für gebundene Bahnen definiert und dann **negativ** | | ''AInjectionSpeed(mu, r, vInf)'' | ''f64'' | welches Tempo am Ort ''r'' ein gewünschtes ''v_∞'' ergibt: ''√(v_∞² + 2mu/r)'' | | ''AEscapeDv(mu, r, vInf)'' | ''f64'' | Schub aus der **Kreisbahn** auf dieses ''v_∞''; ''vInf = 0'' ergibt ''(√2−1)·v_kreis'' | | ''ATurnAngle(e)'' | ''f64'' [rad] | Ablenkung einer Vorbeiflugbahn: ''sin(δ/2) = 1/e''. NaN für ''e ≤ 1'' | | ''AImpactParameter(a, e)'' | ''f64'' [m] | ''b = |a|·√(e²−1)'' — Abstand, in dem der Körper **ohne** Schwerkraft vorbeigeflogen wäre | | ''AFlybyPeriapsis(mu, vInf, b)'' | ''f64'' [m] | nächster Abstand eines Vorbeiflugs. Ob er unter dem Körperradius liegt (Einschlag), prüft der Aufrufer | > **Drei Verwechslungen, die die Unit im Quelltext ausdrücklich benennt:** Die Fluchtgeschwindigkeit ist ein **Betrag ohne Richtung**; sie gilt für **diesen** Zentralkörper (wer die Erde mit 11.2 km/s verlässt, steht danach in einer Sonnenbahn); und sie gilt für den **Stoß** — ein Antrieb mit kleinem Schub über Stunden braucht mehr. > > ''AInjectionSpeed'' ist zugleich die Formel hinter dem **Oberth-Effekt**: tief im Schwerefeld ist der Zuschlag für dasselbe ''v_∞'' viel kleiner, weil unter der Wurzel der große Term ''2mu/r'' steht. ===== 4. Energie, Halbachse, Umlaufzeit ===== ^ Funktion ^ Rückgabe ^ Bedeutung ^ | ''AEnergy(mu, r, v)'' | ''f64'' [J/kg] | ''v²/2 − mu/r''. Negativ = gebunden, 0 = Parabel, positiv = Hyperbel | | ''ASemiMajorAxis(mu, r, v)'' | ''f64'' [m] | ''−mu/(2E)''; **NaN bei ''E = 0''** — die Parabel hat keine endliche Halbachse | | ''APeriod(mu, a)'' | ''f64'' [s] | ''2π√(a³/mu)'', drittes Keplersches Gesetz; NaN für ''a ≤ 0'' | | ''ASemiMajorFromPeriod(mu, T)'' | ''f64'' [m] | Umkehrung — für sonnensynchrone und geostationäre Auslegung | ===== 5. Bahnelemente aus einem Zustand ===== ^ Funktion ^ Rückgabe ^ Bedeutung ^ | ''AEccentricityVec(mu, s)'' | ''AVec3'' | Laplace-Runge-Lenz-Vektor; zeigt zum Perizentrum | | ''AEccentricity(mu, s)'' | ''f64'' | dessen Betrag | | ''AInclination(s)'' | ''f64'' [rad] | 0…π; über π/2 heißt rückläufig. NaN bei gerader Bahn | | ''ARaan(s)'' | ''f64'' [rad] | Rektaszension des aufsteigenden Knotens, 0…2π. **NaN bei äquatorialer Bahn** — dort gibt es keinen Knoten, und 0 wäre ein gültiger Winkel | | ''ACircularThreshold()'' | ''f64'' | 1e−12 | | ''AIsCircular(mu, s)'' | ''bool'' | Exzentrizität unter der Schwelle | | ''ATrueAnomaly(mu, s)'' | ''f64'' [rad] | Winkel vom Perizentrum zum Ort, 0…2π; das Vorzeichen entscheidet die Radialgeschwindigkeit. **NaN auf der Kreisbahn** | | ''APeriapsis(a, e)'' · ''AApoapsis(a, e)'' | ''f64'' [m] | ''a(1∓e)''; NaN für ''e ≥ 1'' | > **Warum es eine Kreisbahn-Schwelle gibt.** Eine rechnerisch exakte Kreisbahn existiert nicht: der Exzentrizitätsvektor einer aus dem Kreistempo gebauten Bahn hat den Betrag ~1.2e−16 — Rundungsrauschen, aber nicht 0, und seine **Richtung ist dabei völlig beliebig**. Wer daraus eine wahre Anomalie rechnet, bekommt eine Zahl ohne Bedeutung. 1e−12 trennt sauber: Rundung liegt vier Größenordnungen darunter, die kleinste praktisch gemeinte Exzentrizität darüber. ===== 6. Hohmann-Transfer ===== ^ Funktion ^ Rückgabe ^ Bedeutung ^ | ''AHohmannDv1(mu, r1, r2)'' | ''f64'' | erster Schub (im Ausgangsorbit), **vorzeichenbehaftet** | | ''AHohmannDv2(mu, r1, r2)'' | ''f64'' | zweiter Schub (im Zielorbit), vorzeichenbehaftet | | ''AHohmannDv(mu, r1, r2)'' | ''f64'' | Summe der **Beträge** | | ''AHohmannTime(mu, r1, r2)'' | ''f64'' [s] | halbe Umlaufzeit der Transferellipse | | ''AHohmannPhaseAngle(mu, r1, r2)'' | ''f64'' [rad] | Voraushaltewinkel: wie weit das Ziel beim Start vorausstehen muss | > **Zwei Grenzen, die die Unit selbst benennt:** > > * Beim **Absenken** sind beide Einzelwerte negativ. Wer sie vorzeichenbehaftet addiert, bekommt den Treibstoffbedarf mit falschem Vorzeichen — deshalb summiert ''AHohmannDv'' die Beträge. > * Für ''r2/r1 > 11.94'' ist der **bielliptische** Transfer günstiger. Diese Unit rechnet ihn nicht; sie liefert dann einen richtigen, aber nicht den besten Wert. ===== 7. Ebenenänderung ===== ^ Funktion ^ Rückgabe ^ Bedeutung ^ | ''APlaneChangeDv(v, dInc)'' | ''f64'' | ''2v·sin(Δi/2)'' — reine Inklinationsänderung | | ''ACombinedDv(v1, v2, dInc)'' | ''f64'' | Tempo **und** Ebene in einem Schub (Kosinussatz); nie teurer als beide nacheinander | Bei 7.7 km/s kostet **ein Grad rund 135 m/s**. Deshalb wird die Ebene im Apozentrum gedreht, wo das Tempo am kleinsten ist. ===== 8. Abplattung: Knotendrift, Apsidendrift, sonnensynchrone Bahnen ===== Die Unit rechnet sonst mit einem kugelsymmetrischen Zentralkörper. Dieser Abschnitt ist die einzige Ausnahme: er berücksichtigt die **Abplattung** über den Koeffizienten ''J2'' — den Term, ohne den sich sonnensynchrone Bahnen, Molniya und Tundra nicht erklären lassen ([[https://github.com/SEOLizer/LyX-Compiler/issues/1988|#1988]]). ^ Funktion ^ Rückgabe ^ Bedeutung ^ | ''AJ2Earth()'', ''AJ2Mars()'', ''AJ2Moon()'' | ''f64'' | zweiter zonaler Koeffizient; Erde 1.08263·10⁻³ | | ''ANodalDrift(mu, j2, rBody, a, e, inc)'' | ''f64'' | Knotendrift in **rad/s**; negativ bei prograden Bahnen (Knoten wandert nach Westen) | | ''AApsidalDrift(mu, j2, rBody, a, e, inc)'' | ''f64'' | Drehung der Apsidenlinie in **rad/s** | | ''ACriticalInclination()'' | ''f64'' | 63.4349° in Radiant — dort verschwindet der Apsidendrift | | ''ACriticalInclinationRetro()'' | ''f64'' | die zweite Lösung, 116.5651° | | ''ASunSyncDrift()'' | ''f64'' | Solldrift einer sonnensynchronen Bahn: 360° je **tropischem** Jahr | | ''ASunSyncInclination(mu, j2, rBody, a, e)'' | ''f64'' | Neigung, die diese Drift erzeugt; Fehlerwert, wenn es bei dieser Höhe keine gibt | Drei Punkte, an denen die Formeln anders sind, als man sie im Kopf hat: * **In der Driftformel steht der Halbparameter ''p = a(1−e²)'', nicht die große Halbachse.** Bei einer Kreisbahn ist das dasselbe, bei Molniya mit ''e = 0.74'' unterscheidet es sich um mehr als das Doppelte. * **Sonnensynchron heißt tropisches Jahr** (365.2422 Tage), also synchron mit der **Sonne** und nicht mit den Fixsternen. Die Bahn heißt nach dem, womit sie mitläuft. * **Eine sonnensynchrone Bahn ist zwangsläufig rückläufig.** Die verlangte Drift ist positiv, also muss der Kosinus der Neigung negativ sein. Deshalb liegen alle SSO-Neigungen über 90°. Ein Zahlenbeispiel steht auf der Seite [[lyx_-_programmiersprache:units:astro:bahntypen|Bahntypen]]: 700 km Bahnhöhe verlangen 98.188°, und die ISS-Bahnebene wandert 5.0023 Grad pro Tag nach Westen. Auf demselben Term bauen drei weitere Funktionsgruppen auf: ^ Funktion ^ Rückgabe ^ Bedeutung ^ | ''ANodalPeriod(mu, j2, rBody, a, e, inc)'' | ''f64'' | Umlaufzeit von **Knoten zu Knoten** — nicht dasselbe wie ''APeriod'' | | ''ARepeatCycleFromSma(mu, j2, rBody, omegaBody, a, e, inc)'' | ''f64'' | Umläufe pro Tag einer gegebenen Bahn | | ''ASmaFromRepeatCycle(mu, j2, rBody, omegaBody, k, m, e, inc)'' | ''f64'' | Halbachse für //k// Umläufe in //m// Tagen | | ''ADecayPerRev(rho, ballisticCoeff, a)'' | ''f64'' | Höhenverlust je Umlauf durch Luftwiderstand | | ''ADecayRate(mu, rho, ballisticCoeff, a)'' | ''f64'' | derselbe Verlust als Rate | | ''AJ3Earth()'' | ''f64'' | dritter zonaler Koeffizient, −2.532·10⁻⁶ | | ''AFrozenArgPerigee()'' | ''f64'' | 90° — die einzige Lage, in der ein Perigäum stehenbleibt | | ''AFrozenEccentricity(j2, j3, rBody, a, inc)'' | ''f64'' | Exzentrizität, bei der J2 und J3 sich aufheben | | ''AIsFrozen(j2, j3, rBody, a, e, inc, argP, toleranz)'' | ''bool'' | Prüfung einer gegebenen Bahn | * **Wiederholbahnen** ([[https://github.com/SEOLizer/LyX-Compiler/issues/1993|#1993]]) schließen sich, wenn die Nodalperiode, die Erddrehung und die Knotendrift zusammenpassen. ''ASmaFromRepeatCycle'' liefert für den Landsat-Zyklus 233/16 eine Bahnhöhe von 700.3 km. * **Bahnverfall** ([[https://github.com/SEOLizer/LyX-Compiler/issues/1994|#1994]]) verbindet die Luftdichte mit dem ballistischen Koeffizienten aus [[lyx_-_programmiersprache:units:astro:entry|std.astro.entry]]. Die Dichte ist ein **Parameter**, kein Modell — sie kommt vom Aufrufer. * **Frozen Orbits** ([[https://github.com/SEOLizer/LyX-Compiler/issues/1996|#1996]]) brauchen J3 zusätzlich zu J2: J2 dreht das Perigäum, J3 zieht es zurück, und bei genau einer Exzentrizität heben sich beide auf. Für 800 km bei 98.6° sind das 0.0010274. Zeitabhängige Rechnungen stehen bewusst **nicht** hier, sondern in [[lyx_-_programmiersprache:units:astro:groundtrack|std.astro.groundtrack]]: alles in dieser Unit ist zeitlos, eine Bahn hat eine Periode, aber keinen Zeitpunkt. ===== 9. Die Parameter im Einzelnen ===== ^ Name ^ Bedeutung ^ Einheit ^ Zu beachten ^ | ''mu'' | Gravitationsparameter ''G·M'' des **Zentralkörpers** | m³/s² | ''AMuEarth()'' & Co.; für einen anderen Körper ''AMuFromMass(m)''. Muss > 0 sein | | ''r'' | Abstand vom **Mittelpunkt**, nicht Höhe über der Oberfläche | m | ''ARadiusEarth() + hoehe''. Muss > 0 sein | | ''a'' | große Halbachse; bei der Kreisbahn ''a = r'', bei der Hyperbel **negativ** | m | ''a = 0'' ist ungültig (Parabel) | | ''e'' | numerische Exzentrizität: 0 Kreis, <1 Ellipse, 1 Parabel, >1 Hyperbel | dimensionslos | ''APeriapsis''/''AApoapsis'' verlangen ''e < 1'', ''ATurnAngle''/''AImpactParameter'' verlangen ''e > 1'' | | ''v'' | Bahngeschwindigkeit am Ort ''r'' | m/s | | | ''vInf'' | hyperbolische Überschussgeschwindigkeit „im Unendlichen" | m/s | 0 ist gültig (Parabel) | | ''r1'', ''r2'' | Radien der Ausgangs- und der Zielkreisbahn beim Hohmann-Transfer | m | ''r2 < r1'' ist erlaubt: das Absenken | | ''dInc'' | Änderung der Bahnneigung | **Radiant** | Grad × ''Pi()/180.0'' | | ''T'' | Umlaufzeit bei ''ASemiMajorFromPeriod'' | s | für geostationär die **siderische** 86164 s, nicht 86400 | | ''b'' | Stoßparameter eines Vorbeiflugs | m | | | ''s'' | Zustand aus [[lyx_-_programmiersprache:units:astro:state|std.astro.state]] | — | muss ''AStateValid'' bestehen | > **Drei Verwechslungen, die Zahlen liefern statt Fehler:** > > * **Höhe statt Radius.** ''ACircularSpeed(mu, 400000.0)'' rechnet eine Bahn 400 km vom Erdmittelpunkt — tief im Inneren. Das Ergebnis (31.6 km/s) sieht aus wie eine Geschwindigkeit. > * **Grad statt Radiant.** ''APlaneChangeDv(7725.8, 30.0)'' liest 30 als Radiant, also knapp fünf volle Umdrehungen. Alle Winkel dieser Unit sind Radiant. > * **86400 statt 86164 s.** Der geostationäre Radius folgt aus dem **Sterntag**; mit dem Sonnentag kommen rund 42 240 km statt 42 164 km heraus — 76 km daneben. ===== 10. Beispiel: Kreisbahn und Transfer ===== import std.astro.state; import std.astro.orbit; import std.io; fn zeig(n: pchar, v: f64, d: int64): void { Print(n); PrintLn(FloatToStr(v, d)); } fn BI(b: bool): int64 { if (b) { return 1; } return 0; } fn main(): int64 { var mu: f64 := AMuEarth(); var leo: f64 := 6678000.0; // 300 km Hoehe var geo: f64 := 42164000.0; zeig("g0 Oberflaeche : ", ASurfaceGravity(mu, ARadiusEarth()), 4); zeig("v_kreis LEO : ", ACircularSpeed(mu, leo), 2); zeig("v_flucht LEO : ", AEscapeSpeed(mu, leo), 2); zeig("Energie LEO : ", AEnergy(mu, leo, ACircularSpeed(mu, leo)), 1); zeig("Umlaufzeit min : ", APeriod(mu, leo) / 60.0, 2); zeig("a aus T (siderisch): ", ASemiMajorFromPeriod(mu, 86164.0), 1); zeig("Hohmann dv1 : ", AHohmannDv1(mu, leo, geo), 1); zeig("Hohmann dv2 : ", AHohmannDv2(mu, leo, geo), 1); zeig("Hohmann dv gesamt : ", AHohmannDv(mu, leo, geo), 1); zeig("Hohmann t Stunden : ", AHohmannTime(mu, leo, geo) / 3600.0, 2); zeig("Ebenenaend. 1 Grad : ", APlaneChangeDv(7725.8, 0.017453292519943295), 1); zeig("v_inf bei 11 km/s : ", AHyperbolicExcess(mu, leo, 11000.0), 1); Print("v_inf zu langsam : "); PrintLn(IntToStr(BI(AIsError(AHyperbolicExcess(mu, leo, 7000.0))))); return 0; } g0 Oberflaeche : 9.7983 v_kreis LEO : 7725.84 v_flucht LEO : 10925.99 Energie LEO : -29844297.8 Umlaufzeit min : 90.52 a aus T (siderisch): 42164138.8 Hohmann dv1 : 2425.8 Hohmann dv2 : 1466.8 Hohmann dv gesamt : 3892.6 Hohmann t Stunden : 5.28 Ebenenaend. 1 Grad : 134.8 v_inf bei 11 km/s : 1273.9 v_inf zu langsam : 1 Die letzte Zeile ist der wichtigste Teil des Beispiels: 7 km/s reichen in 300 km Höhe nicht zur Flucht, und die Funktion sagt das mit NaN — statt 0 zurückzugeben, was wie eine gerade noch erreichte Flucht aussähe. ===== 11. Beispiel: Bahnelemente einer Ellipse ===== Aus einem einzigen Zustand im Perigäum lässt sich die ganze Bahn ablesen — hier eine Molniya-artige Bahn (Perigäum 600 km, Apogäum 39 900 km, 63.4 Grad Neigung): import std.astro.state; import std.astro.orbit; import std.math; import std.io; fn zeig(n: pchar, v: f64, d: int64): void { Print(n); PrintLn(FloatToStr(v, d)); } fn main(): int64 { var mu: f64 := AMuEarth(); var rad: f64 := Pi() / 180.0; var rp: f64 := ARadiusEarth() + 600000.0; var ra: f64 := ARadiusEarth() + 39900000.0; var a: f64 := (rp + ra) / 2.0; var vp: f64 := AVisViva(mu, rp, a); // Tempo im Perigaeum var inc: f64 := 63.4 * rad; // Im Perigaeum steht die Geschwindigkeit senkrecht auf dem Ort var s: AState := AMakeState(rp, 0.0, 0.0, 0.0, vp * CosF64(inc), vp * SinF64(inc)); zeig("Tempo Perigaeum : ", ASpeed(s), 1); zeig("Halbachse km : ", ASemiMajorAxis(mu, ARadius(s), ASpeed(s)) / 1000.0, 1); zeig("Exzentrizitaet : ", AEccentricity(mu, s), 5); zeig("Inklination Grad : ", AInclination(s) / rad, 2); zeig("Umlaufzeit h : ", APeriod(mu, a) / 3600.0, 3); zeig("Perigaeum km : ", APeriapsis(a, AEccentricity(mu, s)) / 1000.0, 1); zeig("Apogaeum km : ", AApoapsis(a, AEccentricity(mu, s)) / 1000.0, 1); zeig("wahre Anomalie Grad: ", ATrueAnomaly(mu, s) / rad, 2); zeig("Tempo Apogaeum : ", AVisViva(mu, ra, a), 1); return 0; } Tempo Perigaeum : 9963.6 Halbachse km : 26628.1 Exzentrizitaet : 0.73794 Inklination Grad : 63.40 Umlaufzeit h : 12.012 Perigaeum km : 6978.1 Apogaeum km : 46278.1 wahre Anomalie Grad: 0.00 Tempo Apogaeum : 1502.4 Zwei Proben, die zeigen, dass die Rechnung geschlossen ist: die zurückgerechneten Peri- und Apozentrumsabstände treffen die Eingabe wieder (6978 km = 6378 + 600, 46278 km = 6378 + 39900), und die **wahre Anomalie ist 0** — der Zustand steht ja im Perigäum. Die Umlaufzeit von 12.012 h ist der Grund für diese Bahnfamilie: zwei Umläufe je Sterntag, mit langem Verweilen über der Nordhalbkugel. Das Tempo unterscheidet sich dabei um den Faktor 6.6 zwischen Perigäum (9964 m/s) und Apogäum (1502 m/s) — deshalb sind Manöver im Apogäum billig. ---- Letzte Aktualisierung: 2026-08-31 — Parametertabelle mit den drei häufigen Verwechslungen (Höhe/Radius, Grad/Radiant, Sonnentag/Sterntag) und ein zweites Beispiel zu den Bahnelementen ergänzt; beide Beispiele mit ''lyxc 1.1.15B'' gebaut und ausgeführt. Zuvor 2026-08-31 — Seite neu angelegt aus ''std/astro/orbit.lyx'' (PR #1890).