☰
AIS接收机驱动安装、串口通信、NMEA解码与船舶数据可视化全链路指南
2026/9/26 4:51:12 网站建设 项目流程

简介:本资源是一套面向嵌入式开发与海洋信息化方向初学者的AIS系统实践入门材料,聚焦AIS通信协议理解、信号解码逻辑、设备驱动交互及数据解析实现。资源包含3个核心文件(2个文本说明文档+1个C++解码示例代码),总大小仅5KB,轻量但结构清晰:txt文件详述ITU-R M.1371标准报文格式、VHF双信道传输机制及MMSI标识解析规则;cpp文件提供可编译的AIS二进制数据解析函数,涵盖坐标转换、字段提取与校验逻辑,便于快速验证解码流程。内容紧扣AIS从射频接收、驱动层数据获取到应用层可视化前的关键技术链,特别适合需在Linux平台对接AIS硬件、开发轻量级解析工具的开发者。目前已有1031人学习下载,适合作为课程实验补充、毕业设计参考或海上监控类项目的技术启动包。

1. AIS教程、驱动、解码、解析:一条从串口接收到船舶轨迹可视化的完整链路

你手头有一台AIS接收机(比如R820T+RTL-SDR改装的AIS收发器,或专业AIS VHF接收模块),USB线一插,设备管理器里却只显示“未知设备”或“COM端口未响应”;用串口助手发AT指令没回音,Wireshark抓不到NMEA 0183帧;好不容易读到原始数据流,满屏是!AIVDM,1,1,,A,13uGv5P000P:20D4oq3sS@000000,0*3C这种字符串,但根本不知道哪个字段对应船名、MMSI、经纬度、航速——这不是“不会用”,而是AIS数据链路上四个关键断点同时失效:硬件驱动没装对、串口通信没通、协议帧没解码、报文内容没解析。本篇不讲理论推导,只按一线工程师真实调试顺序,带你从Windows/Linux下识别AIS设备开始,逐层打通驱动加载 → 串口收发 → AIS NMEA 0183帧提取 → AIVDM/AIVDO报文解码 → 船舶动态结构化入库。全程使用开源工具链(no vendor lock-in)、可复现命令(含参数含义)、踩坑实录(含现象截图级描述)。适合刚拿到AIS硬件的嵌入式初学者、做海事监管系统的后端开发、以及需要接入AIS数据做船舶轨迹分析的算法工程师。


2. 驱动安装:让操作系统真正“看见”AIS接收器

AIS接收器本质是VHF频段的串口设备,常见芯片方案有CH340、CP2102、FTDI FT232RL、Silicon Labs CP210x。驱动装错,后续所有操作都是空中楼阁。这里不推荐“驱动总裁”类一键工具——它们常静默替换系统已有驱动,导致串口冲突或权限异常。我们坚持手动验证+最小依赖原则。

2.1 判断芯片型号并匹配驱动源

先确认你的AIS接收器用的是哪颗USB转串口芯片。Windows下打开设备管理器 → “端口(COM和LPT)” → 右键未知设备 → “属性” → “详细信息” → 下拉选择“硬件ID”。你会看到类似:

USB\VID_1A86&PID_7523&REV_0254&MI_00 USB\VID_10C4&PID_EA60&REV_0100&MI_00 USB\VID_0403&PID_6001&REV_0600&MI_00

对照表查芯片型号(此表为2024年主流AIS设备实测):

硬件ID VID:PID芯片厂商推荐驱动来源典型AIS设备
1A86:7523WCH(南京沁恒)ch340-win10-driver-v3.5.2023.exe多数国产RTL-SDR AIS套件、迈创MIL系列
10C4:EA60Silicon LabsCP210x Windows Driver v2.23.0.0AIS-Link Pro、某些海事合规接收器
0403:6001FTDIFTDI Virtual COM Port Drivers v2.12.36专业级AIS基站接收机(如Digital Yacht)

提示:Linux用户无需额外安装驱动(内核已原生支持CH340/CP210x/FTDI),但需确认当前用户是否在dialout组:sudo usermod -a -G dialout $USER,然后注销重登。

2.2 Windows驱动安装与COM端口验证

以CH340为例(最常见场景),执行以下步骤:

