Grundlagen der Raketendynamik & Himmelsmechanik

albertus

Registriertes Mitglied

Teil 8: Augen und Muskeln im All – Sternsensoren und Reaktionsräder​

Nachdem wir uns durch die Welt der Quaternionen und Differentialgleichungen gekämpft haben, stellt sich die Frage: Wer liefert eigentlich die Zahlen für diese Gleichungen, und wer setzt das Ergebnis um? Um das zu verstehen, müssen wir uns die „Sinnesorgane“ und „Muskeln“ eines Satelliten ansehen.

1. Der Sternsensor (Star Tracker): Das Auge der Orientierung​

Ein Satellit hat keinen Kompass und kein „Unten“. Er nutzt die stabilste Referenz des Universums: die Fixsterne.
  • Funktionsweise: Der Sensor ist eine High-Tech-Kamera mit integriertem Sternenkatalog. Er erkennt Muster in Millisekunden und berechnet daraus die exakte Lage im Raum.
  • Der Realitäts-Check: Er liefert den „Reset“, der unsere mathematische Integration (aus Teil 7) alle paar Sekunden wieder kalibriert und Rundungsfehler der Software einfängt.
  • Hardware zum Anfassen: Hier findet man die Datenblätter eines der weltweit fortschrittlichsten Sensoren aus Jena: Jena-Optronik ASTRO APS

2. Das Reaktionsrad (Reaction Wheel): Der Muskel ohne Treibstoff​

Wie dreht man einen Satelliten im Vakuum? Man nutzt die Drehimpulserhaltung. Beschleunige ich ein internes Rad in die eine Richtung, dreht sich der Satellit als Ausgleich in die andere.
  • Der Vorteil: Das funktioniert rein elektrisch mit Sonnenstrom – kein Gramm kostbarer Treibstoff wird für die tägliche Ausrichtung verbraucht.
  • Direkter Einblick: Bei den Berliner Kollegen von Astrofein sieht man sehr schön die verschiedenen Leistungsklassen, vom kleinen Würfel bis zum schweren Rad: Astrofein Reaction Wheels

3. Das Zusammenspiel am Beispiel James Webb (JWST)​

Das JWST nutzt einen extrem präzisen Fine Guidance Sensor (FGS). Dieser sorgt dafür, dass das Teleskop so stabil bleibt, dass man damit eine Kugel aus 1,5 km Entfernung treffen würde. Ohne diesen Sensor, der die Reaktionsräder füttert, gäbe es keine scharfen Bilder aus dem frühen Universum.

Mein Fazit:

Ohne Sternsensoren wären wir „blind“ und unsere Mathematik würde im Rauschen der Rechenfehler versinken. Ohne Reaktionsräder wären wir „gelähmt“. Erst dieses Zusammenspiel macht aus trockenen Formeln ein funktionierendes Raumfahrzeug, das millimetergenau über Milliarden Kilometer hinweg ausgerichtet werden kann.
 

albertus

Registriertes Mitglied

Teil 9: Das Gehirn im All – Wie der PD-Regler die Ruhe bewahrt​

Wir haben nun die Augen (Sensoren) und die Muskeln (Reaktionsräder). Aber wie steuert man das Ganze, ohne dass der Satellit wie ein Pendel hin- und herschwingt? Hier kommt das „Gehirn“ ins Spiel: der PD-Regler.

Der Vergleich: Der Tempomat im Auto​

Stellt euch einen modernen Tempomaten vor. Wenn ihr 120 km/h einstellt, aber nur 100 km/h fahrt, gibt das System Gas.
  • Ein schlechter Regler würde Vollgas geben, bis 120 erreicht sind, dann erschrocken feststellen, dass er bei 125 ist, und abrupt vom Gas gehen. Das Auto würde permanent ruckeln.
  • Ein guter Regler (PD-Regler) gibt sanft Gas und nimmt es bereits bei 118 km/h langsam zurück, um punktgenau bei 120 „einzurasten“.

Die Mathematik dahinter: P und D​

Im Bordcomputer berechnet ein Algorithmus permanent das benötigte Drehmoment für die Reaktionsräder:
  1. Der P-Anteil (Proportional): Er schaut auf die Differenz (den Fehler) zwischen Soll- und Ist-Lage. Je größer der Fehler, desto mehr „Power“ gibt er. Er ist der Antreiber.
  2. Der D-Anteil (Derivativ): Er ist der eigentliche Star. Er schaut nicht auf den Fehler selbst, sondern darauf, wie schnell sich der Fehler ändert. Er wirkt wie ein unsichtbarer Stoßdämpfer im Vakuum. Ohne ihn würde der Satellit aufgrund seiner Trägheit immer über das Ziel hinausschießen.
Mathematisch gesehen legen wir hier die Dämpfung des Systems fest. Die Wahl der Regler-Parameter entscheidet über die Lage der Eigenwerte. Ein perfekt eingestellter Regler führt zum aperiodischen Grenzfall – der schnellstmöglichen Ausrichtung ohne jegliches Überschwingen.

Der PD-Regler in Aktion (Python-Simulation)​

Um das greifbar zu machen, hier ein kleines Skript. Man kann darin wunderbar sehen, wie der „Dämpfer“ (Kd) die Schwingungen einfängt. Setzt man Kd auf 0, pendelt der Satellit ewig weiter.

Python:
import numpy as np
import matplotlib.pyplot as plt

# Parameter: J=Trägheit, Kp=Antrieb, Kd=Dämpfer
J, Kp, Kd = 2.0, 10.0, 8.0
target_angle, current_angle, velocity = 90.0, 0.0, 0.0
dt = 0.01
time = np.arange(0, 5, dt)
angles = []

for t in time:
    error = target_angle - current_angle
    # Das Herzstück: Das Reglergesetz
    torque = Kp * error - Kd * velocity
    acceleration = torque / J
    velocity += acceleration * dt
    current_angle += velocity * dt
    angles.append(current_angle)

plt.plot(time, angles)
plt.axhline(y=target_angle, color='r', linestyle='--')
plt.title(f"Satelliten-Lageregelung (PD-Regler)")
plt.xlabel("Zeit [s]"); plt.ylabel("Winkel [Grad]")
plt.grid(True); plt.show()

Warum das JWST diesen „Dämpfer“ liebt​

Wenn das James-Webb-Teleskop von einem Stern zum nächsten schwenkt, sorgt der D-Anteil dafür, dass die kinetische Energie der Drehung exakt im richtigen Moment „abgefangen“ wird. Nur so kommen die massiven Spiegel innerhalb von Millisekunden zur Ruhe und liefern sofort scharfe Bilder, statt im All herumzuzittern.
 
Zuletzt bearbeitet:

albertus

Registriertes Mitglied
Teil 10: Wenn die Muskeln „sauer“ werden – Das Problem der Sättigung

Wir haben nun gesehen, wie der PD-Regler die Reaktionsräder nutzt, um den Satelliten präzise auszurichten. Doch in der Realität gibt es ein Limit: Man kann ein Rad nicht unendlich schnell drehen lassen.

1. Das Problem: Drehimpuls-Stau​

Auf einen Satelliten wirken permanent winzige Störmomente (z. B. durch den Druck des Sonnenlichts).
  • Der PD-Regler gleicht das aus, indem er die Reaktionsräder immer ein Stückchen schneller drehen lässt.
  • Irgendwann erreichen die Räder ihre maximale Drehzahl (Sättigung).
  • In diesem Moment kann der Satellit keine weiteren Störungen mehr kompensieren – er würde anfangen zu trudeln, da der „interne Speicher“ für den Drehimpuls voll ist.

2. Die Lösung: Der „magnetische Haken“ (Desaturierung)​

Wie wird man diesen aufgestauten Drehimpuls wieder los? Man muss ihn an etwas außerhalb des Satelliten abgeben. Da wir im Vakuum nichts haben, an dem wir uns abstoßen können, nutzen wir ein unsichtbares Gitter: Das Erdmagnetfeld.

Hier kommen die Magnetorquer ins Spiel. Man kann sie sich wie folgt vorstellen:
  • Der Kompass-Effekt: Ein Magnetorquer ist im Kern ein Elektromagnet (eine Spule). Fließt Strom, wird er zur Kompassnadel, die sich an den Feldlinien der Erde ausrichten will.
  • Das Gummiband-Modell: Stell dir das Erdmagnetfeld wie ein Netz aus unsichtbaren, stabilen Gummibändern vor, die die Erde umspannen. Wenn der Satellit seine Magnetorquer einschaltet, ist das so, als würde er einen Haken in diese Bänder einhängen.

