机器翻译,未经母语人士审校。以英文版为准。

接收机信任度与海事在GitHub上编辑来源:docs/NMEA-TRAINING.md

NMEA训练数据流:kshana nmea-scenario

海事院校和模拟器中心可以把由Kshana生成的NMEA 0183输入桥楼模拟器或海图绘图仪,以训练船员识别GNSS压制干扰和欺骗干扰。

仅用于训练和测试。所生成的数据流是合成的。绝不能把它们输入船舶的实际导航系统。Kshana仅供参考,不是经型式认可的导航设备。每个数据流都以一条专有标记语句$PKSHT,TRAINING,SYNTHETIC,NOT-FOR-NAVIGATION开头,并每十秒重复一次,接收机会忽略该语句;对于拒绝未知语句的模拟器,--no-marker可将其去除。这里写出的仅是NMEA文本:没有射频、IQ或波形输出,除了发往你所指定地址的文本之外,不发射任何东西。

来自场景coastal-drag-off的训练数据流(引擎v0.40.0,随机种子22,25分钟,教员日志每10 s一个定位结果)。地图显示船舶的真实航迹和接收机所报告的航迹:两者一致,直到脚本设定的位置拖引在421 s开始,此后所报告的航迹逐渐偏离真实航迹,而接收机始终保持有效定位,并在事件于1140 s结束时跳回。旁边是两条航迹之间的距离随时间的变化,以及接收机所报告的平均载噪比密度,它在事件持续期间升至某一个被抬高的水平。由Kshana生成的合成训练数据。仅用于训练和测试:绝不要把这一数据流输入船舶的实际导航系统。仅供参考:不是经型式认可的导航设备。仅供参考的软件,不是经型式认可的导航设备(IEC 61108、IEC 61162):船舶航行的责任仍由操作人员承担。位置、日期和航迹均为虚构。来自场景coastal-drag-off的训练数据流(引擎v0.40.0,随机种子22,25分钟,教员日志每10 s一个定位结果)。地图显示船舶的真实航迹和接收机所报告的航迹:两者一致,直到脚本设定的位置拖引在421 s开始,此后所报告的航迹逐渐偏离真实航迹,而接收机始终保持有效定位,并在事件于1140 s结束时跳回。旁边是两条航迹之间的距离随时间的变化,以及接收机所报告的平均载噪比密度,它在事件持续期间升至某一个被抬高的水平。由Kshana生成的合成训练数据。仅用于训练和测试:绝不要把这一数据流输入船舶的实际导航系统。仅供参考:不是经型式认可的导航设备。仅供参考的软件,不是经型式认可的导航设备(IEC 61108、IEC 61162):船舶航行的责任仍由操作人员承担。位置、日期和航迹均为虚构。

该图取自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重新生成。