Maschinelle Übersetzung, nicht von einem Muttersprachler geprüft. Englisch ist die maßgebliche Fassung.

Empfängervertrauen und SeefahrtAuf GitHub bearbeitenQuelle: docs/RECEIVER-TRUST.md

Empfängervertrauen: ein reales GNSS-Empfänger-Log bewerten

kshana receiver-trust liest ein Log eines realen Empfängers eines globalen Satellitennavigationssystems (GNSS), lässt Vertrauensmonitore Epoche für Epoche darüber laufen und sagt, wann und warum die Lösung des Empfängers aufhörte, vertrauenswürdig zu sein. Es kann das Log auch gegen Ereignisse und Vorhersagen bewerten, die Sie vor dem Lauf angeben: ob jedes Ereignis rechtzeitig erkannt wurde und ob ein modellierter Abfall der Träger-zu-Rauschleistungsdichte (C/N0) mit dem übereinstimmt, was der Empfänger gemessen hat.

Die Observablen sind die des Empfängers selbst; die Monitore und ihre Schwellen sind die der Engine und Ihre. Jedes Ergebnis trägt diese Kennzeichnung, den SHA-256 des Logs und jede Schwelle, mit der es lief, sodass ein Lauf wiederholt und geprüft werden kann.

Für ein Schiff unterwegs, mit einer Live-Bewertung und einem optionalen Gate vor einem Kartensystem, siehe MARITIME-TRUST.md.

Das eigene Spoofing-Flag des Empfängers gegen die Alarme von Kshana, aus einem echten Lauf der Engine v0.40.0 auf einem erfundenen UBX-Protokoll (200 Epochen bei 1 Hz). C/N0 fällt bei 80 bis 90 s und 120 bis 130 s um 20 dB; der Empfänger markiert 120 bis 130 s und 160 bis 165 s. Von 140 nach der Kalibrierung verglichenen Epochen markierten 11 beide, 6 nur der Empfänger, 11 nur Kshana und 112 keiner. Keine der beiden Seiten ist Referenzwahrheit, und Übereinstimmung ist keine Validierung. Beratend: Analyseausgabe eines Forschungs- und Entwicklungswerkzeugs, keine typzugelassene Navigationsausrüstung und kein Dienst für die Sicherheit von Menschenleben.Das eigene Spoofing-Flag des Empfängers gegen die Alarme von Kshana, aus einem echten Lauf der Engine v0.40.0 auf einem erfundenen UBX-Protokoll (200 Epochen bei 1 Hz). C/N0 fällt bei 80 bis 90 s und 120 bis 130 s um 20 dB; der Empfänger markiert 120 bis 130 s und 160 bis 165 s. Von 140 nach der Kalibrierung verglichenen Epochen markierten 11 beide, 6 nur der Empfänger, 11 nur Kshana und 112 keiner. Keine der beiden Seiten ist Referenzwahrheit, und Übereinstimmung ist keine Validierung. Beratend: Analyseausgabe eines Forschungs- und Entwicklungswerkzeugs, keine typzugelassene Navigationsausrüstung und kein Dienst für die Sicherheit von Menschenleben.

Ausführen#

kshana receiver-trust examples/receiver-trust/session.toml

Das schreibt session.result.json, session.trust.csv (eine Zeile je Epoche) und session.trust.svg (mittleres C/N0 über der Zeit mit dem Vertrauenszustand darunter) neben das Szenario und gibt ein einzeiliges Urteil aus. Das Beispiel-Log ist synthetisch und soll das Format zeigen; richten Sie path auf das Log Ihres eigenen Empfängers.

Vertrauenswert über eine synthetische Passage, aus einem echten Lauf der Engine v0.40.0 auf examples/maritime-trust (ein erfundenes NMEA-Log einer Fähre auf einer Route von Tallinn nach Helsinki, 3001 Epochen bei 1 Hz). Drei Spuren teilen sich eine Zeitachse. Oben: der Abstand zwischen der vom Empfänger gemeldeten Position und der echten Position des Schiffes, der bis etwa 1576 s innerhalb weniger Meter bleibt, als das skriptgesteuerte Wegziehen der Position des Logs ihn vergrößert, während der Empfänger weiter eine gültige Lösung meldet. Mitte: der Vertrauenswert von 0 bis 100, während der ersten 300 s der Kalibrierung nicht berechnet, im Band nominal (mindestens 90) bis zum Wegziehen, dann durch das Band degraded (mindestens 55) in das Band untrusted fallend. Unten: das Band jeder Epoche als farbiges Band mit seinem Namen. Der Wert ist beratend. Beratende Software, keine typzugelassene Navigationsausrüstung (IEC 61108, IEC 61162): Der Betreiber bleibt für die Navigation des Schiffes verantwortlich. Das Log ist erfunden, um das Format und die Monitore zu zeigen; es ist keine Messung und sagt nichts darüber aus, wie sich irgendein Empfänger schlagen würde.Vertrauenswert über eine synthetische Passage, aus einem echten Lauf der Engine v0.40.0 auf examples/maritime-trust (ein erfundenes NMEA-Log einer Fähre auf einer Route von Tallinn nach Helsinki, 3001 Epochen bei 1 Hz). Drei Spuren teilen sich eine Zeitachse. Oben: der Abstand zwischen der vom Empfänger gemeldeten Position und der echten Position des Schiffes, der bis etwa 1576 s innerhalb weniger Meter bleibt, als das skriptgesteuerte Wegziehen der Position des Logs ihn vergrößert, während der Empfänger weiter eine gültige Lösung meldet. Mitte: der Vertrauenswert von 0 bis 100, während der ersten 300 s der Kalibrierung nicht berechnet, im Band nominal (mindestens 90) bis zum Wegziehen, dann durch das Band degraded (mindestens 55) in das Band untrusted fallend. Unten: das Band jeder Epoche als farbiges Band mit seinem Namen. Der Wert ist beratend. Beratende Software, keine typzugelassene Navigationsausrüstung (IEC 61108, IEC 61162): Der Betreiber bleibt für die Navigation des Schiffes verantwortlich. Das Log ist erfunden, um das Format und die Monitore zu zeigen; es ist keine Messung und sagt nichts darüber aus, wie sich irgendein Empfänger schlagen würde.

