Horizontmasken und Himmelsgeometrie
Bis 0,36 war jeder Sichtbarkeitstest zur Erde in der Engine ein einziger Elevationsgrenzwert, mask_deg: Ein Satellit zählte, wenn er auf oder über einer Zahl lag, gleich in welcher Richtung. Eine Straße, ein Kai, ein Fjord oder ein Kran verdeckt einen Teil des Himmels und lässt den Rest offen. Ein Skyline ist ein vom Azimut abhängiger Elevationsschnitt; die Himmelsgeometrie-Funktionen machen aus einem Standort, einer Zeit, Konstellationen und einer Skyline die sichtbare Menge, die Dilution of Precision (DOP), die Geometriekovarianz, die horizontale Fehlerellipse, eine Monte-Carlo-Wolke und ein Skyplot. Der Entwurf ist docs/design/2026-10-12-geometry-and-skyline-design.md (Punkte 1 und 2).
Evidenz: Die maskierte Sichtbarkeitsentscheidung (geodätische Blickwinkel, die Tabellenmaske, die sichtbare Menge und deren DOP) ist gegen Orekit 12,2 und gnss_lib_py 1.0.4 in einem vorab registrierten Vergleich VALIDATED, ebenso die Fehlerellipse und der Kofaktor je System (numpy, vorab registriert); die Reduktionen für Schlucht, Sektor und Gelände, die Voreinstellungen und die übrigen Himmelsgeometrie-Funktionen sind MODELLED (Evidenz). Eine Skyline entfernt Satelliten in Sichtlinie und nichts weiter. Die Voreinstellungen sind REPRESENTATIVE Geometrien, keine Vermessungen.
Die Skyline#
Eine Skyline ist das punktweise Maximum aus vier Beschreibungen. Der Azimut ist in Grad im Uhrzeigersinn von geografisch Nord im lokalen Ost-Nord-Oben-System des Standorts angegeben; Elevationen liegen in [0, 90).
| Beschreibung | TOML | Was es ist |
|---|---|---|
| Tabelle | table = [[az, el], ...] |
Elevationen, linear im Azimut interpoliert und bei 360° umgebrochen. Azimute streng aufsteigend in [0, 360); höchstens 3600 Zeilen. |
| Straßenschlucht | street_az_deg, width_m, height_left_m, height_right_m, antenna_m, length_m |
Zwei gerade, parallele Wände (unten). |
| Sektoren | sectors = [{ az_from, az_to, el_deg }] |
Scharfkantige Intervalle, im Uhrzeigersinn von az_from (eingeschlossen) bis az_to (ausgeschlossen), die durch Nord laufen dürfen; höchstens 360. |
| Gelände | terrain = [{ az, distance_m, height_m }] |
Auf eine Tabelle reduzierte Punkte: Elevation atan((height_m − d²/(2 R_eff)) / d), mit dem Krümmungsabfall für R_eff = 4/3 × 6371 km (eine gewählte, angegebene Konstante). height_m liegt über der Antenne. |
preset = "<name>" geht von einer benannten Geometrie aus; die Schluchtfelder überschreiben dann die Schlucht der Voreinstellung Feld für Feld, und table, sectors und terrain kommen hinzu.
Das mask_deg des Empfängers behält seine Bedeutung: Es ist eine flache Skyline. Der wirksame Schnitt beim Azimut az ist max(mask_deg, skyline(az)), und ein Satellit ist sichtbar, wenn seine Elevation auf oder über diesem Wert liegt: dasselbe >=, das die flache Maske immer verwendet hat. Ein Satellit über mask_deg, aber unter der Skyline, ist durch die Skyline maskiert.
Die Straßenschlucht#
Eine Straße verläuft entlang des Azimuts s, w Meter zwischen den Wänden, die Antenne befindet sich a Meter hoch auf der Mittellinie. Entlang des Azimuts az, mit θ = az − s, erreicht der Strahl nach d(az) = (w/2) / |sin θ| eine Wand, sodass eine Wand der Höhe h bei folgendem Wert schneidet
cut(az) = atan( (h − a) / d(az) ) (the right wall for sin θ > 0, the side at s + 90°)
Der offene Streifen liegt entlang der Straße. Bei length_m = L (Antenne in der Mitte) verlässt ein Strahl die Schlucht durch ein offenes Ende, und die Wand schneidet nichts, wenn d(az) · |cos θ| > L/2. Eine Wand, die nicht höher als die Antenne ist, schneidet nichts. antenna_m beträgt standardmäßig 1,5 m (ein Autodach oder ein Handempfänger, eine angegebene Wahl); eine neue Schlucht braucht width_m.
Voreinstellungen#
Gewählte und angegebene Abmessungen (die der Entwurfsnotiz), keine Vermessungen eines realen Ortes. kshana skyline --preset <name> gibt eine mit ihrer Herkunft und ihrem Schnitt für jedes Grad aus.
| Voreinstellung | Geometrie | Herkunft |
|---|---|---|
city-street |
Schlucht: Straße 0°, Breite 20 m, Wände 30 m und 30 m, Antenne 1,5 m. 70,7° quer zur Straße, entlang dieser offen. | Verhältnis von Höhe zu Breite 1,5, innerhalb des Bandes von 0,5–2 für Seitenverhältnisse von Straßenschluchten bei Oke (1988), Street design and urban canopy layer climate, Energy and Buildings 11, 103–113. |
harbour-approach |
Sektoren: zur Seeseite offen über 090–270 (180°); Kaigebäude 8° über 315–045 (90°); der Wellenbrecher und sein Leuchtfeuer 3° über 045–090 und 270–315. | Gewählte Annahmen (zum Beispiel 40-m-Lagerhallen in etwa 285 m Entfernung). |
fjord |
Gelände: Wände 600 m über der Antenne in 1500 m Abstand beiderseits einer Nord-Süd-Rinne, ein Punkt je Grad (bei 1500/|sin az| m), Krümmungsabfall angewendet. 21,8° quer dazu, unter 1° entlang der Achse. |
Von der Größenordnung her entsprechen Breite und Relief der tiefen westnorwegischen Fjorde (Holtedahl (1967), Notes on the formation of fjords and fjord-valleys, Geografiska Annaler 49A, 193–203). |
container-terminal |
Sektoren: Containerstapel 12° über der landseitigen Hälfte 000–180; Kranausleger 35° über 245–255 und 25° über 285–295; sonst zum Wasser offen. | Fünf ISO-668-High-Cube-Container (14,5 m) in etwa 60 m Entfernung von einer Antenne in 2 m Höhe; ein Ausleger etwa 50 m über dem Kai bei 70 m und 100 m, in der Größenordnung eines Post-Panamax-Krans. Ein Kransektor ist undurchsichtig. |
In einem Szenario#
Ein optionaler Abschnitt [skyline], über dem eigenen Grenzwert der Art:
| Typ | Was die Skyline ändert | Je Stichprobe |
|---|---|---|
orbit (mit user_site) |
Die Sichtbarkeitszeitreihe (GNSS-Verfügbarkeit) und die DOP-Zusammenfassung. | — |
integrity (mit user_site) |
Die Satelliten, die RAIM und ARAIM (araim_dual) verwenden. |
epochs[].masked_by_skyline |
gnss-sim |
Die Satelliten, deren Pseudoentfernungen simuliert und von RAIM verwendet werden. | gnss_measurements[].masked_by_skyline |
jamming |
Die Satelliten, die der Empfänger verfolgen kann, vor dem Störsender. | epochs[].masked_by_skyline |
leo-pvt |
Die Menge der sichtbaren Satelliten jedes Modus über der Maske des jeweiligen Systems, einschließlich des Polarsweeps (dieselbe Skyline an jedem Standort). Die Hüllkurve des Doppler-Modus und der entworfene einzelne Überflug sind Grenzen dessen, was ein Empfänger bewältigen muss, und behalten die Maske jedes Systems. | joint.epochs[].masked_by_skyline |
leo-pass |
Welche Epochen als über der Maske gelten, die Zeit darüber, die Satelliten des GNSS-Vergleichs. | satellites[].pass.epochs_masked_by_skyline |
nmea-scenario (Trainings-NMEA) |
Die Satelliten in GSV und in der Lösung. Azimute sind am Boden festgelegte wahre Peilungen, nicht der Kurs des Schiffes. | — |
Der Bodenstandort von orbit und integrity. Beide Arten modellieren einen umlaufenden Nutzer mit geozentrischer Elevation und ohne erdfesten Azimut, sodass sie eine Skyline nur mit dem Bodenstandort-Modus der Entwurfsnotiz annehmen: user_site = { lat_deg, lon_deg, height_m } anstelle von user (genau eines von beiden). Jede Stichprobe ist ein absoluter Zeitpunkt, epoch + t: Jeder Satellit wird dorthin propagiert (ein Elementsatz, eine Broadcast-Ephemeride oder eine SP3-Datei wird von der eigenen Epoche aus fortgeschrieben, ein Walker-Satellit zählt t ab epoch) und dort in erdfeste Koordinaten gedreht, sodass der Standort einen einheitlichen Himmel sieht. epoch ist die des Bahnszenarios selbst; ohne eine (und immer bei integrity, das keine hat) ist es die neueste Epoche unter den Satelliten, die eine tragen, oder J2000 nur für Walker-Muster. Elevation und Azimut sind geodätisch (WGS-84). Die Aufteilung der ARAIM-Schutzniveaus und des Stanford-Vertikalfehlers der Integritätsart in horizontal und vertikal verwendet dasselbe geodätische Oben (die Normale des WGS-84-Ellipsoids, bei 45° Breite etwa 0,19° von der geozentrischen Radialen entfernt); Snapshot-RAIM verwendete es bereits. Ein user_site ohne Skyline ist ein gewöhnlicher Bodennutzer; der Pfad des umlaufenden user bleibt unverändert.
kind = "integrity"
mask_deg = 5.0
# ...
[user_site]
lat_deg = 59.45
lon_deg = 24.75
height_m = 15.0
[skyline]
preset = "harbour-approach"
Rückwärtskompatibilität. Ohne einen Abschnitt [skyline] ist ein Szenario byteidentisch mit dem, was dieselbe Engine vor dem Skyline-Code lieferte: tests/skyline_scenarios.rs prüft JSON, Diagramm und Zusammenfassung jedes mitgelieferten Szenarios, das eine dieser Arten ausführt, und den NMEA-Text jedes Trainingsszenarios gegen SHA-256-Digests der Basislinie „0,36 portable“ (die Digests des Release-Commits 0.35.0, neu festgelegt, als die Engine auf portable Mathematik umgestellt wurde, und im Test als Aufzeichnung festgehalten: docs/revisions/STUDIO15-portable-math-rebaseline.md). Ein leerer Abschnitt [skyline] schneidet nichts; das Ergebnis entspricht dann dem Lauf ohne ihn, bis auf den hinzugefügten Block skyline und die Nullwerte bei masked_by_skyline.
Was zurückgewiesen wird, mit dem Grund in der Meldung: eine Skyline an einem umlaufenden user; user und user_site zusammen; eine unbekannte Voreinstellung; eine Schlucht ohne width_m; eine Tabelle, die in [0, 360) nicht streng aufsteigend ist; eine Elevation außerhalb von [0, 90); ein leerer Sektor; ein nicht positiver Geländeabstand; Eingaben über den Obergrenzen; jeder unbekannte Schlüssel.
Das Ergebnis erhält skyline: { source, open_fraction, provenance }, wenn der Abschnitt vorhanden ist: source ist preset:<name>, preset:<name>+overrides oder custom; open_fraction ist der Anteil des Raumwinkels der oberen Hemisphäre über max(mask_deg, skyline) (der Mittelwert von 1 − sin(cut) über den Azimut: 1 bei einer Maske von null, 0,5 bei einem flachen Schnitt von 30°); provenance ist die Zeile der Voreinstellung oder die des Szenarios selbst. Einheiten und Herkunftsklassen stehen im Block units.
Mitgelieferte Beispiele (kshana example <name>):
| Beispiel | Was es zeigt (zum Vergleich den Abschnitt [skyline] entfernen) |
|---|---|
orbit-urban-canyon-skyline |
GPS + Galileo am Grund von city-street: 17 von 289 Stichproben behalten eine Lösung, medianer PDOP 70,5 (1,14 bei offenem Himmel). |
integrity-harbour-approach |
ARAIM mit zwei Konstellationen bei der Einfahrt in einen Hafen: 70 Satelliten-Epochen verdeckt, Verfügbarkeit unverändert (145 von 145). |
gnss-sim-container-terminal-skyline |
Pseudoentfernungen und RAIM an einem Kai: 44 Satelliten-Epochen verdeckt; RAIM-Verfügbarkeit 0,59 (0,85 bei offenem Himmel). |
jamming-harbour-approach-skyline |
Ein Störsender mit 2 W in einem Hafen: 83 Satelliten-Epochen verdeckt, Verfolgung unverändert (der Störsender hatte sie übernommen). |
leo-pvt-fjord-skyline |
GPS + Galileo + eine LEO-Schicht in einem Fjord: medianer fusionierter PDOP 1,14 (0,93 bei offenem Himmel). |
leo-vertical-autonomous-vehicle-skyline |
Die Schlucht von leo-vertical-autonomous-vehicle als flacher Schnitt von 35° und als city-street, entlang der Fahrtrichtung des Autos gedreht: 8 gegenüber 4 bis 5 GPS- und Galileo-Satelliten; fusionierter mittlerer Fehler 2,1 m in beiden; der Alarm bei 1,5 m bei 51 % und 59 % der Epochen. |
Himmelsgeometrie#
Fünf Engine-Funktionen (src/geometry.rs), auf jeder Oberfläche dieselben:
| Funktion | Eingabe → Ausgabe |
|---|---|
sky_geometry(request) |
je Satellit id, system, az_deg, el_deg, cut_deg, visible, masked; n_visible, n_masked, open_fraction; dop (GDOP, PDOP, HDOP, VDOP, TDOP, tdop_by_clock); states, cofactor_enu (Einheitsvarianz), covariance_enu_m2; ellipse_1sigma und ellipse beim geforderten Konfidenzniveau; label, statement, advisory |
sky_monte_carlo(request, seed, n) |
n (höchstens 5000, eine Eingabeobergrenze) Kleinste-Quadrate-Fehler bei unabhängigen gaußschen Entfernungsfehlern von σ_UERE aus einem mit seed initialisierten ChaCha8-Strom: samples_enu_m, die empirische Kovarianz, horizontaler und 3-D-RMS neben σ_UERE × HDOP und σ_UERE × PDOP, der Anteil innerhalb der 95-%-Ellipse |
skyline_presets() |
die Voreinstellungen mit Bezeichnung, Beschreibung, Herkunft, dem Schnitt für jedes Grad und open_fraction |
skyline_profile(skyline) |
ein Skyline-Abschnitt, reduziert auf die Tabelle mit 360 Einträgen, die die Engine verwendet, mit source, provenance, open_fraction |
skyplot_svg(request) |
der Skyplot als statisches SVG (ohne Skript, ohne externe Referenz, jede Eingabezeichenfolge maskiert) |
Eine Anfrage:
{
"site": {"lat_deg": 59.91, "lon_deg": 10.75, "height_m": 5},
"time_s": 3600,
"systems": ["gps-baseline", "galileo", "beidou-meo", "xona-pulsar"],
"mask_deg": 5,
"skyline": {"preset": "fjord"},
"clock": "per-system",
"sigma_uere_m": 1.5,
"confidence": 0.95
}
systems sind die Konstellations-Voreinstellungen der Engine (gps-baseline, galileo, beidou-meo, glonass, ... von constellation-design; die LEO-Voreinstellungen xona-pulsar, iridium-stl, ...) oder eine vollständige leo-pvt-Tabelle [[system]], propagiert zu time_s (keplersch mit säkularem J2, die Bahnen des Verbundmodus leo-pvt). Ihre relativen Phasen stammen aus unterschiedlichen Referenzepochen, der Himmel ist also eine repräsentative Geometrie, nicht der Himmel dieses Datums an diesem Ort. Satelliten können stattdessen (oder zusätzlich) direkt angegeben werden: "satellites": [{"id": "G05", "system": "GPS", "az_deg": 120, "el_deg": 35}, ...], oder mit "ecef_m": [x, y, z] und einem site oder user_ecef_m. Standardwerte: die Maske jedes Systems (5° GNSS, 10° LEO; 5° für direkt angegebene Satelliten), eine Empfängeruhr je System ("common" für eine gemeinsame Uhr), σ_UERE 1 m (eine repräsentative Zeile eines Zweifrequenz-Budgets), Konfidenz 0,95. Eingabeobergrenzen: höchstens 2000 Satelliten über dem Horizont (eine Systemtabelle, die mehr verlangt, wird vor dem Aufbau zurückgewiesen) und 16 Empfängeruhren.
Ein datierter Himmel aus Elementsätzen. "tle" nimmt Text von Two-Line-Element-Sätzen entgegen (eine Namenszeile vor jedem Satz ist optional; höchstens 4 MiB, eine Eingabeobergrenze), propagiert vom SGP4 der Engine (WGS-72, der Propagator, den orbit-real-tle verwendet) zu "epoch" plus time_s, mit UT1 gleich UTC und ohne Polbewegung in erdfeste Koordinaten gedreht und von site aus gesehen. "epoch" ist UTC nach ISO 8601 (2026-06-07T12:00:00Z) und datiert nur die Elementsätze (die Voreinstellungen tragen kein Datum, daher wird ein epoch ohne tle zurückgewiesen); "tle_system" bezeichnet sie für die Uhr je System (Standard TLE). Jedes Ergebnis gibt in sky_source und sky_statement an, um welchen Himmel es sich handelt:
sky_source |
Der Himmel |
|---|---|
presets |
die Konstellations-Voreinstellungen der Engine: eine repräsentative Geometrie |
tle-at-epoch |
die zur angegebenen Epoche propagierten Elementsätze: der Himmel, den diese Elementsätze zu dieser Epoche ergeben, keine Messung davon (ihre eigene Genauigkeit ist die von SGP4 und das Alter der Sätze) |
tle-at-element-epoch |
kein epoch: die Elementsätze, propagiert zur eigenen Epoche des neuesten Satzes plus time_s, ein repräsentativer Himmel |
satellites |
direkt angegebene Satelliten, wie angegeben |
Eine Mischung verbindet sie mit +. epoch_utc ist der Zeitpunkt, zu dem die Elementsätze propagiert wurden, und tle_skipped nennt, was vom Text nicht verwendet wurde, mit dem Grund: fehlerhafte oder verwaiste Zeilen von Elementsätzen (mit ihren Zeilennummern), Sätze, die der Parser zurückgewiesen hat, und Sätze, die SGP4 nicht zu diesem Zeitpunkt propagieren konnte (zerfallen oder jenseits seiner Grenzen); insgesamt höchstens 100 Einträge, dann ein letzter Eintrag, der den Rest zählt. Eine leere systems-Liste fügt keine Voreinstellungen hinzu. Der Skyplot nennt die Grundlage in seiner Fußzeile.
Ein Kern. Die Kofaktormatrix ist orbit::cofactor_from_los, der Aufbau der Entwurfsmatrix und die Gauß-Jordan-Inverse hinter orbit::dop. orbit::dop_cov stellt die Kovarianz bereit und orbit::dop ist deren Reduktion, sodass die Skalare der Stufe VALIDATED unverändert sind und weiterhin durch tests/dop_reference.rs festgeschrieben werden. Es gibt keine zweite DOP-Implementierung.
Die Ellipse. Halbachsen k σ √λ für die Eigenwerte λ des Ost-Nord-Blocks, mit k = √(−2 ln(1 − p)) (√5.991 = 2.448 bei 95 %, 1 bei 39,35 %), und der Azimut der Hauptachse ½ atan2(2 Q_EN, Q_NN − Q_EE) in [0, 180) von Nord.
| Oberfläche | Einstiegspunkte |
|---|---|
| CLI | kshana sky <request.json|toml> oder kshana sky --site <lat,lon[,h]> (--systems <a,b> | --tle <file>) [--epoch] [--tle-system] [--time] [--mask] [--skyline-preset] [--uere] [--clock], mit --monte-carlo <n> --seed <s> oder --svg; kshana skyline --preset <name> | --presets | --profile <file> |
| Rust | kshana::geometry::{sky_geometry, sky_monte_carlo, skyline_presets, skyline_profile, skyplot_svg}, kshana::surface::* mit denselben Namen |
| Python | kshana.sky_geometry, sky_monte_carlo, skyline_presets, skyline_profile, skyplot_svg |
| WASM | sky_geometry(request_json), sky_monte_carlo(request_json, seed, n), skyline_presets(), skyline_profile(skyline_json), skyplot_svg(request_json) |
| MCP | sky_geometry (request oder skyline_preset); kein Monte Carlo über MCP (Massenstichproben, die ein Agent zusammenfassen und nicht mitführen sollte) |
Jedes Ergebnis trägt label (MODELLED), die statement (Geometrie unter einem angegebenen Fehlermodell: unabhängige, gleiche, mittelwertfreie gaußsche Entfernungsfehler; keine Vorhersage des realen Fehlers eines Empfängers, der außerdem Biase, Mehrwegeausbreitung und Fehler ohne Sichtverbindung hat; keine Integritätsgrenze) und den Hinweis: Beratende Software, keine typzugelassene Navigationsausrüstung (IEC 61108, IEC 61162): Der Betreiber bleibt für die Navigation des Schiffes verantwortlich.
Nachweise#
Fünf Registerzeilen (docs/VERIFICATION-MATRIX.md), wie die Entwurfsnotiz sie abgrenzt:
| Zeile | Status | Unabhängige Referenz |
|---|---|---|
| Azimutabhängige Horizontmaske: sichtbare Menge, Azimut und Elevation sowie DOP unter der Maske | VALIDATED | Orekit 12,2 (TopocentricFrame-Blickwinkel, ElevationMask) mit gnss_lib_py 1.0.4 (get_dop und die DOP-Matrix), vorab registriert in xval/orekit-skyline/PREREGISTRATION.md (Commit e4b9d912), bevor eines von beiden ausgeführt wurde: 1173 Blickwinkel an sechs Standorten und vier Epochen, sechs Tabellen, 142 sichtbare Mengen; schlechteste Elevation 1.3e-13°, Azimut 2.3e-13°, Maske 1.1e-12° gegenüber 1e-9°; identische sichtbare Mengen, keine im Grenzband; DOP 3.3e-13 relativ und Kofaktor 6.6e-13 der Matrixskala gegenüber 1e-9. Umfang: Tabellenmasken, geodätische Blickwinkel, die maskierte Menge und ihr DOP und Kofaktor bei gemeinsamer Uhr. |
| Reduktionen von Straßenschlucht, Sektor und Gelände auf eine Tabelle | MODELLED | von Hand berechnete Werte; der obige Vergleich liest deren Tabellen als Eingaben und prüft sie nicht |
| Skyline-Voreinstellungen | MODELLED | keine: gewählte, angegebene Abmessungen (nur gegen sich selbst geprüft) |
| Horizontale Fehlerellipse und Kofaktor je System aus der Geometriekovarianz | VALIDATED | numpy 2.5.4 linalg.inv und linalg.eigh (Standard P2) auf den 142 eingecheckten sichtbaren Mengen, gemeinsame Uhr und eine Uhr je System, vorab registriert in xval/numpy-ellipse/PREREGISTRATION.md (Commit 0bbeeaee): 270 Fälle, Achsen 5.1e-13 relativ, Orientierung 5.3e-12°, Kofaktor 1.0e-12 der Matrixskala, gegenüber 1e-9 und 1e-6° |
| Himmelsgeometrie-Funktionen | MODELLED | die Komposition: Propagation der Voreinstellung zu einem repräsentativen Himmel, die Monte-Carlo-Wolke (gegen die Geometrie geprüft, die sie abtastet), die Oberflächen |
Das Fehlen eines Abschnitts [skyline] wird Byte für Byte gegen die Ausgaben von 0.35.0 geprüft, was Rückwärtskompatibilität zeigt und nichts validiert. gnss_lib_py wendet nur eine einzige Elevationsmaske an und ist hier daher die Referenz für DOP, nicht für die Maske.
Was eine Skyline nicht modelliert: Beugung über einer Wandkante, Reflexionen und Signale ohne Sichtverbindung, die ein realer Empfänger womöglich dennoch verfolgt (sie werden verworfen, nicht verschlechtert), teilweise Durchlässigkeit (ein Gitterkran ist über seinen Sektor hinweg undurchsichtig), Gelände jenseits der angegebenen Punkte und die Erdkrümmung innerhalb der Schlucht- und Sektorformen.