Ein Flugführungsrechner beantwortet dem Piloten drei Fragen: wo bin ich auf dem Profil, wann komme ich an und womit komme ich an. Dieser Guide baut die Rechnungen dahinter Schritt für Schritt mit std.aero — vom Steigflug über den Sinkflugbeginn bis zur Warteschleife.
→ Guides · Vorher lesen: Standardatmosphäre, Höhen und Geschwindigkeiten · Navigation und Wegpunkte · Unit-Übersicht · DO-178C
import std.aero.atmos; // Atmosphäre, Höhen, Geschwindigkeiten
import std.aero.perf; // Bahngeometrie, Zwangspunkte, Reiseflug, Wind
import std.aero.vnav; // segmentierte Steig- und Sinkprofile
import std.aero.fplan; // Vorhersage über die Route, Reserven
import std.aero.holding; // Warteschleifen
<WRAP center round important 90%>
Diese Units rechnen — sie fliegen nicht. Was hier entsteht, ist ein Planungswerkzeug. Ein Gerät an Bord braucht zusätzlich den Nachweisprozess nach DO-178C, eine Musterzulassung und die Daten aus dem Flughandbuch des konkreten Musters. std.aero ist neu (2026-09-04) und im ausgelieferten lyxc 1.1.18A noch nicht enthalten.
</WRAP>
Der häufigste Anfängerfehler beim Nachbau eines FMS ist eine Funktion namens Sinkrate(). Die gibt es nicht, weil ein FMS vier verschiedene Fragen beantwortet — und wer sie verwechselt, bekommt eine Zahl, die plausibel aussieht und nicht zur Lage passt:
| Frage | Funktion | Hängt ab von |
|---|---|---|
| Welche Rate hält einen 3°-Pfad bei dieser Grundgeschwindigkeit? | AvSinkrateFpm | nur der Grundgeschwindigkeit — reine Trigonometrie |
| Welche Rate erreicht „FL100 bei 30 NM„? | AvNoetigeSinkrateFpm | Höhe und Strecke als Vorgabe |
| Wo muss der Sinkflug beginnen, damit er im Leerlauf aufgeht? | AvTodStreckeNm | Gleitzahl des Musters und Wind |
| Welche Geschwindigkeit ist bei diesem Cost Index günstiger? | AvGuenstigere | Kostenverhältnis — eine Optimierung |
Dieselbe Trennung gilt auf der Steigseite: die beste Steigrate ist ein Energieüberschuss-Problem (AvSteigrateFpm: überschüssige Leistung geteilt durch Gewicht), keine Geometrie.
Ein Verkehrsflugzeug steigt unten mit 2500 ft/min und oben mit 500, und der Stundenverbrauch fällt dabei um ein Drittel. std.aero.vnav integriert deshalb in Schritten über die Höhe, statt mit einem Mittelwert zu rechnen:
unit main;
import std.aero.atmos;
import std.aero.perf;
import std.aero.vnav;
import std.io;
import std.string;
fn main(): int64 {
// Steigflug 1500 ft -> FL350, Plan 280 kt / M0.78, ISA+10, 20 kt Gegenwind
var p: AvProfil := AvSteigprofil(1500.0, 35000.0, 1000.0,
280.0, 0.78, 10.0,
2400.0, 500.0, // ROC unten / oben
3200.0, 1500.0, // kg/h unten / oben
0.0 - 20.0);
if (AvProfilGueltig(p) == false) { PrintLn("Profil ungueltig"); return 1; }
PrintLn(StrConcat("erreichte Hoehe: ", StrConcat(FloatToStr(AvProfilEndhoeheFt(p), 0), " ft")));
PrintLn(StrConcat("Dauer: ", StrConcat(FloatToStr(AvProfilZeitMin(p), 1), " min")));
PrintLn(StrConcat("Strecke: ", StrConcat(FloatToStr(AvProfilStreckeNm(p), 1), " NM")));
PrintLn(StrConcat("Treibstoff: ", StrConcat(FloatToStr(AvProfilKraftstoffKg(p), 0), " kg")));
// Zum Vergleich: eine einzige mittlere Rate
PrintLn(StrConcat("grob (1450 fpm): ",
StrConcat(FloatToStr(AvSteigzeitMin(1500.0, 35000.0, 1450.0), 1), " min")));
return 0;
}
erreichte Hoehe: 35000 ft
Dauer: 27.6 min
Strecke: 175.1 NM
Treibstoff: 985 kg
grob (1450 fpm): 23.1 min
Viereinhalb Minuten Unterschied auf einem einzigen Steigflug — und die Mittelwertrechnung liegt in die optimistische Richtung daneben. Über einen Flugplan mit Treibstoffrechnung ist das der Unterschied zwischen „reicht“ und „reicht nicht„.
Die Strecke aus dem Profil ist gleichzeitig der T/C (Top of Climb): 175 NM nach dem Start ist die Reiseflughöhe erreicht. Für die Position auf der Route gibt es AvTopOfClimbNm.
AvProfilEndhoeheFt sagt, wie weit es gekommen ist. Das ist die ehrliche Antwort auf „das Flugzeug schafft die Höhe heute nicht“ — ein Ergebnis mit der Zielhöhe wäre eine Lüge. Immer AvProfilGueltig und die erreichte Höhe prüfen, nie die angeforderte weiterverwenden.
Der Sinkflugbeginn (T/D) ist die wichtigste einzelne Zahl im Reiseflug. Zu spät heißt: zu hoch am Zwangspunkt und Bremsen im Sinkflug. Zu früh heißt: minutenlang tief fliegen und Treibstoff verschwenden.
unit main;
import std.aero.perf;
import std.io;
import std.string;
fn main(): int64 {
var jetztFt: f64 := 35000.0;
var zielFt: f64 := 3000.0;
var gleitzahl: f64 := 17.0; // aus dem Flughandbuch
var tasKt: f64 := 280.0;
var wind: f64 := 25.0; // Rückenwind, positiv
PrintLn(StrConcat("Faustformel 3:1: ",
StrConcat(FloatToStr(AvTodStreckeNmFaustformel(jetztFt, zielFt), 1), " NM")));
PrintLn(StrConcat("mit Gleitzahl 17: ",
StrConcat(FloatToStr(AvTodStreckeNm(jetztFt, zielFt, gleitzahl, tasKt, wind), 1), " NM")));
PrintLn(StrConcat("Sinkrate dazu: ",
StrConcat(FloatToStr(AvTodSinkrateFpm(gleitzahl, tasKt, wind), 0), " fpm")));
// Zwangspunkt: FL100 bei 30 NM, wir sind in FL180
PrintLn(StrConcat("noetige Rate: ",
StrConcat(FloatToStr(AvNoetigeSinkrateFpm(18000.0, 10000.0, 30.0, 300.0), 0), " fpm")));
PrintLn(StrConcat("noetiger Winkel: ",
StrConcat(FloatToStr(AvNoetigerWinkelGrad(18000.0, 10000.0, 30.0), 2), " Grad")));
if (AvZwangspunktErreichbar(18000.0, 10000.0, 30.0, gleitzahl, tasKt, wind)) {
PrintLn("Zwangspunkt: erreichbar");
} else {
PrintLn(StrConcat("zu hoch um: ",
StrConcat(FloatToStr(AvAbweichungVomProfilFt(18000.0, 10000.0, 30.0,
gleitzahl, tasKt, wind), 0), " ft")));
}
return 0;
}
Faustformel 3:1: 96.0 NM
mit Gleitzahl 17: 97.5 NM
Sinkrate dazu: 1668 fpm
noetige Rate: 1333 fpm
noetiger Winkel: 2.51 Grad
Zwangspunkt: erreichbar
Die 3:1-Regel („drei mal die abzubauenden Tausend Fuß„) liegt hier nur anderthalb Meilen daneben — bei Rückenwind und einer besseren Gleitzahl geht die Schere weiter auf. Sie steht als eigene Funktion da, weil sie im Cockpit tatsächlich benutzt wird, aber sie ersetzt die Rechnung nicht.
AvZwangspunktErreichbar hält die nötige gegen die mögliche Rate. Genau das ist der Grund, warum ein FMS eine Meldung ausgibt, statt still ein unmögliches Profil zu zeichnen — und AvAbweichungVomProfilFt liefert die Zahl hinter der Anzeige „so viele Fuß über dem Pfad“.
AvTodStreckeAusProfilNm aus std.aero.vnav: dort wird das Sinkprofil integriert und die Strecke ist das Ergebnis, nicht die Eingabe.
T/C, T/D und DECEL sind keine echten Wegpunkte — sie stehen in keiner Datenbank, sondern werden aus dem Profil gerechnet und als Symbol auf die Route gezeichnet. Alle drei liefern eine Position in NM entlang der Route, nicht eine Strecke:
| Symbol | Funktion | Bedeutung |
|---|---|---|
| T/C | AvTopOfClimbNm | hier ist die Reiseflughöhe erreicht |
| T/D | AvTopOfDescentNm | hier beginnt der Sinkflug |
| DECEL | AvDecelPunktNm | hier beginnt die Verzögerung auf Anfluggeschwindigkeit |
AvTopOfDescentNm den Fehlerwert — keine negative Zahl. „Der Sinkflug hätte schon begonnen haben müssen„ ist eine Lage, keine Position, und eine negative Zahl sähe aus wie ein Ergebnis.
Dazu kommt die Kurvengeometrie, ohne die eine Route zu lang gerechnet wird: AvKurvenvorhaltNm sagt, wie weit vor dem Knickpunkt die Kurve beginnt, AvKurvenabkuerzungNm den Streckengewinn. Ab 180° Kursänderung ist der Vorhalt ein Fehler — eine Kehrtwende lässt sich nicht abkürzen.
Das ist die Seite, die ein Pilot am häufigsten ansieht. Jeder Abschnitt verbraucht Zeit und Treibstoff, und der Zustand am Ende ist der Anfang des nächsten:
unit main;
import std.aero.fplan;
import std.io;
import std.string;
fn zeige(name: pchar, v: AvVorhersage): void {
var s: pchar := StrConcat(name, " t=");
s := StrConcat(s, FloatToStr(AvVorhersageZeitMin(v), 0));
s := StrConcat(s, " min s=");
s := StrConcat(s, FloatToStr(AvVorhersageStreckeNm(v), 0));
s := StrConcat(s, " NM EFOB=");
PrintLn(StrConcat(s, StrConcat(FloatToStr(AvVorhersageEfobKg(v), 0), " kg")));
}
fn main(): int64 {
var v: AvVorhersage := AvVorhersageStart(9000.0);
AvVorhersageZeitabschnitt(v, 12.0, 600.0); // Rollen: Zeit ohne Strecke
zeige("nach Rollen ", v);
AvVorhersageAbschnitt(v, 175.0, 380.0, 2100.0); // Steigflug
zeige("T/C ", v);
AvVorhersageAbschnitt(v, 520.0, 460.0, 1900.0); // Reiseflug
zeige("T/D ", v);
AvVorhersageAbschnitt(v, 98.0, 400.0, 900.0); // Sinkflug
zeige("Anflug ", v);
var strecke: f64 := AvVorhersageVerbrauchKg(v);
var zuschlag: f64 := AvZuschlagKg(strecke, 5.0);
var endres: f64 := AvEndreserveKg(1200.0, 30.0);
var mindest: f64 := AvMindestkraftstoffKg(120.0, strecke, zuschlag, 1400.0, endres, 0.0);
PrintLn(StrConcat("Streckenverbrauch: ", StrConcat(FloatToStr(strecke, 0), " kg")));
PrintLn(StrConcat("Mindestmenge: ", StrConcat(FloatToStr(mindest, 0), " kg")));
if (AvKraftstoffReicht(9000.0, mindest)) {
PrintLn(StrConcat("Ueberschuss: ",
StrConcat(FloatToStr(AvKraftstoffUeberschussKg(9000.0, mindest), 0), " kg")));
} else {
PrintLn("REICHT NICHT");
}
var ab: f64 := 22.0 * 60.0 + 40.0; // Abflug 22:40
var an: f64 := AvAnkunftMinuten(ab, AvVorhersageZeitMin(v));
PrintLn(StrConcat("Ankunft: ",
StrConcat(IntToStr(AvStundeAus(an)), StrConcat(":", IntToStr(AvMinuteAus(an))))));
return 0;
}
nach Rollen t=12 min s=0 NM EFOB=8880 kg
T/C t=40 min s=175 NM EFOB=7913 kg
T/D t=107 min s=695 NM EFOB=5765 kg
Anflug t=122 min s=793 NM EFOB=5545 kg
Streckenverbrauch: 3455 kg
Mindestmenge: 5748 kg
Ueberschuss: 3252 kg
Ankunft: 0:42
Vier Dinge sind daran wichtig:
AvVorhersageZeitabschnitt gibt es, damit man sie nicht mit Strecke 0 und irgendeiner Geschwindigkeit einsetzen muss — die Division wäre eine Lüge.Die Aufteilung steht in der Unit, die Zahlen kommen vom Aufrufer — sie stehen im Betriebshandbuch und unterscheiden sich je nach Betreiber und Flugart:
Die Summe ist in AvMindestkraftstoffKg bewusst ausgeschrieben statt in einem Faktor versteckt: wer eine Position weglässt, sieht es an der Aufrufstelle.
unit main;
import std.aero.holding;
import std.io;
import std.string;
fn main(): int64 {
var einflugkurs: f64 := 90.0;
var hoeheFt: f64 := 12000.0;
var tasKt: f64 := 260.0;
var bank: f64 := 25.0;
PrintLn(StrConcat("Anflug 090: ", AvEinflugName(AvEinflugverfahren(einflugkurs, 90.0, true))));
PrintLn(StrConcat("Anflug 270: ", AvEinflugName(AvEinflugverfahren(einflugkurs, 270.0, true))));
PrintLn(StrConcat("Anflug 030: ", AvEinflugName(AvEinflugverfahren(einflugkurs, 30.0, true))));
PrintLn(StrConcat("max. IAS: ",
StrConcat(FloatToStr(AvMaxWartegeschwindigkeitKt(hoeheFt), 0), " kt")));
PrintLn(StrConcat("Runde: ",
StrConcat(FloatToStr(AvRundenzeitMin(hoeheFt, tasKt, bank), 2), " min")));
PrintLn(StrConcat("je Runde: ",
StrConcat(FloatToStr(AvRundenverbrauchKg(hoeheFt, tasKt, bank, 1800.0), 0), " kg")));
PrintLn(StrConcat("mit 1200 kg: ",
StrConcat(IntToStr(AvMoeglicheRunden(1200.0, hoeheFt, tasKt, bank, 1800.0)), " volle Runden")));
PrintLn(StrConcat("Breite: ",
StrConcat(FloatToStr(AvSchleifenbreiteNm(tasKt, bank), 1), " NM")));
return 0;
}
Anflug 090: direkt
Anflug 270: parallel
Anflug 030: versetzt
max. IAS: 230 kt
Runde: 5.06 min
je Runde: 152 kg
mit 1200 kg: 7 volle Runden
Breite: 4.2 NM
Das Einflugverfahren ist die einzige wirklich knifflige Stelle: die Sektorgrenzen sind nicht symmetrisch (180° direkt, 110° parallel, 70° versetzt). Wer die 110 und die 70 vertauscht, bekommt in einem schmalen Bereich das falsche Verfahren — und merkt es nicht, weil die anderen Richtungen weiter stimmen. Die Konvention der Unit steht auf der Unit-Seite: einflugkursGrad ist der Kurs auf dem Anflugschenkel zum Fix.
„Wie viele Runden erlaubt der Treibstoff„ verbindet die Schleife mit der Vorhersage: jede Runde ist ein AvVorhersageZeitabschnitt.
std.aero enthält kein Flughandbuch. Diese Kennzahlen sind musterabhängig und müssen von außen kommen:
| Größe | Wofür | Größenordnung Verkehrsflugzeug |
|---|---|---|
| Gleitzahl im Sinkflug | T/D, Zwangspunkte | 15 bis 18 |
| Steigraten unten/oben | Steigprofil | 2500 / 500 fpm |
| Verbrauch unten/oben | Profil und Vorhersage | musterabhängig |
| Schub und Widerstand | Steigrate, Dienstgipfelhöhe, Drift-Down | in Newton |
| W/δ im Optimum | optimale Reiseflughöhe | musterabhängig |
| Verzögerung im Leerlauf | DECEL-Punkt | 10 bis 20 kt/min |
Ein eingebauter „typischer“ Wert wäre für jedes andere Muster falsch und würde nirgends auffallen — deshalb gibt es ihn nicht.
W/δ ist im Optimum konstant. Wird das Flugzeug leichter, muss δ kleiner werden — die beste Höhe steigt im Verlauf des Fluges. Genau deshalb gibt es Stufensteigflüge:
var optM: f64 := AvOptimaleHoeheM(masseKg, wProDeltaOptN);
var gewinn: f64 := AvStufensteigGewinnM(masseVorherKg, masseNachherKg, wProDeltaOptN);
Wer die Reiseflughöhe als feste Zahl führt, fliegt die zweite Hälfte zu tief — und bezahlt das im Verbrauch.
Ob eine Stufe sich lohnt, ist eine Kostenfrage, keine Höhenfrage: AvGesamtkostenKgAequiv und AvGuenstigere vergleichen zwei Angebote bei gegebenem Cost Index. CI 0 heißt „Treibstoff ist alles„ (maximale Reichweite), ein hoher CI „Zeit ist teuer“.
Beides sind Sinkprofile, nur mit anderem Anlass — die erste Rechnung sucht eine Höhe, die zweite eine Zeit:
| Fall | Funktionen |
|---|---|
| Drift-Down nach Triebwerksausfall: auf welche Höhe sinkt das Flugzeug, und reicht sie über die Berge? | AvDriftDownHoeheFt, AvDriftDownFreigaengig |
| Notabstieg bei Druckverlust: wie lange bis zur atembaren Höhe, und reicht der Sauerstoff? | AvNotabstiegZeitMin, AvNotabstiegStreckeNm, AvSauerstoffReicht |
AvDriftDownFreigaengig prüft zwei Seiten: die erreichbare Höhe und den geforderten Abstand darüber. AvSauerstoffReicht rechnet den Abstieg und den anschließenden Flug in der Zwischenhöhe — die Frage, die über die zulässige Streckenführung entscheidet.
Dazu passen die Umkehrpunkte aus std.aero.perf: AvPunktGleicherZeitNm (von hier dauert Weiterfliegen so lang wie Umkehren) und AvPunktOhneWiederkehrNm (der letzte Punkt, von dem der Treibstoff zur Rückkehr reicht). Über Wasser sind das die beiden Zahlen, die die Streckenführung bestimmen — und der Wind verschiebt sie erheblich, weil er in eine Richtung hilft und in die andere bremst.
Die Reihenfolge, in der ein Rechner die Seite füllt:
AvUebergangshoeheFt).AvGrundgeschwindigkeitKt.
Und über allem: Fehlerwerte prüfen. Jede Funktion liefert bei unsinniger Eingabe NaN (AvIsError) oder false. Ein FMS, das eine unmögliche Lage still in eine plausible Zahl übersetzt, ist gefährlicher als eines, das gar nichts anzeigt.
Letzte Aktualisierung: 2026-09-05 — Seite neu angelegt; alle Beispiele gegen lyxc 1.1.18A übersetzt und ausgeführt, die Ausgaben stammen aus dem Lauf.
Prüflauf 2026-09-05 mit doku-pruefer.py über den gesamten Aero-Bereich (Repo-Compiler lyxc 1.2.2A): 13 Vollprogramme, 13 übersetzen, 0 echte Fehler; 193 Aufrufe gegen die pub fn-Signaturen in aurum/std gehalten, 0 Abweichungen.