Die Abbildung oben ist die Schiffsdemo aus MARITIME-TRUST.md: ein erfundenes Log, eine beratende Bewertung.

Dasselbe Szenario läuft aus Python (kshana.receiver_trust(toml)), aus dem WebAssembly-Paket (receiver_trust(toml), mit dem Log inline) und aus dem Werkzeug assess_receiver_log des Model-Context-Protocol-(MCP-)Servers.

Logs, die es liest#

format Quelle Was gelesen wird
ubx u-blox binär NAV-SAT: C/N0, Elevation und Azimut je Satellit; NAV-PVT: Position; MON-RF: automatische Verstärkungsregelung (AGC) und der Jamming-Indikator jamInd; NAV-TIMEGPS: Woche; und die eigenen Kennzeichen des Empfängers: NAV-STATUS spoofDetState und SEC-SIG (self_report, siehe RECEIVER-PROTOCOLS.md)
rinex RINEX-3-Beobachtungsdatei Codes S (C/N0) je Satellit und Signal; mit einer Broadcast-Navigationsdatei (nav) die Pseudoentfernungen für die eigene Lösung der Engine
android Android-GnssLogger-CSV Zeilen Raw: C/N0 und AgcDb je Satellit; Zeilen Fix: Position
nmea NMEA-0183-Text GSV: Signal-Rausch-Verhältnis je Satellit (dB-Hz, mit oder ohne die Signal-ID 4,10) und seine Elevation und sein Azimut; GSA: Dilution of Precision und verwendete Satelliten; GGA und RMC: Zeit und Position
sbf Septentrio binär (0,38, nur lesend) PVTGeodetic: Position; MeasEpoch: C/N0 je Satellit und Signal; RFStatus: Zahl der Bänder; siehe RECEIVER-PROTOCOLS.md
rtklib-pos RTKLIB-Lösungsdatei (.pos) Zeit, Position (Breite/Länge oder ECEF, umgerechnet) und verwendete Satelliten je Epoche; Dateien in Grad-Minuten-Sekunden werden mit einer Meldung zurückgewiesen
novatel NovAtel-OEM7-ASCII- oder Binär-Logs Position BESTPOS (nur berechnete Lösung), C/No RANGE je Satellit und Signal; Störsender-Kennzeichen RXSTATUS werden zum self_report der Epoche (Jamming-Zustand 2, wenn der Empfänger einen Störsender kennzeichnet, 1, wenn nicht; in RXSTATUS gibt es kein Spoofing-Kennzeichen), gegen die Alarme von Kshana gehalten durch den Vergleich receiver-self-report
gnss-sdr GNSS-SDR-Monitor- und PVT-Monitor-Ströme als JSON-Zeilen C/N0 je Kanal, Lösung, verwendete Satelliten, HDOP, Azimut und Elevation; erzeugt von integrations/gnss-sdr/relay.py

Einzelheiten, Quellen und Grenzen dieser drei: MACHINE-INPUTS.md.

Jede von den Lesern erzeugte Epoche trägt außerdem source_span, [start, end) Byte-Offsets in die Eingabe: der kleinste zusammenhängende Bereich, der die zu ihr beitragenden Datensätze enthält, sodass das genaue Roh-Stück für ein Ereignisfenster gehasht werden kann. NMEA: jede Zeile, die gelesen wird, solange die Epoche aktuell ist (eine Obermenge, wo eine fremde Zeile zwischen ihren Sätzen steht). UBX: die Frames der Epoche. RINEX 3: die Epochendatensätze von jeder Zeile > bis zur nächsten. Android: die Zeilen Raw der Epoche (eine Zeile Fix nur für eine Epoche ohne Zeilen Raw). Fehlt bei einem Live-Strom und überall, wo er nicht wohldefiniert ist (RINEX 2).

Die Datei kommt über path hinein (aufgelöst relativ zum eigenen Ordner des Szenarios) oder inline als text oder base64 (die einzigen Möglichkeiten in einem Browser).

Ein IMU-Log als zweiter Sensor#

[log.imu] fügt ein Inertial-Log auf derselben Uhr hinzu:

[log.imu]
format = "csv"          # or "euroc"
path = "imu.csv"        # or text / base64
heading0_deg = 90.0     # heading at the first IMU sample
yaw_axis_down = true    # body z down (NED/FRD); false for z up (ENU/FLU)
time_offset_s = 0.0     # added to the IMU clock to reach the log's t_s