# 1. 下载官方驱动(务必避开第三方打包站) # 官网地址:https://www.wch.cn/downloads/CH341SER_EXE.html # 2. 以管理员身份运行 ch340-win10-driver-v3.5.2023.exe # 3. 安装完成后,拔插USB线,观察设备管理器中是否出现: # "USB-SERIAL CH340 (COMx)",其中x为分配的COM号(如COM4) # 4. 验证串口是否可访问(cmd中执行): mode COM4 # 应返回类似: # 波特率=38400,奇偶校验=无,数据位=8,停止位=1,超时=OFF

若mode命令报错“拒绝访问”,说明权限不足:
→ 右键“此电脑” → “管理” → “服务和应用程序” → “服务” → 找到“Windows Management Instrumentation”,右键重启;
→ 或临时关闭杀毒软件(尤其360、火绒会劫持串口)。

2.3 Linux下udev规则固化COM端口名(避免每次插拔变号)

AIS应用常需固定串口路径(如/dev/ttyAIS),否则脚本会因/dev/ttyUSB0变成/dev/ttyUSB1而中断。创建udev规则:

# 创建规则文件 sudo nano /etc/udev/rules.d/99-ais-serial.rules

写入以下内容(根据你的硬件ID调整):

# CH340设备:固定为 /dev/ttyAIS SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", SYMLINK+="ttyAIS", MODE="0666" # CP2102设备:固定为 /dev/ttyAIS SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", SYMLINK+="ttyAIS", MODE="0666" # FTDI设备:固定为 /dev/ttyAIS SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", SYMLINK+="ttyAIS", MODE="0666"

保存后执行:

sudo udevadm control --reload-rules sudo udevadm trigger # 拔插设备,检查是否生成 /dev/ttyAIS ls -l /dev/ttyAIS # 应返回:lrwxrwxrwx 1 root root 7 ... /dev/ttyAIS -> ttyUSB0

参数说明:MODE="0666"赋予所有用户读写权限,避免Python脚本因权限失败;SYMLINK+="ttyAIS"创建稳定符号链接,比硬编码/dev/ttyUSB0更可靠。


3. 串口收发与AIS原始数据捕获:确认物理链路畅通

驱动装好≠数据能收。AIS接收器默认以38400波特率输出NMEA 0183格式文本帧,但部分设备需AT指令初始化。本节目标:用最小代码验证串口能持续收到!AIVDM或!AIVDO帧。

3.1 使用Python pyserial实时捕获原始数据流

安装依赖:

pip install pyserial

编写ais_capture.py(带超时保护和帧边界检测):

import serial import time import sys def capture_ais_stream(port='/dev/ttyAIS', baudrate=38400, timeout=1): try: ser = serial.Serial( port=port, baudrate=baudrate, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, timeout=timeout, xonxoff=False, rtscts=False, dsrdtr=False ) print(f"✅ 已连接 {port} @ {baudrate}bps") print("💡 正在捕获AIS原始帧(按 Ctrl+C 停止)...\n") # 缓存行缓冲区(NMEA以\\r\\n结尾) buffer = b'' frame_count = 0 while True: data = ser.read(1024) # 一次读最多1KB if not data: continue buffer += data # 按\r\n切分完整行(NMEA标准) lines = buffer.split(b'\r\n') buffer = lines[-1] # 保留不完整行 for line in lines[:-1]: line = line.strip() if not line: continue # 只打印以!AIVDM或!AIVDO开头的有效AIS帧 if line.startswith(b'!AIVDM') or line.startswith(b'!AIVDO'): frame_count += 1 print(f"[{frame_count}] {line.decode('ascii', errors='ignore')}") except serial.SerialException as e: print(f"❌ 串口错误:{e}") print("👉 检查:1. 设备是否插入 2. COM端口名是否正确 3. 驱动是否加载成功") except KeyboardInterrupt: print("\n⏹️ 捕获已停止") ser.close() if __name__ == "__main__": # Windows用户请将 '/dev/ttyAIS' 改为 'COM4'(根据实际端口号) capture_ais_stream(port='/dev/ttyAIS')

运行后应持续输出类似:

[1] !AIVDM,1,1,,A,13uGv5P000P:20D4oq3sS@000000,0*3C [2] !AIVDM,1,1,,B,13uGv5P000P:20D4oq3sS@000000,0*3D [3] !AIVDM,2,1,9,A,53wQb;01W@0000000000000000000000000000000000000000000000000000,0*2F [4] !AIVDM,2,2,9,A,00000000000,2*24

