NMEA-Trainingsströme: kshana nmea-scenario
Seefahrtsakademien und Simulatorzentren können von Kshana erzeugtes NMEA 0183 in einen Brückensimulator oder einen Kartenplotter einspeisen, um Besatzungen darin zu schulen, GNSS-jamming und -spoofing zu erkennen.
Nur für Training und Tests. Die erzeugten Ströme sind synthetisch. Sie dürfen niemals in die laufenden Navigationssysteme eines Schiffes eingespeist werden. Kshana ist beratend, keine typzugelassene Navigationsausrüstung. Jeder Strom beginnt mit einem proprietären Markierungssatz und wiederholt ihn alle zehn Sekunden,
$PKSHT,TRAINING,SYNTHETIC,NOT-FOR-NAVIGATION, den Empfänger ignorieren;--no-markerentfernt ihn für einen Simulator, der unbekannte Sätze ablehnt. Dies schreibt NMEA nur als Text: Es gibt keine HF-, IQ- oder Wellenformausgabe, und nichts sendet außer dem Text an die Adresse, die Sie benennen.
Die Abbildung ist aus dem Ausbilderlog von scenarios/training/coastal-drag-off.toml gezeichnet.
Verwendung#
# write a file (default <name>.nmea) and the instructor log next to it
kshana nmea-scenario scenarios/training/coastal-drag-off.toml --out drag.nmea
# serve over TCP in real time on this machine only (waits for the simulator to connect)
kshana nmea-scenario scenarios/training/open-sea-jamming.toml --tcp 10110
# reachable from the bridge-simulator host: name the address in full
kshana nmea-scenario scenarios/training/open-sea-jamming.toml --tcp 192.168.1.20:10110
# UDP, one sentence per datagram, ten times faster than real time
kshana nmea-scenario scenarios/training/combined-event.toml --udp 192.168.1.50:10110 --speed 10
# UDP broadcast
kshana nmea-scenario scenarios/training/combined-event.toml --udp 192.168.1.255:10110 --broadcast
| Option | Bedeutung |
|---|---|
--out <file> |
den Strom in eine Datei schreiben; ohne Netzwerkausgabe ist der Standard <name>.nmea |
--instructor-log <prefix> |
<prefix>.instructor.json und <prefix>.instructor.txt schreiben (Standard: neben der Datei) |
--tcp <addr:port> oder <port> |
TCP-Server; der Lauf beginnt, wenn sich ein Client verbunden hat (--wait-clients <n>). Ein bloßer Port lauscht nur auf 127.0.0.1 |
--udp <addr:port> oder <port> |
UDP, ein Satz je Datagramm; --broadcast erlaubt eine Broadcast-Adresse. Ein bloßer Port sendet an 127.0.0.1 |
--realtime, --speed <x> |
den Strom takten; --speed 0 ist so schnell wie möglich. Die Netzwerkausgabe läuft standardmäßig in Echtzeit, Dateien so schnell wie möglich |
--seed <n> |
den Seed des Szenarios ersetzen |
--no-marker |
den Markierungssatz weglassen |
Es gibt keine Authentifizierung. Ein TCP-Server mit einer nicht lokalen Adresse liefert den Strom an jeden, der ihn erreichen kann, und UDP sendet an jede Adresse, die Sie benennen. Ein TCP-Client, der seine Daten nicht innerhalb von zwei Sekunden abnimmt, wird getrennt, sodass ein blockierter Verbraucher die anderen nicht aufhalten kann.
Derselbe Seed ergibt auf einer Plattform dieselben Bytes, und das Takten ändert die Bytes nie. Plattformübergreifend ist die eigene Arithmetik des Generators bitidentisch (er verwendet die portable Mathematikschicht), aber Satellitenpositionen und Blickwinkel stammen aus Funktionen der Engine, die die Mathematikbibliothek des Hosts aufrufen, sodass in einem seltenen Grenzfall eine gerundete Stelle von Elevation, Azimut oder C/N0 in GSV sich zwischen Plattformen unterscheiden kann.
Was geschrieben wird#
Jede Epoche (1, 2, 5 oder 10 je Sekunde) enthält: RMC, GGA, GNS (Fix, Position, Zeit), GSA (verwendete Satelliten und DOP, einer je Konstellation), GSV (Satelliten in Sicht mit Elevation, Azimut und SNR in dB-Hz, ein Satz je Konstellation, NMEA-4,10-Signal-ID), VTG (Kurs und Geschwindigkeit über Grund), ZDA (Zeit und Datum), HDT (Kreiselpeilung) und VBW (Wasser- und Grundgeschwindigkeit aus dem Log). Der Talker ist GN bei mehreren Konstellationen, sonst der eigene der Konstellation. Zeilen enden in CRLF und haben gültige Prüfsummen.
HDT und VBW stehen für unabhängige Sensoren (einen Kreiselkompass und ein Doppler-Log). Kein Ereignis berührt sie, was beabsichtigt ist: Die Lücke zwischen dem, was GNSS berichtet, und dem, was Kreisel und Log sagen, ist ein Hinweis für die Nachbesprechung.
Wenn der Fix verloren geht, ist die Qualität von GGA 0, der Status von RMC V, die Positionsfelder sind leer und die Zeitfelder laufen weiter (die Uhr des Empfängers läuft weiter), wie bei echten Empfängern.
Das Schiff#
[vessel] und [[waypoint]] geben eine Startposition, eine Geschwindigkeit und die Punkte an, durch die gesteuert wird. Das Schiff wird unter einer Begrenzung der Drehrate (max_rot_deg_per_min, Standard 30), einer Begrenzung, wie schnell die Drehrate anwächst (max_rot_accel_deg_per_s2), und einer Begrenzung der Geschwindigkeitsänderung (max_accel_kn_per_min) zum nächsten Wegpunkt gesteuert. Die Geschwindigkeit eines Abschnitts ist der Wert speed_kn des Wegpunkts. [environment] fügt eine Strömung hinzu, sodass sich die Geschwindigkeit über Grund von der Geschwindigkeit durchs Wasser und der Steuerkurs vom Kurs über Grund unterscheidet, sowie eine magnetische Missweisung. stop_at_end bringt das Schiff am letzten Wegpunkt zum Stillstand.
Satellitengeometrie#
Satelliten stammen aus den eigenen nominalen Konstellationen der Engine (GPS-Slot-Tabelle, Walker-Muster für Galileo und BeiDou MEO, GLONASS-ICD), propagiert durch constellation::satellite_positions_fixed (Zweikörper plus säkulares J2, Erdrotation) und vom Schiff aus mit den WGS-84-Blickwinkeln der Engine gesehen. Die sichtbare Anzahl, die Elevationen und Azimute in GSV sind für den Ort und die Tageszeit plausibel. Dies ist ein nominaler Himmel, keine Ephemeride für das Datum des Stroms: PRNs werden in der Reihenfolge der Slots vergeben, und jede Konstellation behält ihr veröffentlichtes Slot-Layout, kontinuierlich ab der Epoche der GPS-Slot-Tabelle (2016-12-31) unter J2 propagiert, sodass das Layout intakt ist, seine Orientierung aber nicht die des realen Himmels am Datum des Stroms. C/N0 folgt der Elevation (ein nominaler Zenitpegel, gesetzt in [receiver]), mit einem festen Versatz je Satellit, langsamem Fading und Rauschen. Ein Satellit unter track_threshold_dbhz hat ein leeres SNR-Feld; einer unter use_threshold_dbhz wird verfolgt, aber nicht verwendet. Bis zu max_used (Standard 12, die Obergrenze von NMEA GGA) nutzbare Satelliten werden verwendet, nach der Geometrie gewählt (zuerst der höchste Satellit in jedem Azimutsektor von 30 Grad). Weniger als vier nutzbare Satelliten verlieren den Fix, und er kehrt nach reacquire_s nutzbaren Signals zurück.
Ereignisse#
Jedes [[event]] hat ein kind, einen Einsatz start_s, eine duration_s (vom Einsatz bis zum Beginn der Freigabe), eine Einsatzrampe ramp_s und eine Freigaberampe recovery_s. Die Stärke steigt linear über ramp_s, wird gehalten und fällt dann über recovery_s; 0 ist ein Sprung. Alle Wirkungen skalieren mit dieser Stärke. Parameter, die nicht zur Art gehören, werden abgelehnt.
| Art | Parameter | Wirkung |
|---|---|---|
jamming |
cn0_drop_db, spread_db (Standard 6) |
das C/N0 jedes Satelliten fällt um bis zu cn0_drop_db (Streuung je Satellit), Satelliten fallen zuerst mit dem niedrigsten Wert aus, der Fix geht verloren, wenn weniger als vier nutzbar sind, und kehrt nach der Freigabe und reacquire_s zurück |
drag-off |
final_offset_m, eines von bearing_deg (wahr) oder relative_bearing_deg (zum Kurs beim Einsatz, dann gehalten), optional max_accel_mps2, counterfeit_cn0_dbhz |
der Empfänger behält einen gültigen Fix, dessen Position sich von der Wahrheit entfernt; SOG und COG enthalten das Wegziehen. Das Wegziehen folgt auf den Rampen einer Smoothstep-Funktion, sodass die falsche Spur ohne Geschwindigkeitssprung beginnt und endet; seine Spitzen sind 1.5 D/T m/s und 6 D/T^2 m/s zum Quadrat bei einer Rampe von T s über D m (beide protokolliert), und ein Szenario, das max_accel_mps2 überschreiten würde, wird abgelehnt. Ein Sprung (ramp_s = 0) verschiebt die Position, ohne die Geschwindigkeit zu berühren |
time-spoof |
offset_s, counterfeit_cn0_dbhz |
Die Zeit von RMC, GGA, GNS und ZDA wird von der wahren UTC verschoben; die Position bleibt wahr |
replay-delay |
delay_s, affect_time (Standard true), counterfeit_cn0_dbhz |
Position, Geschwindigkeit (und Zeit) sind die des Schiffes von vor delay_s, wobei die Verzögerung auf ihren Rampen einer Smoothstep-Funktion folgt und die berichtete Geschwindigkeit mit 1 - d(delay)/dt skaliert wird, solange sie sich ändert: eine vereinfachte Abstraktion im Stil von meaconing, kein Ausbreitungsmodell |
counterfeit_cn0_dbhz: Solange ein Wegziehen, ein Zeit-Spoofing oder eine Wiedergabeverzögerung aktiv ist, zeigt jeder verfolgte Satellit diesen einen erhöhten Pegel, ein klassisches Zeichen. Lassen Sie es bei einem subtilen Ereignis weg, bei dem das echte C/N0-Muster erhalten bleibt. Solange irgendein Fälschungsereignis aktiv ist, folgt der Empfänger dem gefälschten Signal, sodass jamming ihn nicht ausfallen lässt; ein durch früheres jamming verlorener Fix kehrt nach reacquire_s auf dem gefälschten Signal zurück (siehe combined-event). Eine Zeitänderung, die die berichtete Zeit anhalten oder rückwärts laufen ließe (Rate von 1 s je Sekunde oder mehr), wird abgelehnt, außer sie ist ein Sprung (ramp_s = 0).
Ereignisse dürfen sich überlappen; ihre Wirkungen addieren sich (Versätze, Zeitänderungen, Verzögerungen) oder die stärkste gilt (jamming). Der onset der Zeitleiste ist die erste Epoche, in der das Ereignis eine Wirkung hat, eine Epoche nach dem geskripteten start_s, wenn das Ereignis eingerampt wird.
Das Ausbilderlog#
Zusammen mit dem Strom liefern <prefix>.instructor.json und <prefix>.instructor.txt:
- die Ereignisse wie eingespeist, in einfacher Sprache mit jedem Parameter, und ihren UTC-Einsatz;
- eine Zeitleiste: Einsatz, volle Wirkung, Beginn der Erholung, erholt, und die eigenen
fix-lostundfix-regaineddes Empfängers; - die wahre Spur gegen die berichtete im Abstand
log_interval_s: wahre und berichtete Position, Geschwindigkeit und Kurs, Positionsfehler in Metern, Zeitversatz, verwendete und verfolgte Satelliten, mittleres C/N0 und welche Ereignisse aktiv waren; - die Spitzengeschwindigkeit und -beschleunigung der wahren und der berichteten Spur;
- der
trainer_notedes Szenarios.
Zeigen Sie das Log erst bei der Nachbesprechung.
JSON-Felder (Schema kshana-nmea-training/1)#
| Feld | Typ, Einheit | Bedeutung |
|---|---|---|
schema |
Zeichenfolge | kshana-nmea-training/1 |
warning |
Zeichenfolge | die Aussage, nur für Training zu gelten |
scenario, description, trainer_note |
Zeichenfolge | aus dem Szenario |
seed |
Ganzzahl | verwendeter Seed |
start_utc |
ISO 8601 UTC | Beginn des Laufs |
duration_s |
s | Länge des Laufs |
summary.true_peak_sog_kn, summary.reported_peak_sog_kn |
Knoten | höchste wahre und berichtete Geschwindigkeit über Grund |
summary.true_peak_accel_mps2, summary.reported_peak_accel_mps2 |
m/s zum Quadrat | größte Geschwindigkeitsänderung je Sekunde, wahr und zwischen aufeinanderfolgenden berichteten Fixes |
events[] |
eines je geskripteten Ereignis | |
events[].id |
Ganzzahl | 1-basiert; verwendet von timeline[].event und track[].active_events |
events[].description |
Zeichenfolge | Beschreibung in einfacher Sprache mit den Parametern |
events[].start_utc |
ISO 8601 UTC | geskripteter Einsatz |
events[].parameters |
Objekt | das Ereignis genau wie geschrieben (kind, start_s, duration_s, ramp_s, recovery_s und die eigenen Parameter der Art; fehlende werden weggelassen) |
events[].resolved_bearing_deg |
Grad wahr oder null | Wegziehen: die angewandte Richtung (eine relative Peilung wird beim Einsatz aufgelöst) |
events[].peak_drag_speed_mps, events[].peak_drag_accel_mps2 |
m/s, m/s zum Quadrat oder null | Wegziehen: die Spitzen, die das Wegziehen zur falschen Spur hinzufügt |
timeline[] |
Momente für die Nachbesprechung, in zeitlicher Reihenfolge | |
timeline[].t_s, .utc |
s ab Beginn, ISO 8601 UTC | wann (wahre Zeit) |
timeline[].event |
ganze Zahl oder null | die Ereignis-ID; null bei Zustandsänderungen des Empfängers |
timeline[].what |
Zeichenfolge | onset, full-effect, recovery-begins, recovered (Ereignisse); fix-lost, fix-regained (Empfänger) |
timeline[].text |
Zeichenfolge | Erläuterung |
track[] |
eine Zeile je log_interval_s |
|
track[].t_s, .utc |
s, ISO 8601 UTC | wann (wahre Zeit) |
track[].true_lat_deg, .true_lon_deg |
Grad | wahre Position |
track[].true_sog_kn, .true_cog_deg, .true_heading_deg |
Knoten, Grad wahr | wahre Geschwindigkeit und wahrer Kurs über Grund sowie Kreiselpeilung |
track[].fix_valid |
boolesch | der Empfänger berichtete einen Fix |
track[].reported_lat_deg, .reported_lon_deg, .reported_sog_kn, .reported_cog_deg |
Grad, Knoten, Grad wahr oder null | was der Empfänger berichtete; null, solange der Fix verloren ist |
track[].position_error_m |
m oder null | horizontaler Abstand von der wahren zur berichteten Position |
track[].time_offset_s |
s | berichtete UTC minus wahre UTC |
track[].n_used, .n_tracked |
ganze Zahlen | im Fix verwendete und verfolgte Satelliten |
track[].mean_cn0_dbhz |
dB-Hz oder null | mittleres C/N0 der verfolgten Satelliten |
track[].active_events |
ganze Zahlen | IDs der Ereignisse mit einer Wirkung in diesem Augenblick |
Das Hinzufügen eines Feldes ändert das Schema-Tag nicht. Das Umbenennen oder Entfernen eines Feldes oder das Ändern der Bedeutung oder Einheit eines Feldes erhöht die Nummer (/2).
Die Szenariobibliothek#
scenarios/training/, je einige Minuten Fahrt mit einem Trainerhinweis in ihrer TOML:
| Datei | was sie zeigt |
|---|---|
open-sea-jamming.toml |
C/N0 fällt gemeinsam, Satelliten fallen aus, der Fix geht verloren und kehrt zurück |
coastal-drag-off.toml |
ein gültiger, gesund aussehender Fix wird 1,4 km zum Ufer hin gezogen; einheitlich erhöhtes C/N0 |
port-approach-time-spoof.toml |
Position korrekt, UTC läuft während einer langsamen Hafeneinfahrt 45 s voraus |
combined-event.toml |
jamming, dann Übernahme durch Fälschung mit Wegziehen und Zeitversatz, dann eine Wiedergabeverzögerung |
fjord-natural-degradation.toml |
ein verdeckter Himmel, keine Störung: Die Wände eines Fjords (das REPRESENTATIVE Skyline-Preset fjord) verdecken die Satelliten im Osten und Westen, dann öffnet sich der Kanal wieder (Ereignis natural-degradation, mit einer Tabelle skyline) |
Positionen, Daten und Spuren sind erfunden; die Bibliothek enthält kein reales Schiff, keinen realen Betreiber und keine reale Aufzeichnung. Sie trifft keine Aussage darüber, wie sich irgendein Empfänger oder System gegenüber Störung verhalten würde.
Modellierungsentscheidungen#
Der Generator ist ein Trainingswerkzeug ohne externe Referenz, und seine Zahlen sind Modellierungsentscheidungen, keine Messungen irgendeines Empfängers. Sie sind so gewählt, dass sie wie das Log eines gewöhnlichen Empfängers aussehen: die Steigung von C/N0 von 14 dB vom Zenit zum Horizont unterhalb des Zenitpegels (Standard 47 dB-Hz) und der Versatz je Satellit von +/-1.5 dB, langsames Fading von 0,8 dB über 97 s und 0,5 dB über 31 s, 0,3 dB Jitter; die Schwellen für Verfolgung (20 dB-Hz) und Verwendung (28 dB-Hz); das Positionsrauschen (1,5 m bei HDOP 1, korreliert über 30 s, vertikal doppelt so groß); 0,05 Grad Kreiselrauschen und 0,03 kn Abdriftrauschen; die Zeitkonstante der Steuerung von 20 s und die Ankunftsradien der Wegpunkte des Schiffsmodells; und die Wahl der Satelliten nach Azimutsektor. Die Standardwerte stehen in [receiver] und [vessel] und lassen sich im Szenario alle ändern.
Zurücklesen#
kshana receiver-trust kann diese Dateien einlesen (format = "nmea"). Die Tests prüfen jeden Satz jedes Szenarios der Bibliothek gegen seine eigenen Regeln für Feldanzahl und Prüfsumme und führen die Dateien durch diesen Leser, der GGA, RMC und GSV interpretiert und die anderen Typen übergeht, ohne welche zu überspringen. Tests legen je Szenario einen goldenen Ausschnitt fest (tests/fixtures/nmea_training/); nach einer beabsichtigten Änderung mit KSHANA_BLESS_GOLDEN=1 neu erzeugen.