Die Gierrate wird ab heading0_deg integriert und füllt den Kurs überall dort, wo das Empfänger-Log keinen enthält, sodass der Monitor heading-course (der heading_sensor = true an der Plattform braucht) den Kreiselkurs mit dem Kurs über Grund vergleicht. Ein Kreisel driftet: Der Kurs ist nur so gut wie das Integrationsfenster, und hdg_cog_tol_deg entscheidet, was als Abweichung zählt. Das Layout csv ist in MACHINE-INPUTS.md dokumentiert. Die IMU-Bytes sind Teil des Szenario-Hashs und des Szenario-Hashs eines Nachweispakets. Inline (text/base64) funktioniert auf jeder Oberfläche; ein path wird dort zurückgewiesen, wo keine Dateien gelesen werden.

Plattform: statisch oder Schiff#

Die obigen Monitore gehen von einer festen Antenne aus. Ein Szenario gibt die Plattform vor dem Lauf in einer Tabelle [platform] auf oberster Ebene an; ohne sie ist die Plattform static, und nichts ändert sich.

[platform]
kind = "vessel"            # "static" (default) or "vessel"
max_speed_kn = 30.0        # default 30
max_accel_mps2 = 0.5       # default 0.5
max_turn_rate_dps = 6.0    # default 6
antenna_height_m = 18.0    # no default: without it the sea-level monitor does not run
heading_sensor = false     # true: the stream carries a gyro heading (HDT or THS)
Schlüssel Standard Warum dieser Wert
max_speed_kn 30 Über der Dienstgeschwindigkeit von Handelsschiffen und den meisten Passagierfahrzeugen, sodass ein reales Schiff sie nie erreicht; weit unter der Geschwindigkeit, die ein Wegziehen der Position impliziert. Ein langsameres Schiff sollte eine niedrigere Grenze angeben: Je niedriger die Grenze, desto früher wird ein Wegziehen bemerkt.
max_accel_mps2 0.5 Ein großes Schiff ändert seine Geschwindigkeit um weit weniger als 0,1 m/s²; ein kleines schnelles Fahrzeug erreicht bei einer harten Gasänderung einige Zehntel.
max_turn_rate_dps 6 Ein großes Schiff dreht mit weit weniger als 1 Grad/s und ein kleines Fahrzeug in einer harten Kurve mit einigen.
antenna_height_m keine Eine Eigenschaft der Installation; eine Schätzung wäre eine versteckte Schwelle.
heading_sensor false Als true deklariert und im Log nicht vorhanden ist ein Fehler, sodass ein fehlender Sensor nicht als saubere Prüfung durchgehen kann.

Die Schiffsschlüssel werden unter kind = "static" zurückgewiesen. Für ein Schiff läuft der Monitor position-jump nicht, weil er den Abstand vom Kalibriermittel misst, was bei einer bewegten Antenne falsch ist; das monitor_config des Ergebnisses hält die Plattform und die verwendeten Grenzen fest.

Die synthetischen NMEA-Ströme aus kshana nmea-scenario, für die Besatzungsschulung erzeugt, werden vom NMEA-Leser akzeptiert und können wie jedes NMEA-Log durch diese Art laufen.

Monitore#

Jeder Monitor braucht seine Daten; ein Monitor, dessen Daten nicht im Log stehen, läuft nicht und wird nicht in monitors_run aufgeführt. Die ersten calibration_s Sekunden (Standard 60) legen die Basislinie fest und lösen nie Alarm aus.

Monitor Alarm, wenn Benötigt
cn0-drop das mittlere C/N0 über die mit der Basislinie gemeinsamen Satelliten um cn0_drop_db oder mehr fällt (Standard 6 dB) C/N0
loss-of-lock die verfolgten Satelliten um sats_lost oder mehr unter den Median der Basislinie fallen (Standard 4) C/N0
agc der AGC-Wert um mehr als agc_k_sigma Standardabweichungen von seiner Basislinie abweicht (Standard 5) UBX MON-RF oder Android AgcDb
jam-ind u-blox jamInd jam_ind_threshold überschreitet (Standard 80 von 255) UBX MON-RF
position-jump die eigene Lösung des Empfängers mehr als position_jump_m von ihrem Kalibriermittel entfernt ist (Standard 50 m) eine gemeldete Position
raim die Paritäts-RAIM (empfängerautonome Integritätsüberwachung) auf der eigenen Einzelpunktlösung der Engine den Messsatz zurückweist RINEX-Log mit nav
solve-failure die Einzelpunktlösung der Engine mit fünf oder mehr Satelliten fehlschlägt RINEX-Log mit nav
clock die Empfängeruhr um mehr als den kleinsten erkennbaren Versatz ihres Kalibrierrauschens von ihrer vorhergesagten Geraden abweicht RINEX-Log mit nav

