尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

基于AIS的船舶避碰数据采集与CPA/TCPA计算系统实现

基于AIS的船舶避碰数据采集与CPA/TCPA计算系统实现 简介一份基于AIS的船舶避碰数据采集系统设计PDF面向航海电子、船舶通信、嵌入式系统方向的师生与工程技术人员可服务于课程设计、毕业设计、船舶设备开发及通航安全研究等场景帮助读者建立从船载传感信息接入到VHF无线收发、再到避碰预警的完整设计思路。内容依据实际系统方案展开详细介绍了AIS的组成与工作过程、ITU-R M.1371等通信协议以及DGPS差分定位数据、罗经航向数据、计程仪速度数据的滤波处理硬件部分覆盖FSK鉴频与解码电路、C5402 DSP主控模块、RS-485接口和LCD显示电路软件部分则说明了数据处理、错误检测和主要程序流程。压缩包内共1个PDF文件大小1.96MB结构规整含摘要、目录和章节适合直接阅读打印读者可按章节逐步理解天线信号接收、信号解码、信息显示与安全短消息收发的要点。该资源已有207人学习下载对于希望快速掌握船舶避碰数据采集系统整体方案和关键模块设计的读者具备较好的参考与借鉴价值。1. 基于AIS的船舶避碰数据采集系统要解决的核心问题船与船之间判断会不会撞不能光靠肉眼也不能光靠雷达。雷达给的是回波轮廓分辨不出对方船名、航速和转向意图AIS船舶自动识别系统把这些信息以数字化明文广播出来行业里做避碰辅助决策首先拿到的数据源就是AIS。这套采集系统要解决的问题很直接把往返播发的AIS报文完整收下来解析成可计算的动态与静态要素再统一时间基准和坐标框架为后续CPA/TCPA危险判断提供可靠输入。在VTS和船载避碰告警的实际工程里AIS数据采集通常不是买一台接收机接上串口就能投产的。VHF信道的时隙冲突、报文丢失、波特率不匹配、NMEA语句校验和错误、双信道重复消息这些都会直接影响避碰判断。这篇文章面向要实现或维护这类系统的船舶电子、导航信息化从业者从协议解析、接收链路、存储设计一路讲到避碰参数计算与验证方法给出可直接落地的技术路径。2. AIS报文协议与NMEA 0183解析避碰要读哪些字段2.1 与避碰相关的AIS消息类型和关键字段AIS工作在VHF频段的87B161.975 MHz与88B162.025 MHz两个信道上采用GMSK调制和9600 bps的HDLC帧结构。Class A船舶使用SOTDMA自组织时分多址Class B船舶使用CSTDMA载波侦听时分多址两者都在由2250个时隙组成的一分钟周期内抢占发送机会。做数据采集的人不需要把整个SOTDMA状态机实现一遍但一定要知道哪几条消息类型直接参与避碰计算。类型1、2、3Class A船位报告包含本船经纬度、对地航速SOG、对地航向COG、真航向HDG、转向率ROT和导航状态。船舶在航行状态下大约每2到10秒发送一次锚泊时最长间隔3分钟。类型5Class A静态与航次消息包含船名、呼号、IMO编号、船长船宽、船舶类型、吃水、目的港和ETA斜行每6分钟发送一次。类型18Class B船位报告字段比Class A少没有ROT和导航状态等发送间隔通常为30秒。类型24Class B静态消息分为A、B两部分A部分是船名B部分是船型、尺寸和天线位置用于替代类型5。避碰计算的实际输入是类型1、2、3和18中的动态度字段船型尺寸则来自类型5和24。如果只统计轨迹忽略静态消息会追不上目标船的实际轮廓后续计算安全会遇距离时也没有依据。2.2 AIVDM报文位结构与6-bit ASCII解码AIS链路层数据在网络层以NMEA 0183句子传输最常见前缀是!AIVDM。一条完整的句子如下!AIVDM,1,1,,A,15M67FC000G?ufbEFepT3n00Sa,0*5C字段之间用逗号分隔第一个1是消息片段总数第二个1是当前片段序号紧接着的是连续消息ID和无线信道代码逗号后面那串15M67...才是真正的payload末尾的0是填充位数量5C是异或校验和。AIS payload使用6-bit ASCII编码每个字符表示6个比特因此一条168 bit的位置报告刚好由28个可见字符组成。6-bit ASCII的解码规则并不复杂把字符的ASCII码减48如果结果大于40再减8就得到原始6位值。下面给出可以直接使用的解码函数。def bits_from_payload(payload: str) - str: 将AIVDM payload还原为连续的位串 bits for ch in payload: v ord(ch) - 48 if v 40: # ASCII 0x60-0x77 的字符 v - 8 bits format(v, 06b) return bits def int_from_bits(bits: str, start: int, length: int) - int: 从位串中取无符号整数 return int(bits[start:start length], 2) def signed_from_bits(bits: str, start: int, length: int) - int: 从位串中取有符号整数按二进制补码解释 v int(bits[start:start length], 2) if v (1 (length - 1)): v - 1 length return v这里payload是NMEA句子中!AIVDM,1,1,,A,后面的那一段。6-bit ASCII编码表有40个常规字符和40个偏移字符v 40的判断专门处理0x60及以上的字符比如反引号和小写字母。补码解释用于处理经度、纬度、ROT这些有符号字段避免把负值当成巨大的正整数。消息类型1、2、3的重要位段定义如下起始位从0开始计数字段起始位长度计算说明消息类型061、2、3表示Class A船位重复指示620为原始发射MMSI8309位海上移动业务识别码导航状态3840在航、1锚泊、2失控等转向率ROT428补码-128为不可用对地航速SOG5010除以10得到节位置精度6010低精度1高精度经度6128除以600000得到度东经正纬度8927除以600000得到度北纬正航迹向COG11612除以10得到度真航向HDG1289整数度511为不可用UTC秒137660到63为无效解析函数只需要把位段按表格切出来。注意经纬度的单位是1/10000角分即每一度对应600000个单位而不是常见的1e7。这个单位换算容易写错建议把600000定义为模块级常量。def parse_position_report(payload: str) - dict: 解析Class A位置报告只保留避碰计算需要的字段 b bits_from_payload(payload) msg_type int_from_bits(b, 0, 6) if msg_type not in (1, 2, 3): raise ValueError(f不是Class A位置报告: type{msg_type}) rot_signed signed_from_bits(b, 42, 8) sog_raw int_from_bits(b, 50, 10) lon_raw signed_from_bits(b, 61, 28) lat_raw signed_from_bits(b, 89, 27) return { mmsi: int_from_bits(b, 8, 30), nav_status: int_from_bits(b, 38, 4), rot_deg_min: None if rot_signed -128 else rot_signed / 4.733, sog_knots: None if sog_raw 1023 else sog_raw / 10.0, lon: lon_raw / 600000.0, lat: lat_raw / 600000.0, cog_deg: int_from_bits(b, 116, 128) / 10.0, hdg_deg: int_from_bits(b, 128, 137), utc_sec: int_from_bits(b, 137, 143), }参数说明sog_raw 1023视为无效因为SOG的10位全为1表示无可用数据1022表示“102.2节或更高”实际中不会出现在船舶上ROT的-128表示设备没有给出转向信息其余值除以4.733得到度/分钟utc_sec取自消息内的时间戳但它描述的是消息生成时刻的秒字段不是接收时刻采集端必须额外记录自己的接收时间避碰计算统一以接收端时间为准。2.3 速度、转向率与位置精度对避碰的影响SOG和COG直接决定对方船的相对运动矢量ROT则用来预测目标船未来几秒的航向变化趋势。在追越和交叉相遇场景中ROT比瞬时航向更能说明对方是否在转向让船。ROT的量化间隔是4.733度/分钟低速转向时这个分辨率偏低可能超过半分钟才能体现出一个航向变化在计算TCPA时不直接把ROT并入线性外推而是把它当作短时预警的辅助判据。位置精度字段需要单独处理。AIS的定位源多数是GPS部分船舶接入了差分信号。位置精度为1表示高精度差分定位定位误差在10米以内为0表示普通定位误差可能达到几十米。两条船在小倾角对遇时DCPA本身就只有几百米10米和50米的定位误差足以改变危险等级。建议在数据入库时保留这个字段并在CPA计算中给不同精度来源的目标船设置额外安全裕度。3. 采集系统整体链路天线、接收机、网关与数据落库3.1 接收链路从VHF天线到串口服务器一个标准的岸基AIS接收站包括VHF天线、低噪声放大模块通常集成在接收机内部、AIS接收机、串口服务器和采集服务器。AIS接收机解调两个VHF信道后输出NMEA 0183句子标准波特率是38400 bps数据格式为8位无校验、1位停止位。常见的工业串口服务器把RS-422或RS-232转为TCP采集端通过Socket连接避免长距离串口线带来的电平损耗和干扰。天线安装高度和位置直接制约接收距离。AIS信号在海上的传播接近视距天线高度每提高10米理论视距增加约12.8%。接收系统的工程重点不是追求最远距离而是保证覆盖区内的时隙冲突可控。在船舶密度大的港口两个相邻时隙的报文会互相叠加硬件接收机无法解码表现为接收端消息速率周期性下降。可以架设两套天线分别接两台接收机一台偏向航道入口一台覆盖锚地后端按MMSI和时间戳做去重。高通公司的AIS接收器件方案在行业OEM设备中确实有出现但那是芯片级选型并不影响上层数据格式。做采集系统的人只需要按NMEA标准解析上层句子不必关心接收机内部的射频前端处理流程。3.2 数据接入层的并发处理与乱序串口服务器输出的是字节流应用层要自行完成NMEA分帧。AIVDM句子以!开头以\r\n结尾句子最大长度为82字符多片段消息还需要按!AIVDM,2,2等形式拼接。下面的代码给出一个最小可用的串口读取循环。import serial def read_nmea_stream(port: str, baud: int 38400): 读取串口并逐条产出NMEA句子 with serial.Serial(port, baud, timeout0.2) as ser: buffer b while True: buffer ser.read(4096) while b\r\n in buffer: line, buffer buffer.split(b\r\n, 1) text line.decode(ascii, errorsignore) if text.startswith(!AIVDM) or text.startswith(!AIVDO): yield text这里用split(b\r\n, 1)按行切分每次只处理一个完整句子避免了字节碎片的拼接问题。timeout0.2保证串口在空闲时不会阻塞主循环允许上层ready做心跳监控。如果使用TCP方式接入串口服务器把serial.Serial换成socket.makefile即可解析逻辑完全相同。多接收机的情况下会出现两条问题同一艘船的两个信道消息几乎同时到达或者两台接收机对同一条消息重复上报。去重逻辑不能只按MMSI去重因为同一MMSI的船位是周期性变化的。常见的做法是用(mmsi, utc_sec, lon, lat)作为去重键或者比较相邻两条同MMSI消息的接收时间差小于500毫秒的视为重复。消息时间戳的乱序也要处理接收端收到消息的本地时间可能早于前一条写入数据库前需要按MMSI缓存最近一条的位置和时间避免把历史消息当成最新船位。3.3 存储选型时序库与关系表的取舍AIS的数据量和更新特征很明确繁忙港口一天可能收到数千万条位置报告每条解析后包含MMSI、时间、经纬度、航速、航向等十来个字段。避碰系统多数按最近10到30分钟的窗口做实时计算同时需要保留几个月到一年的轨迹数据用于事后复盘。这种情况下单一数据库很难同时满足高写入和时空查询需求。下面给出三种常见方案的对比按项目的技术栈取舍即可存储方案实时写入能力轨迹回放查询运维成本PostgreSQL TimescaleDB每秒数千条超表按时间分区查询方便需要维护扩展和分区策略InfluxDB每秒上万点时序查询方便但轨迹回放不够直观老版本集群复杂MySQL 普通表按日分区每秒几百条索引合适时可接受结构简单适合小站小规模岸基站点直接用MySQL按日分区就够用写入和查询都简单需要做长时间范围历史分析和实时流计算的项目直接上TimescaleDB。无论选哪种时间字段必须用UTC不能用当地时间。AIS船位是在全球范围内交换的一旦混入时区偏移CPA计算会差出一整个避碰决策周期。4. 避碰数据融合计算CPA/TCPA与危险船判定4.1 把经纬度轨迹转为相对运动参数AIS给出的经纬度是球面坐标而避碰判断关心的是平面上两艘船的相对距离和接近速率。在开阔水域的几海里范围内直接用等距圆柱近似即可满足工程精度把本船位置作为原点目标船投影到以米为单位的ENU平面坐标上。每度纬度对应的地面距离约为111319.9米每度经度对应的距离需要乘以本船所在纬度的余弦值。这种投影在50海里范围内误差可以忽略超过100海里后误差明显增大但AIS避碰通常不关心那么远的距离。远距离目标船进入警戒圈之前先按经纬度粗筛距离小于20海里再用投影坐标做精确计算。4.2 CPA/TCPA的完整计算代码最近会遇距离DCPA和最近会遇时间TCPA是避碰判断的核心输出。计算思路是目标船相对本船的位置矢量减去本船速度矢量得到相对速度位置矢量在相对速度方向上的投影除以相对速度大小取负号就得到最近会遇时间再把该时间代回相对位置公式得到最近点距离。import math from dataclasses import dataclass NM_TO_M 1852.0 dataclass class VesselState: lat: float lon: float course: float # 对地航向度 speed: float # 对地航速节 def project_to_enu(ref_lat: float, ref_lon: float, lat: float, lon: float): 以参考点为原点的等距圆柱投影返回x(东)、y(北)米 lat0_r math.radians(ref_lat) x (lon - ref_lon) * 111319.9 * math.cos(lat0_r) y (lat - ref_lat) * 111319.9 return x, y def course_speed_to_velocity(course_deg: float, speed_kn: float): 航向与航速转ENU速度分量单位米/秒 r math.radians(course_deg) v speed_kn * 0.514444 return v * math.sin(r), v * math.cos(r) def calc_cpa_tcpa(own: VesselState, target: VesselState): 返回(DCPA米, TCPA秒) tx, ty project_to_enu(own.lat, own.lon, target.lat, target.lon) dx0, dy0 tx, ty ovx, ovy course_speed_to_velocity(own.course, own.speed) tvx, tvy course_speed_to_velocity(target.course, target.speed) vrx, vry tvx - ovx, tvy - ovy v2 vrx * vrx vry * vry if v2 1e-9: return math.hypot(dx0, dy0), 0.0 tcpa -(dx0 * vrx dy0 * vry) / v2 if tcpa 0: tcpa 0.0 dcpa math.hypot(dx0 vrx * tcpa, dy0 vry * tcpa) return dcpa, tcpa参数说明own和target的course统一用对地航向COGspeed用对地航速SOG单位分别是度和节。project_to_enu把目标船投影到以本船为原点的平面坐标本船自身坐标始终是(0,0)所以原始相对位置直接取目标船投影值。tcpa如果是负值说明目标船正在远离此时把tcpa截断为0DCPA退化为当前距离。v2接近0表示两船同速同向此时相对位置不再变化直接返回当前距离。阈值的设定没有统一标准下面是业内常见的经验值航行场景DCPA阈值海里TCPA阈值分钟开阔洋面1.030近岸航路 / 分道通航0.515港区 / 锚地附近0.310狭窄水道 / 渡轮区0.25阈值需要按船舶类型做分级。大型油轮和集装箱船的操纵性差同样的DCPA和TCPA下应该更早告警高速客船虽然反应快但接近速度快TCPA阈值要适当放大。实际部署时把阈值表做成可配置项由航行管理人员按港口交通流调整。4.3 危险船排序与位置修正计算得到全部目标船的DCPA和TCPA之后不能只按DCPA从小到大排序。一艘DCPA很小但TCPA为负的船正在远离不构成当前威胁一艘DCPA为0.8海里但TCPA只有6分钟的船反而需要立即关注。合理的排序方式是综合两个维度先按TCPA筛选掉远离目标再按DCPA/TCPA组合值排序或者直接用带权评分函数。AIS位置还有两个容易忽略的偏差。第一船位报告的是GNSS天线位置不是船舶几何中心。一艘180米长的集装箱船天线可能装在驾驶台顶部距离船首七八十米。计算DCPA时如果不加修正两船实际上已经擦碰计算结果却显示有0.1海里的富余。修正方法是从类型5或24中读取船舶尺寸和天线位置偏移把目标船位置沿其航向方向平移到船首或船体边缘。第二AIS更新间隔在低速或锚泊状态下会拉长到3分钟在这段空窗期内船位和航向都是过时的。对TCPA小于更新周期的目标船需要用当前航速航向做外推同时把置信度标记降低避免告警界面出现“幻影碰撞”。5. 采集系统的自测与工程落地技巧5.1 用信号发生器与回放做端到端验证没有条件上实船的团队可以用带AIS回放功能的北斗/GNSS模拟器或开源AIS消息生成器把标准NMEA句子注入接收机的串口或直接注入数据接入层。验证时先确认解析结果和报文字段一一对应再人为加入乱序、重复和缺失字段。工作的顺序是先验证单条消息的解析正确性再验证两条消息之间的时间推进最后压测数据接入层在每秒几百条消息下的处理延迟。回放数据建议直接用VTS系统导出的历史日志。把日志文件按时间戳重放数据接入层不做任何特殊处理解析后与日志里的GPS基准轨迹对比统计位置误差和漏报率。这里有一个实用校验技巧选择一艘位置连续的目标船计算相邻两帧之间的航速反推值与报文里的SOG比较误差超过0.5节就说明时间戳或解析位段有问题。5.2 数据质量监控的实用指标采集系统上线后需要持续监控下面几项指标每秒消息数、每分钟活跃MMSI数、NMEA校验和错误率、单船更新间隔超过阈值的比例、连续位置跳跃的数量。校验和错误率高说明射频链路有干扰或串口连接接触不良单船更新间隔异常说明接收机丢失了该船的大量时隙表面上是数据采集问题实际上可能已经影响避碰决策。质量监控代码可以从下面这个简化的位置质量检查入手。def check_position_quality(row, last_row, max_speed_kn60): 检查单条船位数据的合理性返回告警标记 if abs(row[lat]) 90 or abs(row[lon]) 180: return invalid_coord if last_row is None: return ok dist_m haversine_meters(row, last_row) dt_s row[rcv_ts] - last_row[rcv_ts] if dt_s 0 and dist_m / dt_s max_speed_kn * 0.514444: return jump return okmax_speed_kn按船型设置普通商船取60节足够覆盖高速客船超过这个速度的位置跳跃大概率是解析错误或消息串台。位置跳跃发现后不要直接丢弃还要检查该MMSI下一条消息是否恢复正常连续多次跳跃才需要进入黑名单。这样既避免单条坏数据触发误告警又能及时发现接收信道持续冲突的问题。5.3 高频数据下的去重与缓存策略实时避碰计算窗口通常只有10到30分钟内存缓存可以显著降低数据库压力。用Redis或进程内哈希表维护每个MMSI的最新船位只有当位置变化超过设定阈值时才写库静止船舶每3分钟写一条即可。同一MMSI在双信道同时出现在缓存中时以接收到时间较晚的一条为准不保留两条记录。数据接入层处理多片段AIS消息时要设置一个拼接超时比如3秒内未收齐所有片段就丢弃。AIS船位报告都是单片段消息多片段主要用于类型5和24静态消息这类消息晚几秒不影响避碰判断。给每种消息类型设置独立的处理优先级位置报告最高静态消息次之基站和航标消息直接透传进原始日志即可避免接收机缓存堆满造成新数据丢包。本文还有配套的精品资源点击获取
返回列表