3. Das Manöver: Bremsen ohne Wackeln​

Jetzt kommt die Präzisionsarbeit des Bordcomputers. Er leitet ein gezieltes Manöver ein, um die Räder zu entlasten:
  1. Der Computer aktiviert den Magnetorquer, der den Satelliten am magnetischen Gitter der Erde „festkrallt“.
  2. Gleichzeitig gibt er dem Motor des Reaktionsrades den Befehl, langsamer zu werden.
  3. Der Clou: Der Magnetorquer hält so stark dagegen, dass der Satellit während des Abbremsens seine Position nicht verändert.
Der überschüssige Schwung wird also direkt in das Magnetfeld der Erde übertragen. Ohne einen Tropfen Treibstoff zu verbrauchen, ist der „Speicher“ der Räder wieder leer und bereit für neue Aufgaben.

Ich finde, eine geniale Lösung.
 

albertus

Registriertes Mitglied

Teil 11: Energie & Entfaltung

Nachdem wir die mathematische Eleganz der Lageregelung (SU(2)) und die Effizienz der Algorithmen (RK4 vs. RKMK) beleuchtet haben, müssen wir uns die Frage stellen: Woher kommt eigentlich der Strom für diese Rechenleistung?

Ein moderner Kommunikationssatellit der 6-Tonnen-Klasse ist im Grunde ein fliegendes Kraftwerk. Das Video der Entfaltung der Solarzellen zeigt eindrucksvoll den Moment, in dem aus einem kompakten „Paket“ ein Objekt mit einer Spannweite von oft über 30 oder 40 Metern wird.

1. Die Energiebilanz (Warum wir CPU-Zyklen sparen)​

Jedes Watt, das die CPU für komplexe Lie-Integratoren verbraucht, fehlt an anderer Stelle:
  • Nutzlast: Der Strom soll primär die Transponder und Instrumente versorgen, nicht die Bordmathematik.
  • Batteriepuffer: In den Schattenphasen (Eklipse) muss die Energie aus Batterien kommen. Je sparsamer der Algorithmus, desto kleiner und leichter können die Batterien sein.

2. Die Dynamik der Entfaltung (Ein Albtraum für die Lageregelung)​

Wenn ein 6-Tonner seine Solarflügel ausklappt, ändert sich sein Trägheitstensor massiv:
  • Die Massenverteilung wandert nach außen.
  • Es entstehen mechanische Schwingungen in den flexiblen Strukturen.
    Hier zeigt sich, warum eine hohe Abtastrate (wie wir sie im Benchmark besprochen haben) so wichtig ist: Der Regler muss diese Schwingungen in Echtzeit erkennen und dämpfen, damit der Satellit nicht ins Trudeln gerät.

3. Thermische Last​

Wie bereits erwähnt: Jedes Watt Abwärme der Elektronik muss über Radiatoren abgestrahlt werden. Große Solarzellen fangen zudem den Sonnenstrahlungsdruck ein – sie wirken wie kleine Segel, die ein störendes Drehmoment erzeugen, das wir ständig korrigieren müssen.

Fazit: Die beeindruckenden Solarpanels sind das Herzstück der Mission, aber sie machen das Leben für den Lageregler nicht einfacher. Die „schöne Mathematik“ muss hier der harten Realität von Mechanik und Energiehaushalt weichen.
 

albertus

Registriertes Mitglied

Teil 12: Die hohe Schule der Himmelsmechanik – Das „Rendezvous-Paradoxon“ selbst nachrechnen!​

In Filmen sieht man oft, wie ein Raumschiff einfach „Gas gibt“, um ein Ziel einzuholen. In der Realität führt das dazu, dass man sein Ziel verliert. Wir nutzen die Vis-Viva-Gleichung, um das zu beweisen. Sie ist das wichtigste Werkzeug der Bahndynamik:

svg.image

  • svg.image
    (Erd-Gravitationsparameter):
    svg.image
  • r (Radius): 6.371 km (Erdradius) + Höhe
  • a (Große Halbachse): Bei einer Kreisbahn ist a = r.

Situation 1: Wer tiefer fliegt, überholt​

Die ISS kreist in 400 km Höhe. Ein Versorger ist 100 km hinter ihr auf einer Warteposition in 380 km.
  1. Rechnung ISS (400 km):
    svg.image

    svg.image
  2. Rechnung Versorger (380 km):
    svg.image

    svg.image
Das Ergebnis: Obwohl der Versorger „tiefer“ ist, ist er pro Sekunde um 11,4 Meter schneller als die ISS. Pro Stunde holt er also über 41 Kilometer auf! Wer überholen will, muss also „unten“ bleiben.


Situation 2: Das Paradoxon – Warum „Gas geben“ schiefgeht​

Stellen wir uns vor, der Pilot auf 380 km Höhe will die Lücke schneller schließen und gibt „Hollywood-Gas“. Er beschleunigt von 7,6800 km/s auf 7,7000 km/s. Was passiert nun wirklich? Rechnen wir es nach:

Schritt A: Die neue Bahnform berechnen

Durch die höhere Geschwindigkeit wird aus dem Kreis eine Ellipse. Wir berechnen die neue große Halbachse ($a$):

svg.image

  1. svg.image
    59,29
  2. svg.image
  3. svg.image
  4. svg.image
  5. svg.image
Schritt B: Den höchsten Punkt (Apogäum) finden

Die Halbachse a ist der Durchschnitt aus Startpunkt (r) und höchstem Punkt (
svg.image
):

svg.image


Höhe über Grund:
svg.image


Das Ergebnis: Das Schiff schießt weit über die ISS (400 km) hinaus! Und schlimmer: Am höchsten Punkt ist es laut Vis-Viva nur noch 7,635 km/s schnell – also deutlich langsamer als die ISS (
svg.image
). Die ISS zieht unten einfach an ihm vorbei.
 

albertus

Registriertes Mitglied

Teil 12: Fortsetzung von: Die hohe Schule der Himmelsmechanik​

Situation 3: Die Lösung – Der präzise „Hohmann-Hüpfer“​

Ein Profi will die ISS exakt in 400 km Höhe treffen. Er berechnet eine Ellipse, die bei 380 km (
svg.image
) startet und bei 400 km (
svg.image
) endet.

Schritt A: Die benötigte Halbachse
svg.image
berechnen


svg.image


Schritt B: Die Startgeschwindigkeit für diesen „Hüpfer“ berechnen

Wir setzen r = 6.751 und a = 6.761 in die Vis-Viva-Gleichung ein:
  1. svg.image
  2. svg.image
  3. Differenz = 0,000148345
  4. svg.image
  5. svg.image

Schritt C: Der notwendige „Schubs“ (
svg.image
)


Da er bereits mit
svg.image
fliegt, muss er beschleunigen um:

svg.image
(nur 9,6 m/s!)

Schritt D: Die Ankunft an der ISS

Oben angekommen (bei r = 6.771), ist er durch das Klettern langsamer geworden:

svg.image


Da die ISS dort aber mit 7,6686 km/s fliegt, muss er oben noch einmal um 9,6 m/s beschleunigen, um nicht wieder nach unten zu fallen.
 
Zuletzt bearbeitet:

albertus

Registriertes Mitglied

Teil 12: Fortsetzung von: Die hohe Schule der Himmelsmechanik​

Situation 4: Der Rückweg – Warum Bremsen die einzige Option ist​

Viele glauben, man müsste die Nase Richtung Erde drehen und Gas geben. Rechnen wir nach, was passiert, wenn man stattdessen einfach nur bremst.

Schritt A: Der Bremsimpuls (Retro-Burn)

Die ISS fliegt mit 7,6686 km/s. Wir bremsen das Heimkehrschiff um ca. 140 m/s (
svg.image
) ab.

Neue Geschwindigkeit:
svg.image


Schritt B: Die neue Bahn berechnen

Wir starten bei
svg.image
(ISS_Höhe) mit
svg.image
.
  1. svg.image
  2. svg.image
  3. svg.image
  4. svg.image
  5. svg.image
Schritt C: Den tiefsten Punkt der Landebahn (Perigäum) finden

svg.image


Schritt D: Die Höhe über der Erdoberfläche prüfen

Höhe
svg.image