Kalibriertes Profil (optional). [monitors] profile = "jammertest-2024-calibrated" ersetzt die drei Interferenzschwellen durch Werte, die am öffentlichen JammerTest-2024-Datensatz kalibriert wurden (ein u-blox ZED-F9P je Szenario; Zenodo 15911589): cn0_drop_db = 1.5, agc_k_sigma = 3.5, jam_ind_threshold = 29. Die Kalibrierung war vorregistriert (xval/jammertest-trust/PREREGISTRATION.md), und das Profil ist MODELLED, angepasst an eine öffentliche Kampagne: Seine Schwelle cn0_drop_db hat den vorregistrierten Zielwert für Fehlalarme im zurückgehaltenen Datensatz verfehlt (0,0231 gegenüber 0,02); die Zielwerte für AGC und Jamming-Indikator und der Vereinigungs-Zielwert (Fehlalarme 0,033, Erkennung 0,81) wurden erreicht (xval/jammertest-trust/RESULTS.md). Es gilt für diesen Empfängertyp bei diesem Ereignis, gegenüber planmäßigen Angriffsfenstern, und wurde an den CSV-Logs des Datensatzes kalibriert (seine UBX-Logs ergeben in zwei Ordnern mehr Fehlalarme). Ein mit dem Profil ausgeführtes Ergebnis gibt die angewendeten Schwellen wieder und trägt eine profile_note, die all dies sagt. Ohne das Profil gelten die obigen Standardwerte, und jede Ausgabe bleibt unverändert.

Für eine Plattform vessel laufen auch die Monitore für bewegte Plattformen (Schwellen in einer Tabelle [maritime] auf oberster Ebene, jeder Standardwert dokumentiert in src/receiver_trust/maritime.rs); jeder braucht seine Daten und wird in monitors_run nur aufgeführt, wenn er entschieden hat:

Monitor Alarm, wenn Benötigt
kinematic die Positionsänderung widerspricht der gemeldeten Geschwindigkeit und dem gemeldeten Kurs, oder sie impliziert eine Geschwindigkeit, Beschleunigung oder Drehrate über den Grenzen des Schiffs Lösungen; Geschwindigkeit und Kurs (RMC oder VTG) für den Koppelnavigationsteil
heading-course Kreiselkurs und Kurs über Grund um mehr als hdg_cog_tol_deg abweichen (Geschwindigkeit über min_speed_kn) Kurs HDT, THS oder VHW, heading_sensor = true
speed-log Fahrt durchs Wasser und Fahrt über Grund um mehr als stw_sog_tol_kn abweichen VHW oder VBW und Fahrt über Grund
sea-level die GGA-Höhe um mehr als sea_level_tol_m von antenna_height_m abweicht GGA-Höhe, antenna_height_m
cn0-spread die Streuung des C/N0 über die Satelliten auf cn0_spread_frac ihres Kalibriermedians fällt GSV
cn0-rise das C/N0 der gemeinsamen Satelliten im Mittel um cn0_rise_db stieg und cn0_rise_frac von ihnen stiegen GSV
time-consistency aufeinanderfolgende Epochenzeiten unregelmäßig springen, rückwärts laufen oder die Hostuhr verlassen NMEA-Zeit; Hostuhr für den letzten Teil
osnma der Empfänger einen OSNMA-Authentifizierungsfehler meldet (ein gemeldeter Status wird gelesen; nichts wird verifiziert; um OSNMA aus den I/NAV-Seiten selbst zu verifizieren, siehe docs/OSNMA.md) Statussatz $PKSOS

Eine Epoche ist nicht vertrauenswürdig, wenn RAIM, der Uhrenmonitor, ein Lösungsfehler oder ein Positionssprung Alarm auslöst oder der C/N0-Abfall das Doppelte seiner Schwelle erreicht; beeinträchtigt bei jedem anderen Alarm; und sonst nominal.

Der Engine-Pfad (raim, solve-failure, clock) ist dieselbe Berechnung wie die unabhängige Referenz für Spoofing aus JammerTest 2024 in tests/jammertest_spoof_oracle_support: tests/receiver_trust_jammertest.rs prüft, dass bei allen acht veröffentlichten Einsetzzeitpunkten der erste Alarm auf dieselbe Epoche fällt und von derselben Art ist.

Vertrauenswert (Plattform Schiff)#

Für ein Schiff erhält jede Epoche nach der Kalibrierung außerdem eine Bewertung von 0 bis 100 und die Gründe, warum sie nicht 100 ist. Die Abbildung ist deterministisch und wird festgelegt, bevor ein Log bewertet wird: kein Lernen, nichts an Ereignisse angepasst. Jeder Monitor reduziert seine Evidenz auf ein Verhältnis statistic / threshold (ein Alarm bei 1 oder mehr); ein Verhältnis kostet die Bewertung

points = weight * clamp((ratio - onset_ratio) / (full_ratio - onset_ratio), 0, 1)
score  = round_to_0.1( clamp(100 - sum of points, 0, 100) )

sodass ein Monitor nichts kostet, solange er unter onset_ratio seiner Schwelle liegt (Standard 0,5), sein halbes Gewicht an seiner Schwelle und sein ganzes beim full_ratio-Fachen der Schwelle (Standard 1,5); die Bewertung ist in jeder Statistik nicht steigend. Eine Quelle, die in einer Epoche nicht meldet, behält ihre letzte Statistik für evidence_hold_s (Standard 10 s: zwei Zyklen eines C/N0-Satzes, der alle 5 s gesendet wird), sowohl als Alarm als auch als Abzug.

