NMEA训练数据流:kshana nmea-scenario
海事院校和模拟器中心可以把由Kshana生成的NMEA 0183输入桥楼模拟器或海图绘图仪,以训练船员识别GNSS压制干扰和欺骗干扰。
仅用于训练和测试。所生成的数据流是合成的。绝不能把它们输入船舶的实际导航系统。Kshana仅供参考,不是经型式认可的导航设备。每个数据流都以一条专有标记语句
$PKSHT,TRAINING,SYNTHETIC,NOT-FOR-NAVIGATION开头,并每十秒重复一次,接收机会忽略该语句;对于拒绝未知语句的模拟器,--no-marker可将其去除。这里写出的仅是NMEA文本:没有射频、IQ或波形输出,除了发往你所指定地址的文本之外,不发射任何东西。
该图取自scenarios/training/coastal-drag-off.toml的教员日志绘制而成。
用途#
# 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
| 选项 | 含义 |
|---|---|
--out <file> |
将数据流写入文件;没有网络输出时,默认为<name>.nmea |
--instructor-log <prefix> |
写出<prefix>.instructor.json和<prefix>.instructor.txt(默认:与该文件放在一起) |
--tcp <addr:port>或<port> |
TCP服务器;有客户端连接后才开始运行(--wait-clients <n>)。仅给出端口时,只在127.0.0.1上监听 |
--udp <addr:port>或<port> |
UDP,每个数据报一条语句;--broadcast允许使用广播地址。仅给出端口时,发往127.0.0.1 |
--realtime, --speed <x> |
控制数据流的节奏;--speed 0表示尽可能快。网络输出默认按实时,文件默认尽可能快 |
--seed <n> |
替换场景的随机种子 |
--no-marker |
省略标记语句 |
没有任何认证。被指定非本地地址的TCP服务器会向任何能连到它的人提供该数据流,UDP则会发往你所指定的任何地址。两秒内未取走数据的TCP客户端会被断开,因此一个停滞的消费者不会拖住其他消费者。
同一随机种子在同一平台上给出相同的字节,节奏控制从不改变字节。跨平台时,生成器自身的算术是逐位相同的(它使用可移植的数学层),但卫星位置和视角来自调用主机数学库的引擎函数,因此在罕见的临界情形下,GSV中经舍入的仰角、方位角或C/N0的某一位数字可能因平台而异。
写出的内容#
每个历元(每秒1、2、5或10个)包含:RMC、GGA、GNS(定位、位置、时间)、GSA(所用卫星和DOP,每个星座一条)、GSV(可见卫星,含仰角、方位角和以dB-Hz表示的SNR,每个星座一组,NMEA 4.10信号标识)、VTG(对地航向和航速)、ZDA(时间和日期)、HDT(陀螺航向)和VBW(来自计程仪的对水和对地航速)。多个星座时,发送方标识为GN,否则为该星座自己的标识。各行以CRLF结尾,校验和有效。
HDT和VBW代表独立的传感器(陀螺罗经和多普勒计程仪)。没有任何事件会触及它们,这是有意为之:GNSS所报告的内容与陀螺和计程仪所显示的内容之间的差距,是复盘时的提示线索。
定位丢失时,GGA质量为0,RMC状态为V,位置字段为空,时间字段继续(接收机的时钟持续运行),与真实接收机一样。
船舶#
[vessel]和[[waypoint]]给出起始位置、航速以及需要依次驶经的点。船舶朝下一个航路点航行,受转向率限制(max_rot_deg_per_min,默认30)、转向率建立速度的限制(max_rot_accel_deg_per_s2)以及航速变化限制(max_accel_kn_per_min)。某一航段的航速即该航路点的speed_kn。[environment]增加了海流,因此对地航速不同于对水航速,艏向不同于对地航向,并增加了磁偏角。stop_at_end使船舶在最后一个航路点处停住。
卫星几何#
卫星来自引擎自身的标称星座(GPS轨位表、Galileo和北斗MEO Walker构型、GLONASS ICD),由constellation::satellite_positions_fixed传播(二体加长期J2、地球自转),并以引擎的WGS-84视角从船舶处观测。GSV中的可见数、仰角和方位角对于该地点和一天中的该时刻是合理的。这是一个标称天空,而不是该数据流日期的星历:PRN按轨位顺序分配,每个星座保持其已发布的轨位布局,在J2作用下从GPS轨位表历元(2016-12-31)起连续传播,因此布局是完整的,但其朝向并不是数据流日期那天真实天空的朝向。C/N0随仰角变化(标称天顶电平,在[receiver]中设定),另加固定的每颗卫星偏移、缓慢衰落和噪声。低于track_threshold_dbhz的卫星,其SNR字段为空;低于use_threshold_dbhz的卫星被跟踪但不被使用。最多使用max_used(默认12,NMEA GGA的上限)颗可用卫星,按几何选取(先取每个30度方位扇区中最高的卫星)。可用卫星少于四颗时定位丢失,在reacquire_s的可用信号之后恢复。
事件#
每个[[event]]都有一个kind、一个起始时刻start_s、一个duration_s(从起始到释放开始)、一个起始斜坡ramp_s和一个释放斜坡recovery_s。强度在ramp_s内线性上升,保持,然后在recovery_s内下降;0即为阶跃。所有效应都随该强度缩放。不属于该类型的参数会被拒绝。
| 类型 | 参数 | 效应 |
|---|---|---|
jamming |
cn0_drop_db、spread_db(默认6) |
每颗卫星的C/N0最多下降cn0_drop_db(每颗卫星有各自的离散),卫星按最低者先失锁,可用卫星少于四颗时定位丢失,并在释放和reacquire_s之后恢复 |
drag-off |
final_offset_m、bearing_deg(真方位)或relative_bearing_deg(相对于起始时的航向,然后保持)之一,可选的max_accel_mps2、counterfeit_cn0_dbhz |
接收机保持有效定位,但其位置逐渐偏离真值;SOG和COG都包含拖引。拖引在斜坡上遵循smoothstep,因此虚假航迹的起止没有速度阶跃;对于在D m上斜坡为T s的情形,其峰值为1.5 D/T m/s和6 D/T^2 m/s的平方(两者均有记录),超过max_accel_mps2的场景会被拒绝。阶跃(ramp_s = 0)会移动位置而不触及速度 |
time-spoof |
offset_s, counterfeit_cn0_dbhz |
RMC、GGA、GNS和ZDA的时间相对于真实UTC被移动;位置保持真实 |
replay-delay |
delay_s、affect_time(默认为true)、counterfeit_cn0_dbhz |
位置、速度(以及时间)是该船delay_s之前的值,延迟在其斜坡上遵循smoothstep,在其变化期间,所报告的航速按1 - d(delay)/dt缩放:这是一种简化的、类似meaconing的抽象,而不是传播模型 |
counterfeit_cn0_dbhz:当拖引、时间欺骗或重放延迟处于活动状态时,每颗被跟踪的卫星都显示同一个被抬高的电平,这是一个典型的迹象。若要做一个保留真实C/N0模式的隐蔽事件,则不设该项。只要有任何伪造事件处于活动状态,接收机就会跟随伪造信号,因此压制干扰不会使其失锁;因先前压制干扰而丢失的定位,会在reacquire_s之后在伪造信号上恢复(见combined-event)。会使所报告的时间停止或倒退的时间变化(速率为每秒1 s或更高)会被拒绝,除非它是阶跃(ramp_s = 0)。
事件可以重叠;它们的效应相加(偏移、时间变化、延迟)或取最强者(压制干扰)。时间线上的onset是事件开始产生效应的第一个历元;当事件有斜坡上升时,它比脚本设定的start_s晚一个历元。
教员日志#
与数据流一同给出的<prefix>.instructor.json和<prefix>.instructor.txt包含:
- 所注入的事件,以通俗语言写出,含每个参数及其UTC起始时间;
- 一条时间线:起始、完全生效、开始恢复、已恢复,以及接收机自己的
fix-lost和fix-regained; - 以
log_interval_s为间隔的真实航迹与所报告航迹的对照:真实和所报告的位置、航速和航向,以米为单位的位置误差,时间偏移,所用和被跟踪的卫星,平均C/N0,以及哪些事件处于活动状态; - 真实航迹和所报告航迹的峰值速度和加速度;
- 场景的
trainer_note。
仅在复盘时显示该日志。
JSON字段(模式kshana-nmea-training/1)#
| 字段 | 类型、单位 | 含义 |
|---|---|---|
schema |
字符串 | kshana-nmea-training/1 |
warning |
字符串 | 仅用于训练的声明 |
scenario, description, trainer_note |
字符串 | 来自场景 |
seed |
整数 | 所用的随机种子 |
start_utc |
ISO 8601 UTC | 运行的开始 |
duration_s |
s | 运行的时长 |
summary.true_peak_sog_kn, summary.reported_peak_sog_kn |
节 | 最高的真实和所报告的对地航速 |
summary.true_peak_accel_mps2, summary.reported_peak_accel_mps2 |
m/s的平方 | 每秒速度的最大变化,真实的,以及相邻所报告定位结果之间的 |
events[] |
每个脚本事件一项 | |
events[].id |
整数 | 从1起编号;供timeline[].event和track[].active_events使用 |
events[].description |
字符串 | 含参数的通俗语言描述 |
events[].start_utc |
ISO 8601 UTC | 脚本设定的起始 |
events[].parameters |
对象 | 事件的原样(kind、start_s、duration_s、ramp_s、recovery_s,以及该类型自己的参数;缺失的予以省略) |
events[].resolved_bearing_deg |
真方位的度数或null | 拖引:所施加的方向(相对方位在起始时被解析) |
events[].peak_drag_speed_mps, events[].peak_drag_accel_mps2 |
m/s、m/s的平方或null | 拖引:拖引加在虚假航迹上的峰值 |
timeline[] |
供复盘用的时刻,按时间顺序 | |
timeline[].t_s, .utc |
自开始起的秒数,ISO 8601 UTC | 时刻(真实时间) |
timeline[].event |
整数或null | 事件编号;接收机状态变化时为null |
timeline[].what |
字符串 | onset、full-effect、recovery-begins、recovered(事件);fix-lost、fix-regained(接收机) |
timeline[].text |
字符串 | 说明 |
track[] |
每log_interval_s一行 |
|
track[].t_s, .utc |
s,ISO 8601 UTC | 时刻(真实时间) |
track[].true_lat_deg, .true_lon_deg |
度 | 真实位置 |
track[].true_sog_kn, .true_cog_deg, .true_heading_deg |
节,真方位的度数 | 真实的对地航速和航向,以及陀螺艏向 |
track[].fix_valid |
布尔值 | 接收机报告了定位 |
track[].reported_lat_deg, .reported_lon_deg, .reported_sog_kn, .reported_cog_deg |
度、节、真方位的度数,或null | 接收机所报告的内容;定位丢失期间为null |
track[].position_error_m |
m或null | 真实位置到所报告位置的水平距离 |
track[].time_offset_s |
s | 所报告的UTC减去真实UTC |
track[].n_used, .n_tracked |
整数 | 定位中所用的卫星数,以及被跟踪的卫星数 |
track[].mean_cn0_dbhz |
dB-Hz或null | 被跟踪卫星的平均C/N0 |
track[].active_events |
整数 | 在此刻有效应的事件的编号 |
增加字段不会改变模式标签。重命名或删除字段,或更改字段的含义或单位,则会使编号递增(/2)。
场景库#
scenarios/training/,每个场景为几分钟的航程,其TOML中附有一条教员提示:
| 文件 | 所显示的内容 |
|---|---|
open-sea-jamming.toml |
C/N0一同下降,卫星相继失锁,定位丢失后又恢复 |
coastal-drag-off.toml |
一个有效、看似正常的定位结果向海岸方向拖引1.4 km;C/N0被统一抬高 |
port-approach-time-spoof.toml |
位置正确,在缓慢的进港过程中UTC超前漂移45 s |
combined-event.toml |
先是压制干扰,随后是伪造信号接管并伴有拖引和时间偏移,然后是重放延迟 |
fjord-natural-degradation.toml |
这是被遮挡的天空,而不是干扰:峡湾的两壁(REPRESENTATIVE的fjord天际线预设)遮住了东西两侧的卫星,随后水道再次打开(事件natural-degradation,带skyline表) |
位置、日期和航迹均为虚构;该库不含任何真实的船舶、运营方或录制数据。它不就任何接收机或系统在干扰下的表现作任何陈述。
建模选择#
该生成器是一个没有外部基准(oracle)的训练工具,其数字是建模上的选择,而不是对任何接收机的测量。它们被选成看起来像一份普通的接收机日志:从天顶到地平线,C/N0比天顶电平(默认47 dB-Hz)低14 dB的斜率,以及每颗卫星 +/-1.5 dB的偏移,97 s内0.8 dB和31 s内0.5 dB的缓慢衰落,0.3 dB的抖动;跟踪(20 dB-Hz)和使用(28 dB-Hz)的阈值;位置噪声(在HDOP为1时为1.5 m,相关时间30 s,垂向为其两倍);0.05度的陀螺噪声和0.03 kn的偏航噪声;20 s的操舵时间常数和船舶模型的航路点到达半径;以及按方位扇区选取卫星的做法。默认值位于[receiver]和[vessel]中,都可以在场景里更改。
回读#
kshana receiver-trust可以读入这些文件(format = "nmea")。测试按各自的字段数和校验和规则检查每个库场景的每条语句,并让文件通过该读取器运行,该读取器解释GGA、RMC和GSV,并略过其他类型而不会漏掉任何一条。测试为每个场景固定一份golden摘录(tests/fixtures/nmea_training/);在有意的更改之后,用KSHANA_BLESS_GOLDEN=1重新生成。