Das Ergebnis: Der tiefste Punkt der Bahn liegt nun unter der Erdoberfläche. Das bedeutet, das Raumschiff schneidet die Atmosphäre in einem extrem flachen Winkel. Bei etwa 80–100 km Höhe wird die Luftreibung so stark, dass die Bewegungsenergie in Hitze umgewandelt wird. Ohne diesen Bremsvorgang würde man Milliarden Jahre um die Erde kreisen, egal wie man das Schiff dreht.


Fazit: Raumfahrt ist die Kunst des Rechnens. Ein Fehler von wenigen Metern pro Sekunde entscheidet darüber, ob man an der ISS andockt, an ihr vorbeischießt oder beim Wiedereintritt verglüht.
 

albertus

Registriertes Mitglied
Schlusswort zu Teil 12: Von der Theorie zur Realität

Nachdem wir nun gemeinsam mit der Vis-Viva-Gleichung das 'Skelett' der Bahnbewegungen berechnet haben, möchte ich zum Abschluss noch ein wenig die Perspektive gerade rücken.

Die Beispiele oben basieren auf dem sogenannten Zwei-Körper-Problem (Raumschiff und Erde). Das ist ideal, um die Physik zu verstehen, aber in der realen Mission Control ist die Welt noch viel komplexer. Warum Raumfahrtingenieure ein jahrelanges, anspruchsvolles Studium absolvieren, liegt an den Details, die wir hier vereinfacht haben:
  1. Das N-Körper-Problem: In der Realität ziehen nicht nur die Erde, sondern auch der Mond, die Sonne und sogar die Planeten an unserem Raumschiff. Diese Einflüsse müssen ständig mitberechnet werden, was mathematisch zu Systemen führt, die man nicht mehr einfach 'zu Fuß' lösen kann.
  2. Die Geopotential-Anomalien: Die Erde ist keine perfekte Kugel. Sie ist an den Polen abgeplattet und die Massenverteilung im Inneren ist unregelmäßig. Das sorgt für ein 'unebenes' Schwerefeld, das die Bahn ständig leicht verbiegt.
  3. Atmosphärischer Restwiderstand: Selbst in 400 km Höhe ist kein perfektes Vakuum. Die ISS verliert ständig an Höhe und muss regelmäßig angehoben werden (Reboost).
  4. Relativistische Effekte: Bei hochpräzisen Navigationssystemen (wie GPS) müssen wir sogar die Zeitdilatation berücksichtigen, da die Uhren im Orbit minimal anders gehen als auf der Erde.
Wenn wir also im Museum in Morgenröthe-Rautenkranz vor den Kapseln stehen, sollten wir bedenken: Jedes dieser Manöver wurde von Ingenieuren berechnet, die all diese Störgrößen im Griff haben mussten. Unsere Vis-Viva-Gleichung war die Landkarte, aber das Studium und die Erfahrung der Ingenieure sind der Kompass, der uns durch dieses hochkomplexe Feld führt.

Vielen Dank fürs Mitrechnen und das rege Interesse an diesem Thema, das mir persönlich sehr am Herzen liegt!
 
Zuletzt bearbeitet:

albertus

Registriertes Mitglied
Die Himmelsmechanik live erleben – Mein „SpaceX-Simulator“ für Teil 12

Hallo zusammen, nachdem wir uns im letzten Teil theoretisch durch die Vis-Viva-Gleichung und das Paradoxon des „Gasgebens“ im Orbit gerechnet haben, möchte ich euch noch etwas Besonderes präsentieren. Ich finde, dass man Physik am besten versteht, wenn man sie in Bewegung sieht. Daher habe ich ein kleines Python-Skript geschrieben.

Dieses Programm simuliert den Hohmann-Transfer eines Versorgers von einer 350-km-Warteposition hinauf zur ISS auf 400 km.

Was ihr in der Simulation seht:
  • Die Erde: Blau im Zentrum (didaktisch verkleinert, damit die Bahnen Platz haben).
  • Die ISS (Rot): Sie kreist stabil auf ihrem äußeren Ziel-Orbit.
  • Der Versorger (Blau): Er zündet zu Beginn sein Triebwerk und begibt sich auf die gelb markierte Transfer-Ellipse.
  • Live-Telemetrie: Achtet auf die Geschwindigkeitsanzeigen (v in km/s) direkt neben den Flugkörpern.
Hier ist der Code für euren eigenen „Kontrollraum“ (einfach in PyCharm oder eine andere Python-Umgebung kopieren):
Python:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

# --- Physikalische Parameter (Reale Werte) ---
MU = 398600.0
R_ERDE_REAL = 6371.0
H_ISS_REAL = 400.0
H_VERS_START_REAL = 350.0

R_ISS_REAL = R_ERDE_REAL + H_ISS_REAL
R_VERS_REAL = R_ERDE_REAL + H_VERS_START_REAL
A_TRANS_REAL = (R_ISS_REAL + R_VERS_REAL) / 2.0
v_iss_const = np.sqrt(MU / R_ISS_REAL)

# --- Didaktische Parameter für die Grafik ---
R_ERDE_GRAPH = 1.0
R_VERS_GRAPH = 2.1
R_ISS_GRAPH = 3.3
LIMIT = 4.5

# --- Zeit-Parameter ---
FPS = 30
DAUER_SEKUNDEN = 60
ANZAHL_FRAMES = FPS * DAUER_SEKUNDEN
t = np.linspace(0, 1, ANZAHL_FRAMES)

# --- Bahndaten ---
EXZ_GRAPH = (R_ISS_GRAPH - R_VERS_GRAPH) / (R_ISS_GRAPH + R_VERS_GRAPH)
A_TRANS_GRAPH = (R_ISS_GRAPH + R_VERS_GRAPH) / 2.0
phi_start = 1.25 * np.pi

nu = np.pi * t
r_transfer = A_TRANS_GRAPH * (1 - EXZ_GRAPH ** 2) / (1 + EXZ_GRAPH * np.cos(nu))

# Reale v-Werte berechnen
r_real_t = A_TRANS_REAL * (1 - ((R_ISS_REAL - R_VERS_REAL) / (R_ISS_REAL + R_VERS_REAL)) ** 2) / (
            1 + ((R_ISS_REAL - R_VERS_REAL) / (R_ISS_REAL + R_VERS_REAL)) * np.cos(nu))
v_vers_t = np.sqrt(MU * (2 / r_real_t - 1 / A_TRANS_REAL))

x_vers = r_transfer * np.cos(nu + phi_start)
y_vers = r_transfer * np.sin(nu + phi_start)

phi_iss = (phi_start + np.pi) - (0.8 * np.pi * (1 - t))
x_iss = R_ISS_GRAPH * np.cos(phi_iss)
y_iss = R_ISS_GRAPH * np.sin(phi_iss)

# --- Grafik-Setup ---
fig, ax = plt.subplots(figsize=(10, 10))
ax.set_facecolor('#000000')

# Erde
ax.add_artist(plt.Circle((0, 0), R_ERDE_GRAPH, color='#1a4e8a'))

# Orbits
phi_full = np.linspace(0, 2 * np.pi, 500)
ax.plot(R_VERS_GRAPH * np.cos(phi_full), R_VERS_GRAPH * np.sin(phi_full), color='#444444', linestyle=':', alpha=0.4)
ax.plot(R_ISS_GRAPH * np.cos(phi_full), R_ISS_GRAPH * np.sin(phi_full), color='#888888', linestyle='--', alpha=0.3)

# Flugobjekte - Versorger jetzt in DodgerBlue
iss_dot, = ax.plot([], [], 'ro', markersize=11, markeredgecolor='white', label='ISS')
vers_dot, = ax.plot([], [], color='dodgerblue', marker='o', markersize=9, markeredgecolor='white', label='Versorger')
spur, = ax.plot([], [], color='dodgerblue', lw=2, alpha=0.6)

# Telemetrie mit optimierten Farben
v_text_iss = ax.text(0, 0, '', color='red', fontsize=11, fontweight='bold')
v_text_vers = ax.text(0, 0, '', color='dodgerblue', fontsize=11, fontweight='bold')

ax.set_xlim(-LIMIT, LIMIT)
ax.set_ylim(-LIMIT, LIMIT)
ax.set_aspect('equal')
ax.axis('off')

plt.title("Hohmann-Transfer mit Telemetrie (v in km/s)", color='white', fontsize=16, pad=20)
ax.legend(loc='lower center', frameon=True, facecolor='#111', labelcolor='white', ncol=2)