Die Rundung ist kaufmännisch (floor(x * 10 + 0.5) / 10), das Band ist das der gerundeten Bewertung, und die Begrenzung kommt vor der Rundung. Nur Monitore, deren Punkte über null liegen, werden in den Abzügen aufgeführt, mit ihrem Verhältnis und ihren ungerundeten Punkten, die größten Punkte zuerst; Abzüge mit gleichen Punkten werden in der Reihenfolge der Monitornamen cn0-drop, agc, jam-ind, loss-of-lock, position-jump, raim, clock, solve-failure, kinematic, heading-course, speed-log, sea-level, cn0-spread, cn0-rise, time-consistency, osnma, geometry aufgeführt. Ein Monitor, dessen Test bestanden oder nicht bestanden lautet (eine fehlgeschlagene Lösung, eine fehlgeschlagene Authentifizierung), erhält das Verhältnis 1,5, das volle Gewicht. Die aufgeführten Punkte sind die vor der Begrenzung bei 0.

[score]
nominal_min = 90.0         # score >= 90: nominal
degraded_min = 55.0        # 55 <= score < 90: degraded; below 55: untrusted
onset_ratio = 0.5
full_ratio = 1.5
evidence_hold_s = 10.0
[score.weights]            # overrides; a monitor not listed keeps its default
sea-level = 30.0
Gewicht (Punkte) Monitore Warum
70 osnma ein Authentifizierungsfehler ist eine Aussage, keine Statistik
60 kinematic, raim, clock, position-jump, time-consistency eine gefälschte Position muss der Physik oder den eigenen Prüfungen des Empfängers widersprechen, und die Zeit kann nicht rückwärts laufen; eine Verletzung in voller Stärke (das 1,5-Fache ihrer Schwelle: 60 Punkte, Bewertung 40) ist nicht vertrauenswürdig, und an ihrer Schwelle (30 Punkte, Bewertung 70) beeinträchtigt
40 heading-course, speed-log, solve-failure ein unabhängiger Sensor, der widerspricht, ist beeinträchtigt; zwei in voller Stärke sind nicht vertrauenswürdig
30 sea-level, cn0-spread, cn0-rise, cn0-drop die Signalumgebung oder eine wenig aussagekräftige Prüfung
25 loss-of-lock, agc, jam-ind die Umgebung ist feindlich; das allein zeigt nicht, dass die Lösung falsch ist
bis zu 15, [geometry] geometry (0.36) kein Gewicht auf dieser Rampe: nichts, außer der Himmel ist schlecht, dann bis zu cap_points (15); Geometrie allein erreicht beeinträchtigt, nie nicht vertrauenswürdig, und löst keinen Alarm aus (siehe „Geometrie“ unten)

Die Bandgrenzen ergeben sich aus den Gewichten: Der leichteste Monitor, der Alarm auslöst, kostet an seiner Schwelle 12,5 Punkte, sodass jeder Alarm das nominale Band verlässt; kein einzelner Monitor unter 60 Punkten kann allein das Band „nicht vertrauenswürdig“ erreichen (mehrere zusammen können es). Das Ergebnis hält das Bewertungsmodell fest (score_model), und jede Epoche trägt score.deductions: welche Monitore abgezogen haben, ihre Verhältnisse und ihre Punkte. Bei einem Schiff ist der Zustand der Epoche das Band ihrer Bewertung.

Geometrie: natürliche Verschlechterung abseits angriffsähnlicher Inkonsistenz#

Ein Empfänger neben einem Kaikran, in einer Schleuse oder unter einem hohen Rumpf verliert Satelliten, und seine Lösung wird aus einem Grund schlechter, der kein Angriff ist. Ab 0,36, gemäß der Entwurfsnotiz zur Geometrie (docs/design/2026-10-12-geometry-and-skyline-design.md, Abschnitt 4), trägt jede Epoche ihre Satellitengeometrie, die Bewertung eines Schiffs hat einen Geometriemonitor, und jeder Abzug trägt eine Klasse: geometry (der Himmel), environment (die Signalumgebung) oder inconsistency (angriffsähnliche Evidenz).

Woher die Geometrie kommt. Elevation und Azimut jedes verfolgten Satelliten (NMEA GSV, UBX NAV-SAT), aus denen die Dilution of Precision (DOP) mit dem einen DOP-Kernel der Engine abgeleitet wird (orbit::dop, VALIDATED gegen gnss_lib_py): source = derived. Ersatzweise die vom Empfänger angegebene DOP und die verwendeten Satelliten (NMEA GSA): source = reported. Himmelspositionen und GSA zählen für das evidence_hold_s der Bewertung (Standard 10 s), weil viele Busse GSV nur alle paar Sekunden senden; ein in einer Epoche unvollständiger GSV-Satz (das Ende eines Ausschnitts, ein verlorener Satz) wird nicht verwendet. Ein Log mit keinem von beiden, etwa NMEA nur mit GGA und RMC, oder derzeit Android- und RINEX-Logs, erhält den Status unknown mit dem Hinweis „geometry unknown“: Die Engine rät keine Geometrie, die ihr nicht gegeben wurde, und der Geometriemonitor läuft nicht.

geometry.status Bedeutung
good genug Satelliten und DOP innerhalb der Schwellen
degraded ein oder mehrere Gründe: few-satellites, high-pdop, high-hdop und (informativ, nicht in der Bewertung) sky-blocked, wenn jeder verfolgte Satellit in einer Hälfte des Horizonts sitzt
unknown das Log liefert für diese Epoche keine Satellitengeometrie