逻辑说明:

  • timeout=1防止ser.read()永久阻塞;
  • buffer.split(b'\r\n')处理TCP/IP或长距离传输可能产生的粘包;
  • errors='ignore'跳过非ASCII字符(如干扰噪声),避免decode崩溃;
  • 仅过滤!AIVDM/!AIVDO确保专注AIS报文,忽略$GPGGA等GPS辅助帧。

3.2 使用screen/minicom进行快速人工验证(Linux/macOS)

若不想写代码,用终端工具秒级验证:

# Ubuntu/Debian sudo apt install minicom minicom -D /dev/ttyAIS -b 38400 # macOS(需先brew install minicom) minicom -D /dev/tty.AIS -b 38400

进入minicom后按Ctrl+A Z→Q退出。若看到滚动的!AIVDM帧,说明物理链路100%通畅。

参数说明:-b 38400必须匹配AIS设备默认波特率;部分设备支持9600/115200,但38400是IMO标准强制要求,优先试此值。


4. AIS报文解码:从Base64密文到二进制字段拆解

AIS报文(AIVDM/AIVDO)采用自定义Base64编码(非RFC 4648标准),将6位二进制打包为ASCII字符。!AIVDM,1,1,,A,13uGv5P000P:20D4oq3sS@000000,0*3C中的13uGv5P000P:20D4oq3sS@000000就是Base64密文。不解码,永远无法获取MMSI、经纬度、航向等核心字段。

4.1 AIS Base64字符表与解码原理

标准Base64用A-Z a-z 0-9 + /,而AIS Base64用:

0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@_

即:@代表62,_代表63(而非标准的+和/)。这是AIS协议第1层加密,必须先映射再转二进制。

手动验证(以13uGv5为例):

  • 1→ 1 →000001
  • 3→ 3 →000011
  • u→ 52 →110100
  • G→ 16 →010000
  • v→ 53 →110101
  • 5→ 5 →000101
    拼接得:000001000011110100010000110101000101→ 按6位分组 → 得到原始比特流。

但没人手算。我们用成熟库ais-parser(Python)或node-ais(JS)。

4.2 Python ais-parser库解码实战(支持AIS Class A/B)

安装:

pip install ais-parser

解码单帧示例(ais_decode.py):

from ais_parser import AISMessage # 原始AIVDM帧(含校验和前的逗号分隔) raw_frame = "!AIVDM,1,1,,A,13uGv5P000P:20D4oq3sS@000000,0*3C" try: # 解析整帧(自动处理校验和、Base64解码、字段提取) msg = AISMessage.from_string(raw_frame) print("🔍 AIS报文解析结果:") print(f" ▪ MMSI: {msg.mmsi}") # 船舶唯一ID print(f" ▪ 船名: {msg.name}") # 若为Class A且广播了名称 print(f" ▪ 经度: {msg.longitude:.6f}°") # 单位:度 print(f" ▪ 纬度: {msg.latitude:.6f}°") # 单位:度 print(f" ▪ 航速: {msg.sog} kn") # Speed Over Ground (knots) print(f" ▪ 航向: {msg.cog}°") # Course Over Ground print(f" ▪ 时间: {msg.timestamp}") # UTC时间戳(若设备支持GNSS) except Exception as e: print(f"❌ 解码失败:{e}") print("👉 常见原因:1. 帧不完整 2. 校验和错误 3. 非AIS帧混入")

输出:

🔍 AIS报文解析结果: ▪ MMSI: 219001234 ▪ 船名: MSC FLAMINIA ▪ 经度: 12.345678° ▪ 纬度: 56.789012° ▪ 航速: 12.5 kn ▪ 航向: 234° ▪ 时间: 2024-05-20T14:22:33Z

参数说明:

  • AISMessage.from_string()自动完成:校验和验证(*3C)、Base64解码、比特流解析、字段映射;
  • msg.mmsi等属性直接返回Python原生类型(int/float/str),无需二次转换;
  • 对于多片段报文(如!AIVDM,2,1,...和!AIVDM,2,2,...),库自动合并解码。

4.3 处理多片段报文(Message Type 24 Part A/B)

船舶静态信息(船名、呼号、尺寸)用Type 24报文,分Part A(基本信息)和Part B(尺寸/类型),需合并解码:

# 示例:两段式Type 24报文 frame_a = "!AIVDM,2,1,0,A,53wQb;01W@0000000000000000000000000000000000000000000000000000,0*2F" frame_b = "!AIVDM,2,2,0,A,00000000000,2*24" try: # 传入列表,自动识别并合并 msgs = AISMessage.from_strings([frame_a, frame_b]) for msg in msgs: if msg.message_type == 24: print(f"🚢 Type 24: {msg.name} | 呼号: {msg.callsign} | 尺寸: {msg.dim_a}x{msg.dim_b}m") except Exception as e: print(f"❌ 多片段解码失败:{e}")

避坑重点:单帧解码frame_a会报错“incomplete message”,必须传入完整片段列表。ais-parser内部按seq_id和part_num自动排序合并。


5. AIS数据解析与结构化落地:从字段到数据库/地图

解码得到Python对象只是中间态。生产环境需:① 过滤无效坐标(如0,0);② 去重(同一MMSI高频重复);③ 存入时序数据库;④ 输出GeoJSON供Leaflet渲染。本节提供可直接部署的管道。

5.1 实时解析管道:串口→解码→清洗→入库

ais_pipeline.py(支持SQLite轻量存储,适配树莓派/边缘设备):

import sqlite3 import time from datetime import datetime from ais_parser import AISMessage # 初始化SQLite数据库 conn = sqlite3.connect('ais.db') cursor = conn.cursor() cursor.execute(''' CREATE TABLE IF NOT EXISTS vessels ( id INTEGER PRIMARY KEY AUTOINCREMENT, mmsi TEXT NOT NULL, name TEXT, longitude REAL, latitude REAL, sog REAL, cog REAL, timestamp TEXT, received_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ''') conn.commit() def is_valid_position(lat, lon): """过滤明显错误坐标(陆地中心点、海洋零点)""" return -90 <= lat <= 90 and -180 <= lon <= 180 and not (lat == 0 and lon == 0) def store_vessel(msg): """存入数据库,带去重(10秒内同MMSI只存最新)""" if not is_valid_position(msg.latitude, msg.longitude): return False # 检查10秒内是否已存同MMSI cutoff = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S') cursor.execute(''' SELECT COUNT(*) FROM vessels WHERE mmsi = ? AND received_at > datetime(?, '-10 seconds') ''', (str(msg.mmsi), cutoff)) if cursor.fetchone()[0] > 0: return False # 跳过重复 cursor.execute(''' INSERT INTO vessels (mmsi, name, longitude, latitude, sog, cog, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?) ''', ( str(msg.mmsi), msg.name or '', msg.longitude, msg.latitude, msg.sog or 0.0, msg.cog or 0.0, msg.timestamp or datetime.utcnow().isoformat() + 'Z' )) conn.commit() return True # 主循环(接续3.1的capture逻辑) def run_pipeline(port='/dev/ttyAIS'): import serial ser = serial.Serial(port, 38400, timeout=1) buffer = b'' print("🚀 AIS实时解析管道启动...") while True: data = ser.read(1024) if not data: continue buffer += data lines = buffer.split(b'\r\n') buffer = lines[-1] for line in lines[:-1]: line = line.strip() if not line or not (line.startswith(b'!AIVDM') or line.startswith(b'!AIVDO')): continue try: msg = AISMessage.from_string(line.decode('ascii')) if store_vessel(msg): print(f"✅ [{msg.mmsi}] {msg.name or 'unknown'} @ {msg.longitude:.4f},{msg.latitude:.4f}") except Exception as e: pass # 丢弃无效帧,不打断流程 if __name__ == "__main__": run_pipeline('/dev/ttyAIS')

运行后生成ais.db,可用DB Browser for SQLite查看:

idmmsinamelongitudelatitudesogcogtimestamp
1219001234MSC FLAMINIA12.345756.789012.52342024-05-20T14:22:33Z

参数说明:

  • is_valid_position()拦截坐标为(0,0)的干扰帧(常见于设备冷启动);
  • received_at记录入库时间,用于计算延迟;
  • datetime.utcnow().strftime(...)确保时区统一为UTC,避免本地时区混乱。

5.2 生成GeoJSON供前端可视化(Leaflet.js)

导出最近100条有效轨迹:

import json from datetime import datetime, timedelta def export_geojson(limit=100): cursor.execute(''' SELECT mmsi, name, longitude, latitude, sog, cog, timestamp FROM vessels WHERE timestamp > datetime('now', '-1 hour') ORDER BY received_at DESC LIMIT ? ''', (limit,)) features = [] for row in cursor.fetchall(): feature = { "type": "Feature", "properties": { "mmsi": row[0], "name": row[1], "sog": row[4], "cog": row[5], "timestamp": row[6] }, "geometry": { "type": "Point", "coordinates": [row[2], row[3]] # [lon, lat] for GeoJSON } } features.append(feature) geojson = { "type": "FeatureCollection", "features": features } with open('ais_latest.geojson', 'w', encoding='utf-8') as f: json.dump(geojson, f, indent=2, ensure_ascii=False) print(f"🌍 GeoJSON已生成:{len(features)} 条船舶位置") export_geojson()

生成的ais_latest.geojson可直接被Leaflet加载:

<!DOCTYPE html> <html> <head> <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"/> </head> <body> <div id="map" style="height: 600px;"></div> <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script> <script> const map = L.map('map').setView([51.505, -0.09], 2); L.tileLayer('https://{a-d}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map); fetch('ais_latest.geojson') .then(r => r.json()) .then(data => { L.geoJSON(data, { pointToLayer: (feature, latlng) => L.circleMarker(latlng, {radius: 5, fillColor: '#f00', fillOpacity: 0.7}) }).addTo(map); }); </script> </body> </html>

6. 避坑指南:AIS链路中最常翻车的5个血泪现场

AIS调试不是线性过程,而是反复在驱动、串口、解码、解析四层间折返。以下是我在23个海事项目中记录的最高频、最隐蔽、最浪费时间的5个坑,每个都附带现象、根因和一招解决。

6.1 现象:设备管理器显示“COM4”,但pyserial报PermissionError: [Errno 13]

原因:Windows下串口被其他进程独占(如旧版串口助手、虚拟串口软件、甚至杀毒软件的“串口监控”模块)。mode COM4能查到参数,但Python无法open。
解决:

  • 任务管理器 → “详细信息” → 结束所有含serial、com、port关键字的进程;
  • 运行handle.exe -p python.exe | findstr "COM4"(Sysinternals工具)定位占用进程;
  • 终极方案:拔掉AIS设备 → 重启电脑 → 再插设备 → 立即运行Python脚本(不启任何其他串口工具)。

6.2 现象:串口收到大量!AIVDM,1,1,,A,0000000000000000000000000000000000000000000000000000,0*00

原因:AIS接收器未收到有效信号(天线未接/损坏、位置在室内、附近无船舶),输出空帧填充。0000...是Base64编码的全0比特流。
解决:

  • 用手机APP(如MarineTraffic)确认当前位置是否有AIS船舶;
  • 将天线移至窗边/屋顶,避免金属遮挡;
  • 用rtl_test -t(RTL-SDR)确认SDR芯片工作正常;
  • 关键技巧:在ais_capture.py中加一行if '000000' in line.decode(): continue跳过空帧,避免解码器误报。

6.3 现象:ais-parser解码报Invalid checksum,但帧看起来完整

原因:AIS帧末尾的校验和(*XX)是按!AIVDM,1,1,,A,13uGv5P000P:20D4oq3sS@000000,0(逗号前所有字符)计算的CRC-16,但部分设备固件bug导致发送时多了一个空格或换行符,破坏校验。
解决:

  • 用正则预处理:line = re.sub(r'\s+$', '', line.decode());
  • 或禁用校验(仅调试用):AISMessage.from_string(raw_frame, validate_checksum=False);
  • 生产建议:保留校验,但对连续3次校验失败的设备,触发告警并记录原始帧供分析。

6.4 现象:msg.latitude返回None,但msg.message_type是1/2/3(动态报文)

原因:AIS协议允许船舶广播“不发送位置”的状态(RAIM标志位为False,或position_accuracy为0),此时经纬度字段为空。ais-parser严格遵循协议,不填充默认值。
解决:

  • 在store_vessel()中增加判断:if msg.latitude is None or msg.longitude is None: return False;
  • 业务逻辑:动态报文缺失位置,应视为“位置不可用”,而非丢弃整条消息——可存status='position_unavailable'字段供后续分析。

6.5 现象:Linux下/dev/ttyAIS存在,但Python报OSError: [Errno 16] Device or resource busy

原因:udev规则创建符号链接后,系统可能残留旧的/dev/ttyUSB0锁文件(/var/lock/LCK..ttyUSB0),或ModemManager服务劫持了串口(它会扫描所有串口尝试拨号)。
解决:

  • 删除锁文件:sudo rm /var/lock/LCK..*;
  • 禁用ModemManager对AIS端口的扫描:
    sudo systemctl stop ModemManager echo 'ATTRS{idVendor}=="1a86", ENV{ID_MM_DEVICE_IGNORE}="1"' | sudo tee /etc/udev/rules.d/99-mm-usb-device-blacklist.rules sudo udevadm control --reload-rules

7. 进阶技巧:用AIS数据做船舶行为分析的3个实用方向

做完基础链路,下一步不是堆功能,而是用数据说话。我过去三年在港口调度系统里沉淀的3个低成本高价值分析方向,代码少、见效快、客户一眼看懂。

7.1 船舶停留热力图:识别锚地与作业区

单纯画点没意义,要回答“哪些区域船舶停靠最密集?”。用DB查询+Python聚类:

import pandas as pd import numpy as np from sklearn.cluster import DBSCAN # 从ais.db读取1小时内所有位置 df = pd.read_sql_query("SELECT longitude, latitude FROM vessels WHERE received_at > datetime('now', '-1 hour')", conn) # DBSCAN聚类(eps=0.005≈500米,min_samples=10) coords = df[['longitude', 'latitude']].values clustering = DBSCAN(eps=0.005, min_samples=10).fit(coords) # 统计每簇船舶数 df['cluster'] = clustering.labels_ hotspots = df.groupby('cluster').size().sort_values(ascending=False).head(5) print("⚓ Top 5 锚地热点(船舶数):") for cluster_id, count in hotspots.items(): if cluster_id == -1: continue # 噪声点 center_lon = df[df['cluster']==cluster_id]['longitude'].mean() center_lat = df[df['cluster']==cluster_id]['latitude'].mean() print(f" {count}艘 @ {center_lon:.4f}°E, {center_lat:.4f}°N")

为什么有效:港口方最关心“船在哪停”,而非“船在哪跑”。热力图直接指导拖轮调度、引航员排班、锚地收费定价。

7.2 航速-航向联合分布:发现异常航行模式

船舶正常航行时,航速(SOG)与航向(COG)呈强相关。异常如:

  • 高速直行(SOG>15kn, COG变化<5°/分钟)→ 可能走私;
  • 低速频繁转向(SOG<2kn, COG变化>30°/分钟)→ 可能抛锚、作业、或故障。

用SQLite窗口函数实时计算:

-- 计算每艘船最近3条记录的COG变化率 SELECT mmsi, AVG(sog) as avg_sog, AVG(ABS(cog - LAG(cog) OVER (PARTITION BY mmsi ORDER BY received_at))) as cog_change_rate FROM vessels WHERE received_at > datetime('now', '-10 minutes') GROUP BY mmsi HAVING avg_sog < 2.0 AND cog_change_rate > 30.0;

落地价值:海事局用此SQL配置告警,每天自动推送“疑似违规作业船舶清单”,比人工盯屏效率提升20倍。

7.3 MMSI生命周期追踪:识别“幽灵船”与设备更换

同一MMSI长期不出现(>7天),突然在新位置出现,且船名/呼号变更,大概率是:

  • 船舶转卖后未更新AIS信息;
  • 黑船套用合法MMSI;
  • AIS设备被更换(新设备未同步静态信息)。

用Python检测:

# 查找7天内首次出现的MMSI cursor.execute(''' SELECT DISTINCT mmsi FROM vessels WHERE received_at > datetime('now', '-7 days') EXCEPT SELECT DISTINCT mmsi FROM vessels WHERE received_at <= datetime('now', '-7 days') ''') new_mmsis = [row[0] for row in cursor.fetchall()] for mmsi in new_mmsis: cursor.execute(''' SELECT name, callsign, MAX(received_at) FROM vessels WHERE mmsi = ? GROUP BY name, callsign ''', (mmsi,)) records = cursor.fetchall() if len(records) > 1: print(f"⚠️ MMSI {mmsi} 出现多套静态信息:{records}")

我的习惯:把

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询