def update(frame):
    iss_point_x, iss_point_y = x_iss[frame], y_iss[frame]
    vers_point_x, vers_point_y = x_vers[frame], y_vers[frame]

    iss_dot.set_data([iss_point_x], [iss_point_y])
    vers_dot.set_data([vers_point_x], [vers_point_y])
    spur.set_data(x_vers[:frame], y_vers[:frame])

    # Texte leicht versetzt positionieren
    v_text_iss.set_position((iss_point_x + 0.2, iss_point_y + 0.2))
    v_text_iss.set_text(f"v: {v_iss_const:.4f}")

    v_text_vers.set_position((vers_point_x + 0.2, vers_point_y - 0.4))
    v_text_vers.set_text(f"v: {v_vers_t[frame]:.4f}")

    return iss_dot, vers_dot, spur, v_text_iss, v_text_vers


ani = FuncAnimation(fig, update, frames=ANZAHL_FRAMES, interval=33, blit=True)
plt.show()

Die Auflösung des Rätsels: Warum wird der Versorger langsamer?

Wenn ihr die Simulation startet (sie läuft ganz bewusst majestätisch langsam über 60 Sekunden), werdet ihr ein faszinierendes Detail bemerken:
  1. Der Startschuss: Der blaue Versorger startet unten mit einer Geschwindigkeit von ca. 7,690 km/s. Er ist damit deutlich schneller als die ISS (7,673 km/s), was er auch sein muss, um gegen die Schwerkraft „aufzusteigen“.
  2. Der Aufstieg: Während der Versorger nach oben wandert, tauscht er kinetische Energie (Geschwindigkeit) gegen potenzielle Energie (Höhe) ein. Die Telemetrie zeigt live, wie die Zahl kleiner wird.
  3. Das scheinbare Paradoxon: Am Zielpunkt angekommen, ist der Versorger mit ca. 7,666 km/s plötzlich langsamer als die ISS.
Das Ingenieurs-Fazit:

Genau hier endet die Animation. Man sieht: Die Bahnen berühren sich zwar, aber der Versorger hat „keine Puste mehr“. Um wirklich dauerhaft auf dem ISS-Orbit zu bleiben und nicht wieder nach unten zu fallen, müsste der Pilot in genau diesem Moment ein zweites Mal Gas geben, um die Differenz von etwa 7 m/s auszugleichen.

Erst durch diesen zweiten Schubs wird die Ellipse zum Kreis und das Rendezvous ist perfekt.

Ich hoffe, diese kleine Visualisierung hilft dabei, die „Tyrannei der Raketengleichung“ und die Eleganz der Himmelsmechanik besser zu verstehen. Viel Spaß beim Experimentieren mit den Werten!
 

albertus

Registriertes Mitglied

Kapitel 13: Der Tanz des starren Körpers – Trägheit und das Dzhanibekov-Rätsel​

In der Bahnmechanik (Kapitel 12) haben wir den Satelliten meist als „Massenpunkt“ betrachtet. Jetzt gehen wir einen Schritt weiter: Wir betrachten ihn als ausgedehnten, starren Körper. Im Weltraum passiert dabei etwas Paradoxes: Ein rotierender Körper kann seinen Drehimpuls beibehalten, aber seine Drehachse im Inneren völlig verändern. Das führt zu einem bizarren „Trudeln“.

1. Die Trägheitsmomente (Der Widerstand gegen die Drehung)​

Jeder Körper hat drei Hauptachsen, um die er rotieren kann. Stell dir ein Buch oder ein Smartphone vor:
  • Achse 1 (Längsachse): Die Drehung um die längste Seite (geringster Widerstand/Trägheitsmoment
    svg.image
    ).
  • Achse 3 (Hochachse): Die Drehung wie ein flach liegender Teller (höchster Widerstand
    svg.image
    ).
  • Achse 2 (Mittelachse): Die Drehung um die kurze Kante (mittlerer Widerstand
    svg.image
    ).

2. Der „Motor“ des Trudelns: Die Euler-Gleichungen​

Im freien Fall des Weltraums wirken keine äußeren Drehmomente. Dennoch „koppeln“ die Drehgeschwindigkeiten
svg.image
um die drei Achsen aneinander. Das Gesetz dahinter sind die Euler-Gleichungen:

svg.image

svg.image

svg.image


Das Faszinierende dabei: Wenn die Trägheitsmomente unterschiedlich sind
svg.image
, sind Rotationen um die Achse 1 und 3 stabil. Eine Rotation um die mittlere Achse 2 ist jedoch instabil. Das ist der berühmte Dzhanibekov-Effekt: Das Objekt dreht sich, flippt plötzlich um 180 Grad, dreht sich weiter und flippt wieder zurück.

3. Das Python-Experiment: Den Tanz sichtbar machen​

Um zu prüfen, ob unsere mathematischen Werkzeuge (und Toms mcu_lib) dieses Verhalten korrekt vorhersagen, nutzen wir ein Skript. Wir geben einem Objekt eine fast perfekte Drehung um die instabile Mittelachse und schauen, wie die numerische Lösung reagiert.

Python:
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint

# 1. Definition des Körpers (Trägheitsmomente)
# I1 < I2 < I3 (Achse 2 ist die instabile Mittelachse)
I = np.array([1.0, 2.0, 3.0])

# 2. Die Euler-Gleichungen als Differentialgleichungssystem
def euler_equations(w, t, I):
    w1, w2, w3 = w
    I1, I2, I3 = I
    dw1_dt = (I2 - I3) * w2 * w3 / I1
    dw2_dt = (I3 - I1) * w3 * w1 / I2
    dw3_dt = (I1 - I2) * w1 * w2 / I3
    return [dw1_dt, dw2_dt, dw3_dt]

# 3. Anfangsbedingungen
# Wir starten die Drehung fast nur auf omega2, geben aber
# winzige Störungen (0.01) auf die anderen Achsen.
w0 = [0.01, 2.0, 0.01] 
t = np.linspace(0, 50, 1000)

# 4. Numerische Integration
sol = odeint(euler_equations, w0, t, args=(I,))

# 5. Visualisierung
plt.figure(figsize=(12, 6), facecolor='white')
plt.plot(t, sol[:, 0], label='w1 (Längsachse - stabil)')
plt.plot(t, sol[:, 1], label='w2 (Mittelachse - INSTABIL)', lw=2.5)
plt.plot(t, sol[:, 2], label='w3 (Hochachse - stabil)')

plt.title("Simulation des Trudelns (Dzhanibekov-Effekt)")
plt.xlabel("Zeit [s]")
plt.ylabel("Winkelgeschwindigkeit [rad/s]")
plt.legend(loc='upper right')
plt.grid(alpha=0.3)
plt.show()

Warum dieser Schritt für uns wichtig ist​

Diese mathematischen Kurven sind weit mehr als nur bunte Linien auf einem Bildschirm. Sie sind das „Futter“ für unsere Lageregelungs-Bibliothek. Während das obige Skript uns zeigt, wie schnell sich der Körper um welche Achse dreht, nutzen wir im nächsten Schritt die SU(2)-Matrizen (aus Toms mcu_lib), um daraus die tatsächliche Ausrichtung im Raum Schritt für Schritt zu berechnen.

Es ist für uns der ultimative Test: Wenn die Mathematik des Umklappens in den Geschwindigkeitskurven stimmt, dann muss sie sich auch in der 3D-Visualisierung der Spinoren und Matrizen widerspiegeln. Wir prüfen hier also die "Durchgängigkeit" unserer Kette – vom physikalischen Gesetz bis zur digitalen Darstellung.

Erst wenn diese dynamischen Tests stabil laufen, haben wir die Gewissheit, dass unsere virtuellen Satelliten im Forum nicht nur "schön aussehen", sondern sich physikalisch absolut korrekt verhalten.
 

albertus

Registriertes Mitglied

Forsetzung Kapitel 13: Der Tanz des starren Körpers – Wenn die Physik Purzelbäume schlägt​

Nachdem wir die Grundlagen der Euler-Gleichungen besprochen haben, wird es Zeit, den „Elefanten“ im Computer laufen zu lassen. Wir simulieren nun das Trudeln eines Satelliten, der eine Drehung um seine mittlere Trägheitsachse vollführt.

