std.geodesy.frames — geodätisch, ECEF, ENU, NED

import std.geodesy.frames;

Die Umrechnung zwischen den vier Bezugsrahmen: geodätische Koordinaten (Breite, Länge, Höhe), erdfestes ECEF und die beiden örtlichen Rahmen ENU und NED.

std.geodesy Übersicht · std.geodesy.ellipsoid · Guide: Kurs und Lage im 3D-Raum


1. Geodätische Koordinaten

pub type Geodetic = struct { latRad: f64; lonRad: f64; hEll: f64; }

Signatur Zweck
GeodNew(latRad, lonRad, hEll): Geodetic aus Bogenmaß
GeodFromDeg(latDeg, lonDeg, hEll): Geodetic aus Grad — der übliche Einstieg
GeodLatDeg(g: Geodetic): f64 · GeodLonDeg(g: Geodetic): f64 zurück in Grad

hEll ist die Höhe über dem Ellipsoid, nicht über dem Meeresspiegel. Der Unterschied (Geoidundulation) beträgt in Mitteleuropa rund 45 m — wer eine GPS-Höhe unbesehen als Höhe über NN nimmt, liegt genau um diesen Betrag daneben. Ein Geoidmodell bringt diese Unit nicht mit.


2. Geodätisch ↔ ECEF

Signatur Zweck
GeodToEcef(e: Ellipsoid, g: Geodetic): V3 nach erdfest-kartesisch
EcefToGeod(e: Ellipsoid, p: V3): Geodetic zurück

Die Rückrechnung ist der schwierigere Weg — die Breite steht in einer Gleichung, die sich nicht geschlossen auflösen lässt. Die Umrechnung hin und zurück trifft im Test wieder denselben Wert (53.63040053.630400).

Drei Proben, die man nachrechnen kann

45N/45O:   3194419.145 | 3194419.145 | 4487348.409
Aequator:  6378137.000 |       0.000 |       0.000
Nordpol:          0.000 |       0.000 | 6356752.314

  • 45° N / 45° O stimmt bis auf drei Nachkommastellen mit dem Literaturwert überein — die übliche Kontrollstelle, weil dort x und y gleich groß sein müssen.
  • Am Äquator ist x genau die große Halbachse (EllWgs84().a = 6378137.000), y und z sind null.
  • Am Pol ist z genau die kleine Halbachse (EllB(e) = 6356752.314).

Diese drei Fälle sind die schnellste Probe, ob ein Ellipsoid richtig eingesetzt und die Breite nicht versehentlich in Grad statt Bogenmaß übergeben wurde: schon ein vertauschtes Winkelmaß verschiebt den Äquatorpunkt um Tausende Kilometer.

ECEF ist die Drehscheibe dieser Unit: alles andere führt über diesen Rahmen.


3. Örtliche Rahmen

Signatur Zweck
EcefToEnu(e: Ellipsoid, origin: Geodetic, p: V3): V3 ECEF → Ost, Nord, Oben
EnuToEcef(e: Ellipsoid, origin: Geodetic, enu: V3): V3 zurück
EcefToNed(e: Ellipsoid, origin: Geodetic, p: V3): V3 ECEF → Nord, Ost, Unten
NedToEcef(e: Ellipsoid, origin: Geodetic, ned: V3): V3 zurück
EnuToNed(enu: V3): V3 · NedToEnu(ned: V3): V3 direkt umtauschen
 
ENU und NED unterscheiden sich in zwei Dingen: die ersten beiden Achsen sind vertauscht, und die dritte hat das umgekehrte Vorzeichen. EnuToNed rechnet (e, n, u) → (n, e, −u).

Das Vorzeichen ist die Falle: wer ENU-Werte als NED liest, bekommt eine Höhe, die unter der Erde liegt — und in einer Regelschleife eine Steuergröße mit falschem Vorzeichen. Luftfahrt und Regelungstechnik rechnen in NED, Vermessung und Antennentechnik in ENU.


4. Sichtlinie

Signatur Zweck
EnuAzimuth(enu: V3): f64 Azimut in Bogenmaß, von Nord über Ost
EnuElevation(enu: V3): f64 Erhebungswinkel über der Horizontebene
EnuSlantRange(enu: V3): f64 Schrägentfernung — die Luftlinie, nicht die Grundstrecke

5. Beispiel

unit main;
import std.coordinates.vec3;
import std.coordinates.transform;
import std.geodesy.ellipsoid;
import std.geodesy.frames;
import std.io;
import std.string;

fn main(): int64 {
    var e:  Ellipsoid := EllWgs84();
    var hh: Geodetic  := GeodFromDeg(53.6304, 9.9882, 0.0);
    var zz: Geodetic  := GeodFromDeg(53.5511, 9.9937, 0.0);

    var enu: V3 := EcefToEnu(e, hh, GeodToEcef(e, zz));

    PrintLn(StrConcat("Ost (m):      ", FloatToStr(enu.x, 1)));
    PrintLn(StrConcat("Nord (m):     ", FloatToStr(enu.y, 1)));
    PrintLn(StrConcat("Azimut (Grad):", FloatToStr(RadToDeg(EnuAzimuth(enu)), 2)));
    PrintLn(StrConcat("Entfernung:   ", FloatToStr(EnuSlantRange(enu), 1)));
    return 0;
}

Ost (m):      363.4
Nord (m):     -8825.9
Azimut (Grad):177.63
Entfernung:   8833.4

Nord ist negativ, weil das Ziel südlich liegt — und der Azimut 177,6° sagt dasselbe noch einmal. Beides zusammen ist die Probe, ob der Rahmen richtig herum steht.


Letzte Aktualisierung: 2026-09-07 — Abschnitt „Drei Proben„ ergänzt: 45°N/45°O gegen den Literaturwert, Äquator gegen die große und Pol gegen die kleine Halbachse; nachgemessen mit lyxc 1.2.2D.

Vorherige letzte Aktualisierung: 2026-09-06 — Seite neu angelegt; erhoben aus std/geodesy/frames.lyx, Beispiel gegen lyxc 1.2.2D übersetzt und ausgeführt.