Der Status ist beschreibend, und für die Bewertung zählt die Bezeichnung (unten): degraded schließt den informativen Fall sky-blocked ein, der mit guter oder mittlerer DOP einhergehen kann, und nur eine Bezeichnung poor wird bewertet.

Die Bezeichnung (immer gemeldet, nie bewertet). Das geometry.label jeder Epoche ist good (HDOP höchstens hdop_good 2, PDOP höchstens pdop_good 3 und mindestens used_good 6 Satelliten), poor (HDOP über hdop_max 4, PDOP über pdop_max 6 oder weniger als min_used 5 Satelliten), fair dazwischen, oder unknown. Der Hinweis der Epoche beginnt immer mit der Bezeichnung und den Zahlen, zum Beispiel „geometry fair: HDOP 1,105, PDOP 1,831, VDOP 1,410, 8 satellites; not scored (the score deducts only above HDOP 4, PDOP 6 or below 5 satellites)“, und fügt „, signal loss“ an, wenn das zutrifft.

Der Geometriemonitor (Schiffsbewertung). Er zieht nichts ab, außer die Geometrie ist schlecht: Sein Verhältnis ist max(hdop / hdop_max, pdop / pdop_max, min_used / n_used), und solange dieses höchstens 1 beträgt (gute oder mittlere Geometrie, ein offener Himmel mit nur GPS und 8 Satelliten eingeschlossen), kostet er nichts, sodass ein solches Log genau wie in 0,35 bewertet wird. Über 1 steigt der Abzug linear auf cap_points (15) bei full_ratio (das 1,5-Fache der Schwellen: HDOP 6, PDOP 9, 3 Satelliten): 7,5 Punkte bei Verhältnis 1,25 (HDOP 5 oder 4 Satelliten), 15 ab 1,5 (Bewertung 85, beeinträchtigt). Für sich allein kann er die Bewertung nie unter floor drücken (Standard: das degraded_min der Bewertung, 55), sodass Geometrie allein höchstens das Band „beeinträchtigt“ erreicht und nie das Band „nicht vertrauenswürdig“: Die geltende Obergrenze ist min(cap_points, 100 - floor), sodass eine Tabelle [score], die degraded_min anhebt (etwa eine aus 0,35 mit degraded_min 90), die Obergrenze auf 100 - degraded_min senkt, statt zurückgewiesen zu werden, und ein unter degraded_min gesetztes floor zurückgewiesen wird. Der Monitor löst keinen Alarm aus; er wird in monitors_run zuletzt aufgeführt, wenn er in irgendeiner Epoche entschieden hat (ein Schiff, dessen Log die Geometrie liefert), und wird in der Identität mit 0,35 nicht mitgezählt; er ist kein Eintrag von [score.weights] (einen zu setzen wird zurückgewiesen), und die geltende Obergrenze und Untergrenze werden in geometry_model.cap_in_force und geometry_model.floor_in_force festgehalten. Der Hinweis einer schlechten Epoche sagt, warum, zum Beispiel „geometry poor: HDOP 5,200, PDOP 7,900, VDOP 4,100, 7 satellites; degraded by geometry: HDOP 5,200 above 4 (derived from 7 logged satellites); not an inconsistency“.

Klassen. Jeder Abzug (score.deductions[].class):

Klasse Monitore
geometry geometry (schlechte Geometrie); loss-of-lock, wenn jeder gegenüber der Kalibrier-Basislinie verlorene Satellit bei seiner letzten Meldung unter low_elev_deg lag
environment cn0-drop, cn0-spread, cn0-rise, agc, jam-ind, sonst loss-of-lock; geometry bei Signalverlust (unten)
inconsistency kinematic, heading-course, speed-log, sea-level, time-consistency, clock, raim, position-jump, osnma, solve-failure; und geometry, wenn die Geometrie schlecht ist und die angegebene HDOP dem angegebenen Himmel widerspricht (unten)

Der Schutz gegen einen gefälschten schlechten Himmel. Ein Spoofer könnte ein dünnes GSV senden oder eine hohe HDOP melden, um sich Toleranz zu erkaufen. Die Engine kennzeichnet und verzeiht nicht: Keine andere Prüfung wird durch eine schlechte Geometrie aufgeweitet, und die HDOP, die der Empfänger angibt (GSA innerhalb des Haltefensters, sonst GGA), wird mit der HDOP verglichen, die aus dem von ihm angegebenen Himmel abgeleitet wird. Weichen sie um mehr als max(reported_vs_derived_tol, reported_vs_derived_rel × derived HDOP) ab (1,0 oder 25 % der abgeleiteten HDOP, je nachdem, was größer ist), trägt die Epoche reported_derived_mismatch: true, und bei schlechter Geometrie wird ihr Abzug als inconsistency klassifiziert. Bei guter oder mittlerer Geometrie wird die Abweichung gemeldet und nicht bewertet: Es wird nichts abgezogen, außer die Geometrie ist schlecht. Das ist eine bewusste Entscheidung (0,36): „null, außer schlecht“ gilt für jede Epoche, sodass gute und mittlere Geometrie genau wie in 0,35 bewertet werden und eine gefälschte HDOP nie unbemerkt bleibt. Das Kennzeichen (reported_derived_mismatch) steht in jeder Epoche des Ergebnisses und jeder Live-Zeile, der Hinweis lautet „…beyond the tolerance: reported, not scored (the geometry is not poor)“ oder „…: the geometry deduction is classed an inconsistency“, geometry_summary.hdop_mismatch zählt die Epochen, und die Evidenz-Zusammenfassungsseite zeigt die Zahl, auch null. Die 25 % sind eine REPRESENTATIVE Ingenieurentscheidung, keine gemessene oder normierte Zahl: Ein Empfänger, der je Konstellation eine Uhr löst oder mit einer Teilmenge der von ihm verfolgten Satelliten rechnet (eine Elevationsmaske, ein C/N0-Schnitt, ein RAIM-Ausschluss), gibt eine HDOP an, die sich von der Einzeluhr-HDOP aller verfolgten Satelliten um einen mit der HDOP wachsenden Betrag unterscheidet, sodass eine feste Toleranz allein natürliche schlechte Geometrie als Inkonsistenz lesen würde. Ein größerer Unterschied wird weiterhin als solche gelesen. Ein als geometry klassifizierter Abzug ist eine Aussage über den Himmel, kein Befund, dass kein Angriff stattfand.