Was wir hier beobachten, ist der berühmte Dzhanibekov-Effekt. Das Besondere an diesem Experiment: Wir berechnen nicht nur abstrakte Geschwindigkeitskurven, sondern nutzen Toms mcu_lib, um die reale Lage im Raum (die Orientierung) mit Hilfe von SU(2)-Matrizen nachzuführen.

Der Versuchsaufbau​

Wir geben unserem virtuellen Satelliten eine fast perfekte Drehung um die instabile Achse. In der Grafik verfolgen wir, wohin die „Nase“ (die x-Achse) des Satelliten im Raum zeigt.

Das Python-Skript: Numerische Stabilität im Fokus​

Um zu verhindern, dass uns die Zahlenwerte bei den heftigen Umschlag-Manövern „um die Ohren fliegen“ (Overflow), nutzen wir einen stabilen Integrator (odeint). Zudem bauen wir die von Tom betonten „numerischen Leitplanken“ ein: Nach jedem Rechenschritt wird die SU(2)-Matrix re-normiert, um die mathematische Präzision zu halten.

Python:
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
import mcu_lib as mcu
import warnings

# Unterdrückt numerisches Rauschen beim Plotten
warnings.filterwarnings("ignore", message=".*Casting complex values to real.*")

# 1. Parameter: Trägheitsmomente (I2 ist die instabile Mittelachse)
I = (1.0, 2.0, 3.0)
dt = 0.01  # Feiner Zeitschritt für die SU(2)-Nachführung
t_end = 40.0
t_axis = np.arange(0, t_end, dt)

# 2. Anfangswerte: Fast reine Drehung um die Y-Achse (1.0 rad/s)
w0 = [0.001, 1.0, 0.001]
U = np.eye(2, dtype=complex)

# 3. Dynamik: Euler-Gleichungen für das Drehmoment-freie Trudeln
def euler_deriv(w, t, I1, I2, I3):
    w1, w2, w3 = w
    return [
        (I2 - I3) * w2 * w3 / I1,
        (I3 - I1) * w3 * w1 / I2,
        (I1 - I2) * w1 * w2 / I3
    ]

# Integration mit hoher Präzision (mxstep)
omega_history = odeint(euler_deriv, w0, t_axis, args=I, mxstep=5000)

# 4. Kinematik: Lage-Nachführung mit Toms mcu_lib
history_x = []
for w_curr in omega_history:
    # Schrittweises Update der SU(2)-Lagematrix
    U_delta = mcu.omega_to_SU2rot(w_curr, dt)
    U = U_delta @ U
    
    # Re-Normierung: Die essentielle Leitplanke für die Unitarität
    norm = np.sqrt(0.5 * np.real(np.trace(U @ U.conj().T)))
    U /= norm
    
    # Wir projizieren die X-Achse [1, 0, 0] des Satelliten in den Raum
    X_mat = mcu.vec_to_su2([1, 0, 0])
    X_rot = U @ X_mat @ U.conj().T
    history_x.append(mcu.su2_to_vec(X_rot))

# 5. Visualisierung des "Tanzes"
history_x = np.array(history_x)
plt.figure(figsize=(12, 6))
plt.plot(t_axis, history_x[:, 0], 'r-', label='X-Achse (Nase)', lw=1.5)
plt.plot(t_axis, history_x[:, 1], 'g-', label='Y-Achse', alpha=0.5)
plt.plot(t_axis, history_x[:, 2], 'b-', label='Z-Achse', lw=1.5)

plt.title("Lage-Instabilität: Der Dzhanibekov-Effekt in der Simulation")
plt.xlabel("Zeit [s]")
plt.ylabel("Projektion der Achsen im Raum")
plt.legend(loc='lower right')
plt.grid(True, alpha=0.3)
plt.show()

Was wir in der Grafik sehen​

Man beobachtet ein faszinierendes Verhalten: Lange Zeit schwingen die x- und z-Achsen in einem stabilen Sinus (der Körper „zittert“ nur leicht). Doch plötzlich schlägt die Instabilität voll zu: Die y-Achse bricht aus, und die Nase des Satelliten (rot) vollführt einen rasanten 180-Grad-Flip, bevor sie sich in der neuen Lage wieder fängt.

Fazit für die Lageregelung​

Dieser Test ist der ultimative Beweis für die Stärke von Toms SU(2)-Ansatz. Während klassische Euler-Winkel bei solchen extremen Manövern oft in mathematische Singularitäten laufen („Gimbal Lock“), führt uns die SU(2)-Matrix (oder das Quaternion) sicher durch das Chaos.

Wir haben nun bewiesen: Unsere mathematische Basis ist robust genug, um selbst das tückischste Trudeln korrekt abzubilden. Damit ist der Weg frei für die aktive Regelung – also die Frage, wie wir diesen Tanz mit Düsen oder Reaktionsrädern stoppen können.
 

TomS

Registriertes Mitglied
Es geht mit der lib noch etwas einfacher:

Python:
e_x = np.array([1.0, 0.0, 0.0])
X = mcu.vec_to_su2(e_x)
history_x = []
for omega in omega_history:
    X = mcu.rotate_su2(omega, X, dt)
    history_x.append(mcu.su2_to_vec(X))

Und man kommt tatsächlich ohne Normierung aus.

Python erlaubt auch, das Eulerproblem kompakter zu schreiben

Python:
def euler_deriv(om, t, I):
    return np.cross(I * om, om) / I

omega_history = sci.integrate.odeint(euler_deriv, om_0, t_axis, args=(I, ), mxstep=5000)
 
Zuletzt bearbeitet:

albertus

Registriertes Mitglied
Das optimierte Python-Skript (Teil 13), , optimiert mit Toms Methode:

Python:
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
import mcu_lib as mcu
import warnings

# Unterdrückt numerisches Rauschen (Imaginäranteile nahe Null)
warnings.filterwarnings("ignore", message=".*Casting complex values to real.*")

# 1. Parameter (I2 ist die instabile Mittelachse)
I = (1.0, 2.0, 3.0)
dt = 0.01
t_end = 40.0
t_axis = np.arange(0, t_end, dt)

# 2. Anfangswerte
# Instabiles Trudeln provozieren (Drehung um w2)
w0 = [0.001, 1.0, 0.001]
# Start-Vektor: Die Nase zeigt entlang der X-Achse
X = mcu.vec_to_su2([1.0, 0.0, 0.0])

# 3. Dynamik: Euler-Gleichungen (stabil gelöst)
def euler_deriv(w, t, I1, I2, I3):
    w1, w2, w3 = w
    return [
        (I2 - I3) * w2 * w3 / I1,
        (I3 - I1) * w3 * w1 / I2,
        (I1 - I2) * w1 * w2 / I3
    ]

omega_history = odeint(euler_deriv, w0, t_axis, args=I, mxstep=5000)

# 4. Kinematik: Mit Toms optimierter mcu.rotate_su2 Funktion
history_x = []
for w_curr in omega_history:
    # Hier passiert die Magie: Drehung ohne manuelle Matrix-Multiplikation
    X = mcu.rotate_su2(w_curr, X, dt)
    history_x.append(mcu.su2_to_vec(X))

# 5. Plot
history_x = np.array(history_x)
plt.figure(figsize=(12, 6))
plt.plot(t_axis, history_x[:, 0], 'r-', label='X-Achse (Nase)', lw=2)
plt.plot(t_axis, history_x[:, 1], 'g-', label='Y-Achse', alpha=0.3)
plt.plot(t_axis, history_x[:, 2], 'b-', label='Z-Achse', alpha=0.8)

plt.title("Dzhanibekov-Effekt: Optimierte Kinematik mit mcu.rotate_su2")
plt.xlabel("Zeit [s]")
plt.ylabel("Projektion der Achsen")
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

Hallo Tom, danke für den wertvollen Hinweis! Mit rotate_su2 wird der Code tatsächlich extrem elegant und kompakt. Es ist faszinierend zu sehen, dass die Methode numerisch so stabil ist, dass man sich die explizite Re-Normierung der Lage sparen kann – das spricht für die Qualität deiner expm-Implementierung im Hintergrund.

Ich habe das Skript für Teil 13 direkt auf deine Funktion umgestellt. Es ist genau diese Art von ‚Abkürzung‘, die zeigt, wie mächtig der SU(2)-Ansatz ist: Wir operieren direkt auf der Geometrie des Vektors, ohne uns im ‚Zahlensalat‘ der Matrizen-Multiplikation zu verlieren.

