====== std.astro.groundtrack — Bodenspur ======
Diese Unit schließt ein einzelnes Glied: die Drehung vom Inertialsystem auf die drehende Erde. Vorne liegt [[lyx_-_programmiersprache:units:astro:state|std.astro.state]] mit dem Ortsvektor im **ECI**, hinten [[lyx_-_programmiersprache:units:geodesy:frames|std.geodesy.frames]] mit ''EcefToGeod''. Dazwischen fehlte die Drehung um den **Greenwich-Stundenwinkel** — und die ist der ganze Unterschied zwischen beiden Rahmen ([[https://github.com/SEOLizer/LyX-Compiler/issues/1995|#1995]]).
→ [[lyx_-_programmiersprache:units:astro|std.astro (Übersicht)]] · [[lyx_-_programmiersprache:units:astro:orbit|std.astro.orbit]] · [[lyx_-_programmiersprache:units:astro:state|std.astro.state]] · [[lyx_-_programmiersprache:units:geodesy:frames|std.geodesy.frames]] · [[lyx_-_programmiersprache:units:astro:bahntypen|Bahntypen]]
----
===== 1. Warum eine eigene Unit =====
Der Grund ist die **Zeitachse**. Alles in ''std.astro.orbit'' rechnet zeitlos: eine Bahn hat eine Umlaufzeit, aber keinen Zeitpunkt. Sobald ein Datum ins Spiel kommt — und ohne Datum gibt es keinen Stundenwinkel —, ist das eine andere Art von Rechnung.
Die Abhängigkeit zeigt außerdem bewusst **nicht** auf ''std.geodesy''. Die Unit liefert den Unterpunkt geozentrisch, also auf der Kugel, und den ECEF-Vektor. Wer die geodätische Breite auf dem Ellipsoid braucht, verkettet selbst mit ''EcefToGeod''. Der Unterschied ist nicht klein — bis zu 0.19 Grad in mittleren Breiten —, aber die Wahl gehört dem Aufrufer.
===== 2. Die Funktionen =====
^ Funktion ^ Rückgabe ^ Bedeutung ^
| ''AJ2000()'' | ''f64'' | julianisches Datum der Epoche J2000.0 = 2 451 545.0 |
| ''AJulianCenturies(jd)'' | ''f64'' | julianische Jahrhunderte seit J2000.0 |
| ''AGmst(jd)'' | ''f64'' | Greenwich-Sternzeit als Winkel in **Radiant** |
| ''AEciToEcef(v, gmst)'' | ''AVec3'' | Drehung ins erdfeste System |
| ''AEcefToEci(v, gmst)'' | ''AVec3'' | die Gegenrichtung |
| ''ASubPointLatitude(v)'' | ''f64'' | geozentrische Breite des Unterpunkts (aus dem ECI-Vektor) |
| ''ASubPointLongitude(v, gmst)'' | ''f64'' | Länge des Unterpunkts |
| ''ASubPointAltitude(v, rBody)'' | ''f64'' | Höhe über der Kugel |
Die Breite braucht **keinen** Stundenwinkel: die Drehung geht um die z-Achse und lässt die Breite unberührt. Nur die Länge hängt an der Zeit.
===== 3. Die Bodenspur eines Umlaufs =====
Ein Satellit auf einer 400-km-Kreisbahn, Startpunkt auf der x-Achse des ECI, Epoche JD 2 460 000.5:
^ Zeit ^ GMST ^ Länge des Unterpunkts ^
| 0.0 min | 154.602° | −154.602° |
| 23.1 min | 160.403° | −70.403° |
| 46.3 min | 166.204° | 13.796° |
| 69.4 min | 172.005° | 97.995° |
| 92.6 min | 177.805° | −177.805° |
Die letzte Zeile ist der ganze Punkt: nach einem vollen Umlauf steht der Satellit wieder über demselben //Inertialpunkt//, aber die Länge ist von −154.602° auf −177.805° gewandert. **23.2 Grad Westdrift je Umlauf** — die Erde hat sich in den 92.56 Minuten weitergedreht. Genau diese Drift muss eine [[lyx_-_programmiersprache:units:astro:bahntypen|Wiederholbahn]] so treffen, dass sie sich nach ganzen Tagen schließt.
Zwei Proben stehen daneben:
* Ein Vektor über dem Nordpol liefert **90.0°** Breite, unabhängig vom Stundenwinkel.
* ''AEcefToEci(AEciToEcef(v, gmst), gmst)'' gibt denselben Vektor zurück — 6 778 137.0 m, auf den Meter.
===== 4. Das Programm =====
unit main;
import std.astro.groundtrack;
import std.astro.orbit;
import std.astro.state;
import std.math;
import std.io;
import std.string;
fn f(v: f64, d: int64): pchar { return FloatToStr(v, d); }
fn G(r: f64): f64 { return r * 180.0 / Pi(); }
fn main(): int64 {
// ISS-artige Bahn, 400 km, der Einfachheit halber in der Aequatorebene
var r: f64 := ARadiusEarth() + 400000.0;
var T: f64 := APeriod(AMuEarth(), r);
var jd0: f64 := 2460000.5;
PrintLn(StrConcat("Umlaufzeit: ", StrConcat(f(T / 60.0, 2), " min")));
PrintLn("");
PrintLn("Minute | GMST Grad | Laenge Grad");
var i: int64 := 0;
while i <= 4 {
var dt: f64 := (i as f64) * T / 4.0;
var jd: f64 := jd0 + dt / 86400.0;
var gmst: f64 := AGmst(jd);
// Position auf der Kreisbahn nach dt Sekunden
var w: f64 := SqrtF64(AMuEarth() / (r * r * r));
var eci: AVec3 := AVec(r * CosF64(w * dt), r * SinF64(w * dt), 0.0);
Print(f(dt / 60.0, 1));
Print(" | "); Print(f(G(gmst), 3));
Print(" | "); PrintLn(f(G(ASubPointLongitude(eci, gmst)), 3));
i := i + 1;
}
PrintLn("");
PrintLn(StrConcat("J2000 als julianisches Datum: ", f(AJ2000(), 1)));
PrintLn(StrConcat("Jahrhunderte seit J2000: ", f(AJulianCenturies(jd0), 6)));
var eci2: AVec3 := AVec(0.0, 0.0, r);
PrintLn(StrConcat("Ueber dem Nordpol, Breite: ", StrConcat(f(G(ASubPointLatitude(eci2)), 1), " Grad")));
PrintLn(StrConcat("Hin und zurueck (ECI->ECEF->ECI) x: ", f(AEcefToEci(AEciToEcef(eci2, AGmst(jd0)), AGmst(jd0)).z, 1)));
return 0;
}
Ausgabe:
Umlaufzeit: 92.56 min
Minute | GMST Grad | Laenge Grad
0.0 | 154.602 | -154.602
23.1 | 160.403 | -70.403
46.3 | 166.204 | 13.796
69.4 | 172.005 | 97.995
92.6 | 177.805 | -177.805
J2000 als julianisches Datum: 2451545.0
Jahrhunderte seit J2000: 0.231499
Ueber dem Nordpol, Breite: 90.0 Grad
Hin und zurueck (ECI->ECEF->ECI) x: 6778137.0
> **Die Zeit ist hier die Fehlerquelle, nicht die Geometrie.** ''AGmst'' erwartet ein julianisches Datum, und ein Tag Abweichung dreht die Länge um knapp ein Grad daneben — der Sterntag ist vier Minuten kürzer als der Sonnentag. Wer eine Bodenspur über Wochen rechnet, muss die Epoche sauber führen.