Signalverlust ist nicht der Himmel. Wenn Satelliten, die der Empfänger als sichtbar (über low_elev_deg) auflistet, nicht verfolgt werden, leitet die Engine zusätzlich die DOP aller sichtbaren Satelliten ab. Liegt diese DOP der sichtbaren Satelliten innerhalb der Schwellen und wird entweder nichts verfolgt oder sind die nicht verfolgten Satelliten über den Horizont verteilt (nicht auf eine Hälfte beschränkt), dann war der Himmel da und das Signal nicht: Die Epoche trägt signal_loss: true, den Hinweis „satellites in view but not tracked: signal environment, not geometry“, und der Geometrie-Abzug wird als environment klassifiziert. Nicht verfolgte Satelliten, die auf eine Hälfte des Horizonts beschränkt sind, werden weiterhin als blockierter Himmel gelesen (eine Wand, eine Klippe, ein Kai). Eine beidseitige Abschattung (eine Schlucht oder ein enger Fjord) wird als Signalverlust gelesen, bis ein Horizontprofil konfiguriert ist. Die Kein-Fix-Sentinelwerte des Empfängers sind keine DOP: Eine angegebene HDOP oder PDOP von 99 oder mehr, GGA-Qualität 0 und GSA-Modus 1 ergeben keine angegebene DOP.

Schlüssel [geometry] Standard Herkunft
hdop_max 4 gewählt (Entwurfsnotiz 4,2): bei sigma_uere_m 1,5 m ist HDOP 4 ein 2drms von 12 m, dem kin_pos_tol_m der kinematischen Prüfung. IEC 61108-1 wird häufig so zitiert, dass sie ihre Genauigkeitsanforderungen für HDOP ≤ 4 (oder PDOP ≤ 6) angibt: aus der sekundären GNSS-Empfängerliteratur erinnert, keine bestimmte Sekundärquelle eingesehen und die Norm nicht gelesen; gegen den Text der Norm zu prüfen
pdop_max 6 die PDOP-Verfügbarkeitsschwelle von scenarios/polar-arctic-leo-coverage.toml; GPS SPS Performance Standard, 5. Ausgabe (2020), PDOP ≤ 6, wie in tests/constellation_availability_published_spec_oracle.rs zitiert; gegen den Text der Norm zu prüfen
min_used 5 einer mehr, als eine Lösung braucht, sodass ein einzelner Verlust die Lösung nicht beendet; die wenigsten mit einer redundanten Messung für RAIM
sigma_uere_m 1.5 eine angegebene Eingabe für die 2drms-Verknüpfung von hdop_max; setzen Sie den eigenen Wert des Empfängers
reported_vs_derived_tol 1,0 HDOP gewählt (Entwurfsnotiz 4,2): der absolute Teil der Toleranz; eine Abweichung jenseits der Toleranz ist keine Geometrie
reported_vs_derived_rel 0.25 REPRESENTATIVE Ingenieurentscheidung: der relative Teil, für Empfänger mit Uhren je Konstellation oder Teilmengenlösungen
low_elev_deg 15 Entwurfsnotiz 4,3: Satelliten, die darunter verloren gehen, gehen an den Himmel verloren; ein Horizontprofil (0,36 Punkt 1) wird dies erweitern
azimuth_gap_deg 180 geometrisch, informativ: jeder Satellit in einer Hälfte des Horizonts
cap_points 15 Entwurfsnotiz 4,2: Geometrie allein bewegt die Bewertung von nominal nach beeinträchtigt und nie nach nicht vertrauenswürdig; nur abgezogen, wenn die Geometrie schlecht ist (Gründerentscheidung B1, 0,36)
full_ratio 1.5 das eigene full_ratio der Bewertung: Die Rampe erreicht cap_points beim 1,5-Fachen der Schwellen für schlecht
floor das degraded_min der Bewertung (55) Geometrie allein erreicht nie das Band „nicht vertrauenswürdig“; die geltende Obergrenze ist min(cap_points, 100 - floor); ein Wert unter degraded_min wird zurückgewiesen
hdop_good 2 REPRESENTATIVE, nur die Bezeichnung: die Hälfte von hdop_max (das Einsetzverhältnis der Bewertung aus 0,35)
pdop_good 3 REPRESENTATIVE, nur die Bezeichnung: die Hälfte von pdop_max
used_good 6 REPRESENTATIVE, nur die Bezeichnung: einer mehr als min_used, sodass ein einzelner Verlust noch eine redundante Messung übrig lässt