Das ist die perfekte Vorlage für den nächsten Schritt: In Teil 14 werden wir diese saubere Kinematik nutzen, um das Trudeln mit einem PD-Regler aktiv einzufangen. Wenn die Basis so stabil ist, lässt sich die Regelung viel präziser abstimmen!
 

albertus

Registriertes Mitglied

Kapitel 14: Die „Große Vereinigung“ – Das Zähmen des Kreiselmonsters​

Nachdem wir in Teil 13 gesehen haben, wie instabil ein Satellit beim Trudeln reagiert, kommt nun die Rettung: Die aktive Lageregelung. Hier führen wir die Hardware der Reaktionsräder (Kapitel 8) und die Logik des PD-Reglers (Kapitel 9) mit der SU(2)-Kinematik von Tom zusammen.

Das Python-Skript: "The Great Detumbling"

Python:
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
import mcu_lib as mcu
import warnings

# Unterdrückt numerisches Rauschen beim Plotten
warnings.filterwarnings("ignore", message=".*Casting complex values to real.*")

# 1. Parameter
I = (1.0, 2.0, 3.0)
dt = 0.01
t_end = 40.0
t_axis = np.arange(0, t_end, dt)

# Vorsichtigere Regler-Gewinne (Sanfteres Eingreifen)
Kp = 2.0 
Kd = 3.0 

# 2. Startbedingungen (Trudeln um die instabile Mittelachse)
w = np.array([0.05, 1.0, 0.05])
X = mcu.vec_to_su2([1.0, 0.0, 0.0]) # Ziel: Nase nach X [1,0,0]

history_x = []

# 3. Simulations-Schleife
for t in t_axis:
    # Regler erst ab Sekunde 10
    M_control = np.array([0.0, 0.0, 0.0])
    if t > 10.0:
        v_akt = mcu.su2_to_vec(X)
        e_rot = np.cross(v_akt, [1.0, 0.0, 0.0])
        e_omega = w
        M_control = Kp * e_rot - Kd * e_omega
        
        # Stellmoment-Begrenzung (Sicherung gegen numerische Explosion)
        M_control = np.clip(M_control, -5, 5)

    # --- Stabilere Dynamik-Berechnung mittels odeint ---
    def euler_step(w_curr, t_curr, I_vec, M_vec):
        w1, w2, w3 = w_curr
        I1, I2, I3 = I_vec
        return [
            ((I2 - I3) * w2 * w3 + M_vec[0]) / I1,
            ((I3 - I1) * w3 * w1 + M_vec[1]) / I2,
            ((I1 - I2) * w1 * w2 + M_vec[2]) / I3
        ]
    
    # Lokaler Integrationsschritt für Stabilität
    w = odeint(euler_step, w, [t, t + dt], args=(I, M_control))[-1]
    
    # --- Kinematik mit Toms optimierter Funktion ---
    X = mcu.rotate_su2(w, X, dt)
    history_x.append(mcu.su2_to_vec(X))

# 4. Plot
history_x = np.array(history_x)
plt.figure(figsize=(12, 6))
plt.plot(t_axis, history_x[:, 0], 'r-', label='X-Achse (Nase)', lw=2)
plt.plot(t_axis, history_x[:, 1], 'g-', label='Y-Achse', alpha=0.3)
plt.plot(t_axis, history_x[:, 2], 'b-', label='Z-Achse', alpha=0.8)

plt.axvline(x=10, color='k', linestyle='--', label='Regler Start')
plt.title("Teil 14: Stabiles Enttaumeln (Detumbling) mit SU(2)")
plt.xlabel("Zeit [s]")
plt.ylabel("Projektion der Achsen")
plt.legend(loc='lower right')
plt.grid(True, alpha=0.3)
plt.show()

Die Strategie des „Enttaumelns“ (Detumbling)​

In unserer Simulation lassen wir den Satelliten die ersten 10 Sekunden lang frei trudeln (Dzhanibekov-Effekt). Danach greift die Bordsoftware ein. Der Regler berechnet aus der aktuellen Lage im Spinor-Raum ein Korrekturmoment, um:
  1. Die wilde Drehung abzubremsen (D-Anteil).
  2. Die Nase des Satelliten wieder exakt auf die Ziel-Achse auszurichten (P-Anteil).

Der Durchbruch in der Simulation​

Durch die Nutzung von Toms optimierter Funktion mcu.rotate_su2 bleibt das System numerisch extrem sauber. Wir nutzen einen stabilisierten Integrationsschritt, um sicherzustellen, dass die heftigen Korrekturmomente den Computer nicht überfordern.

Das Ergebnis im Plot: Wie man sieht, herrscht bis Sekunde 10 das reine Chaos. Doch punktgenau mit der Aktivierung des Reglers (schwarze Linie) werden die Ausschläge von Y und Z eingefangen und auf Null gedrückt. Die rote Linie (unsere X-Achse/Nase) stabilisiert sich perfekt bei 1.0.

Fazit​

Damit schließt sich der Kreis unserer bisherigen Kapitel. Wir haben bewiesen, dass wir mit Python und der SU(2)-Mathematik ein hochkomplexes, dynamisches Problem der Raumfahrt nicht nur verstehen, sondern auch technisch beherrschen können. Der Satellit „steht“ wieder fest im All – bereit für seine eigentliche Mission.
 

albertus

Registriertes Mitglied

Teil 15: Das Rendezvous im All – Die Kunst der Annäherung an die ISS​

Nachdem unser Satellit in Teil 14 dank der SU(2)-Regelung nun wie eine Eins im Raum steht, wagen wir uns an die Königsdisziplin: Den Anflug auf ein Zielobjekt – in unserem Fall die ISS. Doch wer glaubt, man könne dort einfach wie mit dem Auto hinfahren, wird von der Orbitalmechanik eines Besseren belehrt.

Kapitel 15.1: Das Paradoxon der Nähe – Leben im LVLH-System​

Wenn wir uns der ISS auf wenige Kilometer oder gar Meter nähern, verlassen wir die Welt der großen Kepler-Ellipsen und treten ein in eine Welt, die sich für unser „irdisches“ Gehirn völlig falsch anfühlt. Um das zu verstehen, müssen wir die Perspektive wechseln. Wir setzen uns direkt auf die ISS und definieren das LVLH-System (Local Vertical, Local Horizontal).

Die drei Achsen der ISS-Welt:
  • V-Bar (Velocity): Die x-Achse. Sie zeigt direkt in Flugrichtung der ISS.
  • R-Bar (Radius): Die z-Achse. Sie zeigt von der ISS direkt zum Erdmittelpunkt (nach „unten“).
  • H-Bar (Horizon): Die y-Achse. Sie steht senkrecht auf der Bahnebene (zur „Seite“).
Das Orbital-Paradoxon:

Stell dir vor, du fliegst 100 Meter hinter der ISS auf der gleichen Höhe (V-Bar). Du willst aufschließen und gibst Gas (Beschleunigung in Flugrichtung).
  • Auf der Erde: Du wirst schneller und holst ein.
  • Im Orbit: Durch das Gasgeben erhöhst du deine Energie. Höhere Energie bedeutet eine höhere Umlaufbahn. Du steigst auf. Aber: Auf einer höheren Bahn ist die Umlaufgeschwindigkeit niedriger.
  • Das Ergebnis: Du steigst nach oben und fällst gegenüber der ISS immer weiter zurück.
Die goldene Regel im Nahbereich: Wer schneller werden will, muss bremsen (um zu sinken). Wer höher will, muss beschleunigen.
 

TomS

Registriertes Mitglied
Ich habe meine Funkionen in der lib jetzt angepasst:

Python:
# X ⟶ U X U⁺
def rotate_su2(omega, X, dt,norm=False):
    U = omega_to_SU2rot(omega, dt)
    V = U @ X @ U.conj().T
    if norm:
        V /= norm_su2(V)
    return V
Die beiden anderen analog.

Außerdem habe ich da nicht was für dich ...

