====== std.astro.guidance — Annäherung, Abweichung, Proportional Navigation ====== ''import std.astro.guidance;'' Alles, was aus **Relativvektoren** folgt: Abstand, Annäherungsrate, dichteste Annäherung, Restflugzeit, Sichtlinienrate und die Sollbeschleunigung der Proportional Navigation. Alle Funktionen nehmen ''rRel'' und ''vRel'' — Ort und Geschwindigkeit des Ziels **relativ zum eigenen Fahrzeug**, im selben Rahmen. Wer absolute Zustände hat, bildet vorher die Differenz. → [[lyx_-_programmiersprache:units:astro|std.astro (Übersicht)]] · [[lyx_-_programmiersprache:units:astro:attitude|std.astro.attitude]] · [[lyx_-_programmiersprache:units:astro:state|std.astro.state]] ---- ===== 1. Abstand und Annäherung ===== ^ Funktion ^ Rückgabe ^ Bedeutung ^ | ''ARange(rRel)'' | ''f64'' [m] | Abstand | | ''AClosingSpeed(rRel, vRel)'' | ''f64'' [m/s] | Annäherungsrate; **positiv beim Näherkommen** | | ''ATimeToCPA(rRel, vRel)'' | ''f64'' [s] | Zeit bis zur dichtesten Annäherung; negativ heißt: der Punkt liegt hinter uns | | ''ADistanceAtCPA(rRel, vRel)'' | ''f64'' [m] | Abstand in diesem Punkt | | ''ARelPositionAt(rRel, vRel, t)'' | ''AVec3'' | geradlinig fortgeschriebene Relativposition | | ''ATimeToGo(rRel, vRel)'' | ''f64'' [s] | Restflugzeit; **NaN, wenn sich das Ziel entfernt** | | ''AGuidanceThreshold()'' | ''f64'' | 1e−12 | > **''ATimeToGo'' meldet lieber NaN als eine große Zahl.** Entfernt sich das Ziel, gibt es keine Restflugzeit — ein großer positiver Wert wäre dort besonders gefährlich, weil er aussieht wie „noch viel Zeit". ===== 2. Abweichung von der Bahn ===== ^ Funktion ^ Rückgabe ^ Bedeutung ^ | ''ACrossTrack(rRel, vRel)'' | ''f64'' [m] | Querabweichung — senkrecht **auf die Geschwindigkeitsrichtung** | | ''AAlongTrack(rRel, vRel)'' | ''f64'' [m] | Abstand entlang der Bahngeraden, positiv wenn das Ziel voraus liegt | > **Gemessen wird senkrecht auf die Bewegungsrichtung, nicht auf die Verbindungslinie.** Der Unterschied ist keine Kleinigkeit: bei 50 km Abstand und 50 Grad zwischen beiden liegen 12 km dazwischen. Der Fehler fällt nur auf, wenn ein Test einen **schiefen** Fall rechnet — ein rechtwinkliger gibt beidesmal dasselbe. ===== 3. Sichtlinie und Proportional Navigation ===== ^ Funktion ^ Rückgabe ^ Bedeutung ^ | ''ALosRate(rRel, vRel)'' | ''AVec3'' [rad/s] | Drehvektor der Sichtlinie: ''(r × v)/|r|²'' — Betrag = Rate, Richtung = Drehachse | | ''ALosRateMagnitude(rRel, vRel)'' | ''f64'' [rad/s] | nur der Betrag | | ''ALosUnit(rRel)'' | ''AVec3'' | Einheitsvektor der Sichtlinie | | ''AProNavAccel(rRel, vRel, n)'' | ''AVec3'' [m/s²] | Sollbeschleunigung ''N·V_c·(ω × r̂)'' | | ''AOnCollisionCourse(rRel, vRel, rateSchranke)'' | ''bool'' | Sichtlinienrate unter der Schranke **und** Ziel kommt näher | Der Navigationsbeiwert ''n'' liegt üblich bei **3 bis 5**. > **Die Kernaussage der Proportional Navigation steht in einer Zahl:** bei konstanter Sichtlinien//richtung// ist ω null und damit die Sollbeschleunigung null — das ist Kollisionskurs. Die Beschleunigung steht **senkrecht** auf der Sichtlinie: sie stellt die Sichtlinie still, sie bremst nicht. Wer sie entlang der Sichtlinie ansetzt, fliegt eine Verfolgungskurve und keine Proportional Navigation. > > ''AOnCollisionCourse'' prüft deshalb **zwei** Bedingungen. Eine ruhende Sichtlinie bei wachsendem Abstand ist gerade kein Kollisionskurs, sondern ein sich entfernendes Ziel auf derselben Geraden. ===== 4. Beispiel ===== import std.astro.state; import std.astro.guidance; 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 { // Ziel 1000 m voraus, 50 m seitlich versetzt, kommt mit 10 m/s entgegen var r: AVec3 := AVec(1000.0, 50.0, 0.0); var v: AVec3 := AVec(0.0 - 10.0, 0.0, 0.0); zeig("Abstand m : ", ARange(r), 1); zeig("Annaeherungsrate : ", AClosingSpeed(r, v), 2); zeig("Zeit bis CPA s : ", ATimeToCPA(r, v), 1); zeig("Abstand bei CPA m : ", ADistanceAtCPA(r, v), 1); zeig("Restflugzeit s : ", ATimeToGo(r, v), 1); zeig("Querabweichung m : ", ACrossTrack(r, v), 1); zeig("Laengsabweichung m : ", AAlongTrack(r, v), 1); zeig("Sichtlinienrate : ", ALosRateMagnitude(r, v), 6); var p: AVec3 := ARelPositionAt(r, v, 50.0); Print("Ort nach 50 s : ("); Print(FloatToStr(p.x, 1)); Print(", "); Print(FloatToStr(p.y, 1)); PrintLn(")"); var a: AVec3 := AProNavAccel(r, v, 4.0); zeig("ProNav |a| m/s2 : ", AMagnitude(a), 4); Print("Kollisionskurs? : "); PrintLn(IntToStr(BI(AOnCollisionCourse(r, v, 0.0001)))); // Echter Kollisionskurs: genau aufeinander zu var rk: AVec3 := AVec(1000.0, 0.0, 0.0); var vk: AVec3 := AVec(0.0 - 10.0, 0.0, 0.0); zeig("gerade: Sichtrate : ", ALosRateMagnitude(rk, vk), 6); zeig("gerade: ProNav |a| : ", AMagnitude(AProNavAccel(rk, vk, 4.0)), 6); Print("gerade: Kollision? : "); PrintLn(IntToStr(BI(AOnCollisionCourse(rk, vk, 0.0001)))); // Ziel entfernt sich: keine Restflugzeit, kein Kollisionskurs var vw: AVec3 := AVec(10.0, 0.0, 0.0); Print("entfernt: t_go NaN : "); PrintLn(IntToStr(BI(AIsError(ATimeToGo(rk, vw))))); Print("entfernt: Kollis.? : "); PrintLn(IntToStr(BI(AOnCollisionCourse(rk, vw, 0.0001)))); return 0; } Abstand m : 1001.2 Annaeherungsrate : 9.99 Zeit bis CPA s : 100.0 Abstand bei CPA m : 50.0 Restflugzeit s : 100.3 Querabweichung m : 50.0 Laengsabweichung m : -1000.0 Sichtlinienrate : 0.000499 Ort nach 50 s : (500.0, 50.0) ProNav |a| m/s2 : 0.0199 Kollisionskurs? : 0 gerade: Sichtrate : 0.000000 gerade: ProNav |a| : 0.000000 gerade: Kollision? : 1 entfernt: t_go NaN : 1 entfernt: Kollis.? : 0 Der mittlere Block ist die eigentliche Aussage: auf **genauem** Kollisionskurs sind Sichtlinienrate **und** Sollbeschleunigung exakt null. Die Regelung tut nichts — weil nichts zu tun ist. Im schiefen Fall darüber ergibt dieselbe Rechnung 0.0199 m/s², und die Querabweichung von 50 m bleibt bis zur dichtesten Annäherung erhalten. Der letzte Block zeigt die Gegenprobe: dasselbe Ziel, nur wegfliegend — die Restflugzeit ist NaN, und ''AOnCollisionCourse'' meldet trotz **ruhender** Sichtlinie korrekt „nein". ---- Letzte Aktualisierung: 2026-09-01 — Seite neu angelegt aus ''std/astro/guidance.lyx'' (Commit 32353cc, #1900, 83 Prüfungen); Beispiel mit ''lyxc 1.1.16A'' gebaut und ausgeführt.