Was sich in den Ausgaben geändert hat und was nicht. Keine Bewertung ändert sich, außer die Geometrie ist schlecht; die Bezeichnung wird immer gemeldet. Angehängte Schlüssel: epochs[].geometry (status, reasons, source, n_used, hdop, pdop, vdop gerundet auf 0,001, open_fraction (null, bis ein Horizontprofil konfiguriert ist), max_azimuth_gap_deg, age_s, reported_hdop, reported_derived_mismatch, note, in_view (Satelliten, die über low_elev_deg aufgelistet sind), signal_loss, label), class bei jedem Abzug und am Ende geometry_model (Schwellen, Haltefenster, die geltende Obergrenze und Untergrenze, Herkunft, Klassenregeln) und geometry_summary (Epochen nach Status, nach Bezeichnung und nach Abzugsklasse sowie die Epochen mit einer Abweichung der angegebenen HDOP); score_model.weights ist wie in 0,35. Zwei Tests halten dies auf die Bytes der Basislinie „0,36 portable“ fest, sobald diese Schlüssel entfernt sind (die Hashes von 0.35.0, neu aufgesetzt, als die Engine auf portable Mathematik umgestellt wurde, und in den Tests als Aufzeichnung dessen behalten, was 0.35.0 veröffentlichte: docs/revisions/STUDIO15-portable-math-rebaseline.md). tests/geometry_trust_no_change.rs hält jede Ausgabe beider Beispielsitzungen fest (Ergebnis-JSON, CSV, SVG, Urteil, wiedergegebene Live-Zeilen, $PKSHT, Prometheus, CEF, LEEF). tests/geometry_corpus_identity.rs hält das Batch-Ergebnis, die Zusammenfassung, die Live-Zeilen und $PKSHT jedes eingecheckten NMEA-Korpus für Schiffe fest (die Demo und die maritimen Referenz-Fixtures, jeweils auch als offener Himmel nur mit GPS und 8 Satelliten, und die aus ihren Seeds erzeugten Szenarien für die Besatzungsschulung); in den beiden Schulungsszenarien, deren Jamming die Geometrie schlecht macht, ist jede nicht schlechte Epoche identisch und jede schlechte unterscheidet sich allein durch den Geometrie-Abzug. Ein Log mit schlechter Geometrie verliert bis zu 15 Punkte, die es in 0,35 nicht verlor; das ist die beabsichtigte Änderung. In der Demo wird das Wegziehen als inconsistency gelesen; tests/geometry_trust.rs bearbeitet das Log, um den westlichen Himmel zu maskieren (mittel: gekennzeichnet, nicht bewertet), ihn und zwei östliche Satelliten zu maskieren (schlecht: Geometrie-Abzüge, Lock-Verlust environment, weil auch hohe Satelliten verloren gingen), nur Satelliten unter 15° zu verlieren (Lock-Verlust geometry) und eine HDOP anzugeben, die der Himmel nicht erklärt (der Abzug für schlechte Geometrie wird zu inconsistency). Die Schwellen sind MODELLED: gewählt, an kein Log angepasst; nichts hier behauptet, wie oft natürliche Verschlechterung und Angriffe an realen Daten unterschieden werden.

Ereignisse und Vorhersagen angeben#

[[events]]
label = "jammer on"
kind = "jamming"            # jamming, spoofing or other
onset_s = 120.0             # seconds since the first epoch of the log
end_s = 240.0               # optional; otherwise onset_s + compare.horizon_s
predicted_cn0_drop_db = 12.0  # optional, e.g. from a `jamming` scenario's link budget

[compare]
detect_tol_s = 10.0         # an alarm this soon after onset counts as a detection
cn0_tol_db = 3.0            # predicted and observed drops agree within this

Für jedes Ereignis gibt das Ergebnis die Fehlalarme zwischen Kalibrierung und Einsetzen an, den ersten Alarm und seine Monitore, die Latenz, den Ausgang (detected, late, missed oder not-evaluable) und den beobachteten medianen C/N0-Abfall gegenüber der Vorhersage (agree, disagree, no-prediction oder not-evaluable). Abweichung wird gemeldet, nie weggestimmt: Die Toleranzen stehen im Szenario, und das Szenario steckt im Hash des Ergebnisses.

Was dies nicht behauptet#

Die Vertrauensmonitore sind MODELLED: Ihre Schwellen sind Eingaben, und ihre Erkennungsleistung bei realer Interferenz ist das, was die Ereignisbewertung misst, nicht etwas, das diese Art behauptet. Bei den Spoofing-Sitzungen von JammerTest 2024 erfassen die Monitore des Engine-Pfads einige Einsetzzeitpunkte innerhalb von 10 s und sind bei anderen spät; die Zahlen siehe die Zeile „Clock-aided χ², RAIM, AGC, SQM fused per-epoch security FoM“ in VERIFICATION-MATRIX.md. Eine Vorhersage, die mit einem Log übereinstimmt, ist ein Datenpunkt, keine Validierung.