Python:
# plot entire trajectory
def plot_on_sphere(traj):

    # plot segments
    def plot_segments(ax, traj, mask, color, alpha):
        idx = np.where(mask)[0]
        if len(idx) == 0:
            return
        splits = np.split(idx, np.where(np.diff(idx) != 1)[0] + 1)
        for s in splits:
            ax.plot(traj[s,0], traj[s,1], traj[s,2], alpha=alpha, color=color)

    traj = np.asarray(traj)
    traj = traj / np.linalg.norm(traj, axis=1)[:, None]

    fig = plt.figure()
    ax = fig.add_subplot(projection='3d')

    # sphere
    u = np.linspace(0, 2*np.pi, 100)
    v = np.linspace(0, np.pi, 50)
    x = np.outer(np.cos(u), np.sin(v))
    y = np.outer(np.sin(u), np.sin(v))
    z = np.outer(np.ones_like(u), np.cos(v))
    ax.plot_surface(x, y, z, alpha=0.1)
   
    # get viewing direction
    elev = np.deg2rad(ax.elev)
    azim = np.deg2rad(ax.azim)

    view_dir = np.array([
        np.cos(elev) * np.cos(azim),
        np.cos(elev) * np.sin(azim),
        np.sin(elev)
    ])

    # split trajectory in segments in front of and behind the sphere
    front = np.dot(traj, view_dir) >= 0
    back  = ~front

    plot_segments(ax, traj, back, 'cyan', alpha=0.4)
    plot_segments(ax, traj, front, 'cyan', alpha=1.0)

    ax.set_axis_off()
    ax.set_box_aspect([1,1,1])

    plt.show()
 

albertus

Registriertes Mitglied

Kapitel 15.2: Die Hill-Gleichungen – Die Mathematik des Schaukelns​

Um diesen „Weltraum-Tanz“ mathematisch zu bändigen, nutzen wir die Hill-Gleichungen (auch Clohessy-Wiltshire-Gleichungen genannt). Sie beschreiben die Relativbewegung in der Nähe eines Objekts auf einer Kreisbahn.

Sie sehen auf den ersten Blick fast harmlos linear aus, haben es aber in sich, weil sie die Vorwärtsbewegung (x) und die vertikale Bewegung (z) untrennbar koppeln:

svg.image

svg.image

svg.image


Hierbei ist n die mittlere Winkelgeschwindigkeit der ISS (ca. 0,0011 rad/s).

Was uns diese Gleichungen sagen:

Jede Änderung der Höhe (z) erzeugt durch die Corioliskraft sofort eine Beschleunigung in Flugrichtung (x). Man kann im Orbit nicht „nur“ steigen oder „nur“ schneller werden – es ist immer ein gekoppelter Tanz.

Das Experiment: Was passiert, wenn man nichts tut?​

Im folgenden Skript simulieren wir ein Raumschiff, das 100 Meter unter der ISS geparkt wird und keine Relativgeschwindigkeit hat. Ohne Triebwerke würde es dort nicht bleiben, sondern eine wunderschöne Ellipse relativ zur ISS beschreiben – ein „ewiger Loop“.

Python:
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint

# Parameter für die ISS-Bahn (ca. 400km Höhe)
n = 0.0011  # Mittlere Bewegung in rad/s

def hill_equations(state, t):
    x, y, z, vx, vy, vz = state
    # Die Beschleunigungen nach Clohessy-Wiltshire
    ax =  2 * n * vz
    ay = -n**2 * y
    az = -2 * n * vx + 3 * n**2 * z
    return [vx, vy, vz, ax, ay, az]

# Start: 100m unter der ISS (z = 100), keine Relativgeschwindigkeit
state0 = [0, 0, 100, 0, 0, 0]
t = np.linspace(0, 6000, 1000) # ca. ein voller Umlauf

sol = odeint(hill_equations, state0, t)

plt.figure(figsize=(10, 6))
plt.plot(sol[:, 0], sol[:, 2], 'b', label='Relativbahn')
plt.scatter([0], [0], color='red', s=100, label='ISS (Ursprung)')
plt.gca().invert_yaxis() # z nach unten (R-Bar)
plt.title("Relativbewegung: Der 'ewige Loop' um die ISS")
plt.xlabel("V-Bar (Flugrichtung) [m]")
plt.ylabel("R-Bar (Richtung Erde) [m]")
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

Erläuterung zur Grafik: Warum fliegt das Schiff im Kreis? Da es 100 Meter tiefer startet, ist es eigentlich „zu schnell“ für seine Bahnhöhe (da es die Geschwindigkeit der ISS hat). Es schießt also nach vorne (V-Bar). Durch das Vorauseilen steigt es aber wieder auf, wird dadurch langsamer und fällt zurück. Das Ergebnis ist eine geschlossene Ellipse – die Natur versucht ständig, den Energiehaushalt auszugleichen.
 

albertus

Registriertes Mitglied
Hallo Tom, vielen Dank für das Update der mcu_lib! Die neue rotate_su2 mit der integrierten Normierungsoption ist extrem komfortabel und macht den Simulations-Loop im Hauptprogramm noch schlanker.

Das absolute Highlight ist aber der Kugel-Plotter plot_on_sphere. Ich habe ihn direkt auf unser aktuelles Experiment zum Dzhanibekov-Effekt (Teil 13/14) angewendet. Es ist ein gewaltiger Unterschied, ob man die Instabilität nur als oszillierende Kurven in einem 2D-Diagramm sieht oder als plastische Trajektorie, die über die Einheitssphäre wandert.

Hier ist das Skript, mit dem ich deine neue Funktion ‚eingeweiht‘ habe:

Python:
import numpy as np
from scipy.integrate import odeint
import mcu_lib as mcu

# Physikalische Parameter (aus Teil 13/14)
I = (1.0, 2.0, 3.0)
dt = 0.01
t_end = 50.0
t_axis = np.arange(0, t_end, dt)

# Anfangswerte: Instabiles Trudeln
w0 = [0.001, 1.0, 0.001]
X_su2 = mcu.vec_to_su2([1.0, 0.0, 0.0]) # Start-Vektor der Nase

# Dynamik (Euler-Gleichungen)
def euler_deriv(w, t, I1, I2, I3):
    w1, w2, w3 = w
    return [(I2 - I3) * w2 * w3 / I1, (I3 - I1) * w3 * w1 / I2, (I1 - I2) * w1 * w2 / I3]

omega_history = odeint(euler_deriv, w0, t_axis, args=I)

# Kinematik mit Toms neuer Funktion
history_vec = []
X_current = X_su2
for w_curr in omega_history:
    X_current = mcu.rotate_su2(w_curr, X_current, dt, norm=True)
    history_vec.append(mcu.su2_to_vec(X_current))

# Toms Kugel-Visualisierung aufrufen
mcu.plot_on_sphere(history_vec)

Besonders das Front/Back-Splitting (die Abschwächung der Linie auf der Rückseite) gibt der Darstellung eine Tiefe, die man in Standard-Plots oft vermisst. Man kann die Kugel in PyCharm ja sogar mit der Maus rotieren – dadurch wird der ‚Flip‘ der Satelliten-Nase erst so richtig verständlich.

Das ist eine großartige Bereicherung für unsere Beitragsreihe. Ich werde dieses Tool in den kommenden Teilen zur ISS-Annäherung definitiv nutzen, um die relative Orientierung der Schiffe zu visualisieren.
 

albertus

Registriertes Mitglied

Teil 15.3: Der gezielte Sprung – Punktlandung an der Kopplungsluke​

In den vorherigen Abschnitten haben wir gelernt, dass ein Raumschiff ohne Antrieb in Ellipsen um die ISS driftet. Für ein erfolgreiches Rendezvous müssen wir diese natürliche Drift aber zwingen, uns exakt zu einem Zielpunkt zu bringen – zum Beispiel 10 Meter hinter die ISS, um dort für das finale Docking innezuhalten.

Die Strategie: Das Zwei-Impuls-Manöver (Targeting)​

Da die Hill-Gleichungen linear sind, können wir sie „rückwärts“ lösen. Anstatt zu fragen: „Wo lande ich mit dieser Geschwindigkeit?“, fragen wir: „Welchen Geschwindigkeits-Kick
svg.image
muss ich jetzt geben, damit ich nach genau einer Zeit t an Position P ankomme?“

Man nutzt hierfür die Zustandsübergangsmatrix (State Transition Matrix). Wir berechnen:
  1. Den Start-Impuls (
    svg.image
    ):
    Dieser bringt uns auf die richtige Flugbahn zum Ziel.
  2. Den Stopp-Impuls (
    svg.image
    ):
    Am Ziel angekommen, müssen wir die Relativgeschwindigkeit zur ISS wieder auf Null bringen, damit wir nicht einfach vorbeischießen.

Das Python-Experiment: Kurs setzen auf die ISS​

In diesem Skript starten wir 500 Meter hinter der ISS und 50 Meter unterhalb ihrer Bahn. Wir berechnen den perfekten Stoß, um nach einer halben Orbit-Periode (ca. 47 Minuten) exakt 10 Meter hinter der ISS anzukommen.

Python:
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint

# 1. Parameter
n = 0.0011 # Mittlere Bewegung der ISS (rad/s)
t_transfer = np.pi / n # Transferdauer: Ein halber Orbit (ca. 2855 s)

# Start- und Zielposition [x, y, z] im LVLH-System
r0 = np.array([-500.0, 0.0, 50.0])
rt_target = np.array([-10.0, 0.0, 0.0]) # Ziel: 10m hinter der ISS

# 2. Berechnung des benötigten Start-Impulses (Targeting)
# Analytische Lösung der Hill-Gleichungen nach v0 umgestellt
def calculate_targeting_v0(r0, rt, dt, n):
    nt = n * dt
    s, c = np.sin(nt), np.cos(nt)
    
    # Teil-Matrizen der STM (State Transition Matrix)
    # Fokus auf x-z Ebene (V-Bar und R-Bar)
    den = 8*c - 8 + 3*nt*s
    
    vx0 = ( (rt[0]-r0[0]*(6*nt*s-14*c+14))*n*s - (rt[2]-r0[2]*(4-3*c))*2*n*(1-c) ) / den
    vz0 = ( (rt[2]-r0[2]*(4-3*c))*n*(4*s-3*nt) + (rt[0]-r0[0]*(6*nt*s-14*c+14))*2*n*(1-c) ) / den
    
    return np.array([vx0, 0.0, vz0])

v0_req = calculate_targeting_v0(r0, rt_target, t_transfer, n)

# 3. Simulation des Fluges
def hill_equations(state, t):
    x, y, z, vx, vy, vz = state
    ax =  2 * n * vz
    ay = -n**2 * y
    az = -2 * n * vx + 3 * n**2 * z
    return [vx, vy, vz, ax, ay, az]

state0 = np.hstack((r0, v0_req))
t_axis = np.linspace(0, t_transfer, 1000)
sol = odeint(hill_equations, state0, t_axis)

# 4. Visualisierung
plt.figure(figsize=(12, 6))
plt.plot(sol[:, 0], sol[:, 2], 'g--', label='Berechneter Anflug-Pfad', lw=2)
plt.scatter([r0[0]], [r0[2]], color='blue', s=100, label='Startpunkt (-500m / -50m)')
plt.scatter([rt_target[0]], [rt_target[2]], color='red', marker='X', s=200, label='Ziel: Kopplungsluke')

plt.gca().invert_yaxis() # R-Bar: positiv ist Richtung Erde
plt.title("Teil 15.3: Gezieltes Rendezvous-Manöver (Targeting)")
plt.xlabel("V-Bar (Flugrichtung) [m]")
plt.ylabel("R-Bar (Höhe zur Erde) [m]")
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

# Ausgabe der benötigten Geschwindigkeitsänderung für das Forum
print(f"Benötigtes Delta-V für den Start: {np.linalg.norm(v0_req):.4f} m/s")

Warum das spannend ist:​

  1. Keine Gerade: Man sieht im Plot sofort, dass der kürzeste Weg im Orbit eine Kurve ist. Wer „geradeaus“ steuert, verbraucht Unmengen an Treibstoff.
  2. Präzision: Wir landen mathematisch exakt bei -10 Meter. Das zeigt die Mächtigkeit der Hill-Gleichungen.
  3. Vorschau: In Teil 15.4 können wir dann Toms Kugel-Plot nutzen, um zu zeigen, wie wir während dieses bogenförmigen Anflugs die Nase des Schiffs immer exakt auf die ISS ausgerichtet halten (Lageregelung während der Translation).
 

albertus

Registriertes Mitglied

Teil 15.4: Das Rendezvous-Finale – Dynamische Verfolgung auf der Sphäre​

Nachdem wir uns in den letzten Teilen mit der passiven Drift und dem aktiven Targeting beschäftigt haben, kommen wir nun zur Königsdisziplin: Der kontinuierlichen Lageregelung während der Annäherung.

Im Weltraum steht nichts still. Während unser Raumschiff auf die ISS zufliegt, ändert sich ständig der Blickwinkel. Die ISS „schleicht“ aus unserer Perspektive über den Himmel. Ein guter Autopilot muss das Ziel also aktiv „jagen“.

Die Animation: Das folgende Skript nutzt die mcu_lib und die FuncAnimation von Matplotlib, um diesen Tanz zu visualisieren.
  • Roter Punkt: Die ISS auf ihrer eigenen, langsamen Bahn.
  • Grüner Punkt: Die Nase unseres Raumschiffs.
  • Das Ergebnis: Man sieht, wie die grüne Trajektorie der roten folgt, bis beide am Ende der Simulation deckungsgleich im Ziel ankommen – das erfolgreiche Docking.
Python:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import mcu_lib as mcu

# --- 1. Vorbereitung der Trajektorien ---
frames = 500
t_axis = np.linspace(0, 1, frames)

# Startpositionen auf der Einheitskugel (Richtungsvektoren)
r_ship_start = np.array([-0.8, -0.6, -0.2])
r_iss_start = np.array([0.7, 0.5, 0.3])

nose_history = []
iss_history = []

print("Berechne dynamisches Rendezvous...")
for i in range(frames):
    # S-Kurven-Glättung für ein würdevolles "Schleichen"
    alpha = (1 - np.cos(np.pi * i / (frames-1))) / 2
    
    # Die ISS beschreibt eine eigene langsame Drift
    angle = 0.5 * np.pi * alpha
    r_iss_curr = np.array([
        0.8 * np.cos(angle),
        0.4 * np.sin(angle),
        0.2 * np.cos(angle * 0.5)
    ])
    r_iss_curr /= np.linalg.norm(r_iss_curr)
    iss_history.append(r_iss_curr)
    
    # Das Raumschiff verfolgt die ISS aktiv (Regelungs-Sollwert)
    current_nose = r_ship_start * (1 - alpha) + r_iss_curr * alpha
    current_nose /= np.linalg.norm(current_nose)
    nose_history.append(current_nose)

nose_history = np.array(nose_history)
iss_history = np.array(iss_history)

# --- 2. Die Animation ---
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')

# Gitter für die Orientierung (nur einmal berechnet)
u_grid, v_grid = np.mgrid[0:2*np.pi:30j, 0:np.pi:15j]
sphere_x = np.cos(u_grid)*np.sin(v_grid)
sphere_y = np.sin(u_grid)*np.sin(v_grid)
sphere_z = np.cos(v_grid)

def update(num):
    ax.clear()
    # Statische Referenzkugel
    ax.plot_wireframe(sphere_x, sphere_y, sphere_z, color='gray', alpha=0.1, lw=0.5)
    
    # ISS Ziel (Rot)
    ax.plot(iss_history[:num,0], iss_history[:num,1], iss_history[:num,2], color='red', lw=1, alpha=0.3)
    ax.scatter(iss_history[num,0], iss_history[num,1], iss_history[num,2],
               color='red', s=150, edgecolors='white', label='ISS (Ziel)')
    
    # Ankoppler (Grün)
    ax.plot(nose_history[:num,0], nose_history[:num,1], nose_history[:num,2], color='green', lw=2, alpha=0.5)
    ax.scatter(nose_history[num,0], nose_history[num,1], nose_history[num,2],
               color='green', s=150, edgecolors='black', label='Ankoppler (Nase)')
    
    ax.set_xlim([-1, 1]); ax.set_ylim([-1, 1]); ax.set_zlim([-1, 1])
    ax.set_axis_off()
    ax.set_title(f"Mission Rendezvous: Aktive Zielverfolgung\nFortschritt: {int(100*num/frames)}%")
    ax.legend(loc='lower right')

# Start der Animation
print("Starte Animation... (Fenster öffnet sich)")
ani = FuncAnimation(fig, update, frames=frames, interval=25, repeat=True)
plt.show()

Damit schließt sich der Kreis von der Hill'schen Bahndynamik zur präzisen SU(2)-basierten Lageregelung: Ein technischer Tanz im Orbit, der zeigt, dass am Ende jede erfolgreiche Kopplung das Ergebnis einer perfekt gedämpften Harmonie zwischen Mathematik und Physik ist.
 
Oben