alphafox02/iridium-sniffer

GitHub: alphafox02/iridium-sniffer

轻量级独立铱星卫星突发信号检测与解调工具,以纯 C 实现替代 gr-iridium,内置 ACARS 解码、实时网页地图和多普勒定位功能。

Stars: 154 | Forks: 27

# iridium-sniffer 一个用 C 语言编写的独立 Iridium 卫星突发信号检测器和解调器。它通过消除对 GNU Radio 的依赖,提供了 [gr-iridium](https://github.com/muccc/gr-iridium) 的替代方案,同时在标准输出上生成相同的兼容 [iridium-toolkit](https://github.com/muccc/iridium-toolkit) 的 RAW 输出。对于希望使用轻量级、无依赖选项或需要嵌入式部署的用户,这提供了具有不同架构方法的类似功能。 支持通过 HackRF、BladeRF、USRP (UHD)、SDRplay (原生 API) 和 SoapySDR 进行实时捕获,或处理来自文件的 IQ 录制。可通过 OpenCL (NVIDIA、AMD、Intel) 作为运行时插件使用可选的 GPU 加速突发检测——主二进制文件可在没有 GPU 支持的系统上运行。通过预生成 FFTW wisdom,可在树莓派 5 和其他 ARM 开发板上以纯 CPU 模式运行。 内置网络地图 (`--web`,测试版) 提供了对解码的振铃警报位置和活动卫星的实时 Leaflet.js 可视化——无需外部工具或 Python。 内置的 ACARS/SBD 解码 (`--acars`) 可直接从 IDA 帧中提取航空消息。安装 [libacars-2](https://github.com/szpajder/libacars) 后,ARINC-622 应用层载荷 (ADS-C, CPDLC, OHMA) 将被完全解码——无需 Python 管道。 原生 GSMTAP 输出 (`--gsmtap`) 通过 UDP 将解码后的 IDA (Iridium Data) 帧直接发送到 Wireshark,从而无需使用 Python `iridium-parser.py -m gsmtap` 管道。 ## 功能 - 完整的 Iridium L 波段突发检测、下变频和 DQPSK 解调管道 - 直接的 iridium-toolkit RAW 输出,兼容 iridium-parser.py 和 reassembler.py - 内置 ACARS/SBD 解码 (`--acars`),可选支持 libacars-2 的 ARINC-622/ADS-C/CPDLC - 解析后的 IDA 输出模式 (`--parsed`),用于直接通过管道传输给 reassembler.py (ACARS/SBD 恢复) - Gardner 定时恢复(默认启用),用于改善弱突发信号的解调 - 原生 GSMTAP/LAPDm 输出至 Wireshark (`--gsmtap`),用于 IDA 帧分析 - 内置网络地图,带有实时卫星和振铃警报可视化 - 基于多普勒的接收机定位,来自解码的卫星信号 (`--position`) - AVX2 和 SSE4.2 SIMD 内核,具有自动运行时检测 (`--simd`) - GPU 加速的 FFT 突发检测 (OpenCL 或 Vulkan) - ZMQ PUB/SUB 输出 (`--zmq`),用于多消费者 iridium-toolkit 兼容性 - ZMQ SUB 和 VITA 49 (VRT) 网络 IQ 输入,用于远程 SDR 和分布式设置 - 多线程架构:检测、下变频池、解调、统计 - 支持 HackRF、BladeRF、USRP、SDRplay 和 SoapySDR - 读取 ci8、ci16 和 cf32 IQ 文件,通过文件扩展名自动检测 ## 安装 ### DragonOS Noble DragonOS Noble 预装了 HackRF、BladeRF、USRP (UHD)、SoapySDR 和 OpenCL 驱动程序。只需克隆并构建: ``` git clone https://github.com/alphafox02/iridium-sniffer.git cd iridium-sniffer mkdir build && cd build cmake .. make -j$(nproc) ``` CMake 会自动检测可用的 SDR 库、GPU 支持和 libacars。所有 SDR 后端、OpenCL GPU 加速和 ACARS ARINC-622 解码都会自动启用。 ### Ubuntu / Debian ``` git clone https://github.com/alphafox02/iridium-sniffer.git cd iridium-sniffer # 核心依赖 sudo apt install build-essential cmake libfftw3-dev # SDR 库(仅安装您拥有的) sudo apt install libhackrf-dev # HackRF One sudo apt install libbladerf-dev # BladeRF sudo apt install libuhd-dev # USRP (B2x0, N2x0, X3x0, etc.) sudo apt install libsoapysdr-dev # RTL-SDR, Airspy, LimeSDR, etc. via SoapySDR # SDRplay 原生 API:从 https://www.sdrpay.com/api/ 安装 # 可选:ACARS ARINC-622/ADS-C/CPDLC 解码 sudo apt install libacars-dev # libacars-2 # 可选:ZMQ 多消费者输出(替代 stdout 管道) sudo apt install libzmq3-dev # --zmq flag # 可选:GPU 加速突发检测 sudo apt install ocl-icd-opencl-dev # OpenCL (NVIDIA, AMD, Intel) mkdir build && cd build cmake .. make -j$(nproc) ``` CMake 输出会显示检测到的内容: ``` -- HackRF: enabled -- BladeRF: enabled -- USRP (UHD): enabled -- SoapySDR: enabled -- libacars: enabled (ARINC-622/ADS-C/CPDLC decoding) -- ZMQ: enabled (multi-consumer PUB/SUB output) -- GPU acceleration: OpenCL ``` ### Raspberry Pi 5 / ARM Pi 5 的 VideoCore VII GPU 通过了基本的 Vulkan 计算测试,但无法维持实时 FFT 批处理所需的吞吐量。构建纯 CPU 版本并使用 `--no-gpu`: ``` git clone https://github.com/alphafox02/iridium-sniffer.git cd iridium-sniffer sudo apt install build-essential cmake libfftw3-dev libsoapysdr-dev mkdir build && cd build cmake .. -DUSE_OPENCL=OFF make -j$(nproc) ``` **FFTW wisdom(对 ARM 很重要):** FFTW 在创建计划时使用 `FFTW_MEASURE` 对 FFT 算法进行基准测试。在 x86 上,这非常快且不易察觉。在 ARM 上,每个计划可能会阻塞 30-60 秒以上,导致在构建计划时样本排队,使得实时捕获期间的 `q_max` 攀升。 预先生成 wisdom 文件可以避免这种情况。iridium-sniffer 在启动时会自动从 `~/.iridium-sniffer-fftw-wisdom` 加载 wisdom,并在关闭时保存更新后的 wisdom。在第一次成功运行(或下面的命令)之后,随后的启动将是立即的。 所需的 wisdom 条目取决于采样率。突发检测的 FFT 大小会有所不同,而下变频 FFT 始终相同(用于 CFO 估计的 cof4096,用于相关的 cof2048/cob2048): | 采样率 | 突发 FFT | Wisdom 命令 | |-------------|-----------|----------------| | 2-2.4 MHz (RTL-SDR) | 2048 | `fftwf-wisdom -v -o ~/.iridium-sniffer-fftw-wisdom cof2048 cof4096 cob2048` | | 6 MHz (Airspy Mini) | 8192 | `fftwf-wisdom -v -o ~/.iridium-sniffer-fftw-wisdom cof8192 cof4096 cof2048 cob2048` | | 10 MHz (默认) | 8192 | `fftwf-wisdom -v -o ~/.iridium-sniffer-fftw-wisdom cof8192 cof4096 cof2048 cob2048` | | 12 MHz (扩展) | 16384 | `fftwf-wisdom -v -o ~/.iridium-sniffer-fftw-wisdom cof16384 cof4096 cof2048 cob2048` | 命名约定:`cof` = 复数前向,`cob` = 复数后向,后跟 FFT 大小。如果在同一系统上运行多个采样率,请在一条命令中包含所有突发 FFT 大小(例如 `cof2048 cof8192 cof4096 cob2048`)。在新系统上,`fftwf-wisdom` 出现的“system-wisdom import failed”警告是正常的,可以忽略。 GNU Radio 会自动管理 FFTW wisdom(在 `~/.gr_fftw_wisdom` 中),这就是 gr-iridium 用户从未遇到此问题的原因。由于 iridium-sniffer 替代了对 GNU Radio 的依赖,因此它直接处理 wisdom。 ### 构建变体 ``` # OpenCL GPU(可用时默认启用) cmake .. -DUSE_OPENCL=ON # Vulkan GPU cmake .. -DUSE_VULKAN=ON -DUSE_OPENCL=OFF # 仅 CPU cmake .. -DUSE_OPENCL=OFF # 带 AddressSanitizer 的 Debug 构建 cmake .. -DCMAKE_BUILD_TYPE=Debug ``` ## 快速开始 ``` # 列出可用的 SDR 设备 ./iridium-sniffer --list # 实时捕获(使用 -i 指定您的 SDR) ./iridium-sniffer -i soapy-0 # RTL-SDR, Airspy, etc. ./iridium-sniffer -i hackrf-SERIAL # HackRF ./iridium-sniffer -i usrp-PRODUCT-SERIAL # USRP # 带网页地图的实时捕获(打开 http://localhost:8888) ./iridium-sniffer -i soapy-0 --web # 处理 IQ 录制文件(不需要 -i) ./iridium-sniffer -f recording.cf32 # 通过管道传递给 iridium-toolkit ./iridium-sniffer -i soapy-0 | python3 iridium-toolkit/iridium-parser.py # ZMQ 多消费者输出(多个 iridium-toolkit 订阅者) ./iridium-sniffer -i soapy-0 --zmq # 内置 ACARS/SBD 解码(无需 Python) ./iridium-sniffer -i soapy-0 --acars # ACARS JSON 输出至 stdout(兼容 dumpvdl2/dumphfdl 格式) ./iridium-sniffer -i soapy-0 --acars-json --station=MYSTATION # 直接馈送至 airframes.io(基于 TCP 的 iridium-toolkit JSON 格式) ./iridium-sniffer -i soapy-0 --feed --station=MYSTATION # 通过 UDP 馈送至 acarshub(iridium-toolkit JSON 格式) ./iridium-sniffer -i soapy-0 --feed=udp://127.0.0.1:5558 --station=MYSTATION # 同时馈送至 acarshub 和 airframes.io ./iridium-sniffer -i soapy-0 --feed=udp://127.0.0.1:5558 --feed --station=MYSTATION # 通过 UDP 流式传输 JSON(dumpvdl2 格式,用于未来的聚合器支持) ./iridium-sniffer -i soapy-0 --acars-udp=192.168.1.100:5555 --station=MYSTATION # 通过 iridium-toolkit 直接恢复 ACARS/SBD(绕过 iridium-parser.py) ./iridium-sniffer -i soapy-0 --parsed | python3 iridium-toolkit/reassembler.py -m acars # 通过多普勒频移估算接收器位置(带网页地图) ./iridium-sniffer -i soapy-0 --position # 带高程辅助的定位(海拔 100 米) ./iridium-sniffer -i soapy-0 --position=100 # 将 IDA 帧发送至 Wireshark ./iridium-sniffer -i soapy-0 --gsmtap ``` ## 性能 在 60 秒的 IQ 录制(cf32,10 MHz,1622 MHz 中心频率,USRP B210)上与 gr-iridium 进行了测试: **默认阈值 (16 dB) -- 最大帧恢复率:** | 指标 | iridium-sniffer | gr-iridium | |--------|-----------------|------------| | 检测到的突发数 | 5468 | ~3666 | | 解调的 RAW 帧 | 3701 | 2713 | | Ok 率 | 68% | 74% | | IDA 帧 (内部 `--parsed`) | 743 | -- | | IDA 帧 (外部 iridium-parser.py) | 373 | 690 | 默认的 16 dB 阈值比 gr-iridium 检测到更多的突发,包括噪声基底处的较弱信号。许多边缘突发解调失败,降低了 ok 百分比——但绝对帧数高出 36%(3701 对比 2713)。这是最大数据恢复率的推荐设置。 **匹配阈值 (18 dB) -- 公平比较:** | 指标 | iridium-sniffer | gr-iridium | |--------|-----------------|------------| | 检测到的突发数 | 3668 | ~3666 | | 解调的 RAW 帧 | 2737 | 2713 | | Ok 率 | 75% | 74% | | IDA 帧 (内部 `--parsed`) | 605 | -- | | IDA 帧 (外部 iridium-parser.py) | 361 | 690 | 在 18 dB(gr-iridium 的默认值)下,突发检测计数几乎相同。ok 率现在与 gr-iridium 匹配,为 75% 对比 74%。外部解析器 IDA 的差距(361 对比 690)反映了 gr-iridium 基于 GNU Radio 的解调器产生更干净的比特——更多的帧通过标准 BCH 纠错幸存下来。如果 ok 率百分比比总帧数更重要,请使用 `--threshold=18`。 **关于实时 ok% 率的说明:** 在实时 SDR 捕获中,您可能会看到 iridium-sniffer 的 ok\_avg 为 35-50%,而 gr-iridium 指南中显示为 70-80%。这是预料之中的,不是问题。iridium-sniffer 使用较低的默认检测阈值(16 dB 对比 gr-iridium 的 18 dB),这会捕获噪声基底处的更多弱突发。这些边缘检测降低了 ok 百分比,但增加了成功解码的帧总数。ok% 统计数据衡量的是检测到的突发成功解码的比例——而不是您实际恢复了多少帧。重要的是每秒解码的帧数,尽管 ok% 数字较低,iridium-sniffer 通常比 gr-iridium 恢复更多可用数据。 **处理速度(60秒 cf32 文件,i7-11800H):** | 配置 | 实际运行时间 | CPU 时间 | 实时倍率 | |---------------|-----------|----------|-----------------| | AVX2 + GPU | 15.1s | 23.6s | 4.0x | | 仅 AVX2 | 12.0s | 21.5s | 5.0x | | 仅 SSE4.2 | - | - | ~3.5x 估计值 | | Scalar + GPU | 16.1s | 42.6s | 3.7x | | 仅 Scalar (基准线) | 13.0s | 40.6s | 4.6x | 提供三个 SIMD 层级:AVX2+FMA (256-bit)、SSE4.2 (128-bit) 和标量。启动时通过 CPUID 自动选择适当的层级。使用 `--simd=MODE` 强制指定路径 (auto/avx2/sse42/scalar) 以进行测试或调试。AVX2 相比标量减少了约 1.9 倍的 CPU 时间;SSE4.2 提供了约 1.5 倍的提升,这有助于在没有 AVX2 的 CPU(例如 Intel Celeron J4105)上运行。GPU 加速对于这种大小的文件会增加启动开销,但对于较长的录制和连续的实时捕获则变得有益。 所有 SIMD 配置都会产生相同的解调输出(帧数、比特内容)。由于突发检测 FFT 中的浮点舍入,GPU 与 CPU 可能会有几帧的差异。 IDA 解码器使用 BCH(31,20) t=2 硬判决纠错,这与 iridium-toolkit 的 `bch_repair()` 相同。标准 BCH 每个最多可纠正 2 个比特错误的 31 位块。通过 `--chase=N` (N=1..7) 提供了一个实验性的 Chase 软判决扩展,它利用解调器提供的每比特幅度分数,尝试恢复**仅限于 IDA 帧**中具有 2 个以上错误的块(IRA/IBC 的 Chase 完全被禁用)。Chase 恢复默认情况下是关闭的。 ## 内置网络地图 (测试版) `--web` 标志启动一个嵌入式 HTTP 服务器,该服务器实时解码 IRA(振铃警报)和 IBC(广播)帧,并将其显示在地图上。这提供了与 [Iridium Live](https://github.com/microp11/iridium-live) 类似的功能,且无需任何外部依赖。 **注意:** 网络地图功能目前处于测试阶段。位置绘制和卫星跟踪功能可用,但仍在验证中。 ``` # 默认端口 8888 ./iridium-sniffer -i soapy-0 --web # 自定义端口 ./iridium-sniffer -i soapy-0 --web=9090 ``` 然后在浏览器中打开 `http://localhost:8888`。 地图显示: - **波束覆盖区** -- 来自 IRA 帧的地面级 Iridium 波束中心,按卫星着色。 - **MT 位置** -- 从寻呼消息中提取的移动终端(手持设备/IoT 设备)位置。 - **飞机位置** -- 基于 ACARS 消息的粗略位置估计(见下文)。 - **寻呼事件** -- 检测到用户寻呼的波束位置。 - **接收机位置** -- 通过多普勒求解器估计的位置(当激活 `--position` 时)。 - **活动卫星计数** 和状态栏中的帧总数。 - **自动居中** 于第一个接收到的位置,然后自由平移/缩放。 所有图层均可通过图层控制面板切换。 数据通过 Server-Sent Events 每秒更新一次。该地图使用带有从 CDN 加载的 OpenStreetMap 切片的 Leaflet.js。无需单独安装或提供任何文件。 ### 飞机位置图层 当同时使用 `--web` 和 `--acars` 时,解码后的 ACARS 消息会与最近的 IRA 地面波束位置相关联,以估计发送飞机的位置: ``` ./iridium-sniffer -i soapy-0 --web --acars ``` 每架飞机(通过尾号识别)在其最新的波束中心定位处都有一个彩色圆点,以及一条连接连续定位点的虚线轨迹。点击标记可显示注册号、航班号(如果消息中存在)、承载消息的卫星/波束以及最后一条解码消息的时间。 **准确性说明:** 位置精度大约为 150-200 公里——即 Iridium 波束覆盖区的半径。这足以识别飞机正在跨越哪个区域或海洋,但不足以进行精确跟踪。轨迹线连接的是波束中心位置,当连续消息通过不同的卫星到达时,可能会显示跳跃。 **API 接口:** | 端点 | 描述 | |----------|-------------| | `GET /` | HTML 地图页面 | | `GET /api/events` | SSE 流(1 Hz 的 JSON 更新)| | `GET /api/state` | 当前状态的 JSON 快照 | 网络地图与正常的 RAW 输出同时运行。添加 `--web` 不会改变标准输出上的内容,因此您可以同时通过管道传输给 iridium-toolkit: ``` ./iridium-sniffer -i soapy-0 --web | python3 iridium-toolkit/iridium-parser.py ``` ## 多普勒定位(实验性) `--position` 标志允许通过多普勒频移测量对接收机进行地理定位。当 Iridium LEO 卫星以约 7.5 km/s 的速度经过头顶时,每个解码突发的频率偏移都编码了卫星与接收机的几何关系。通过收集来自多次卫星经过的测量数据,迭代的加权最小二乘求解器将估计接收机的纬度和经度——无需 GPS。 ``` # 基本定位(意味着启用 --web 以显示地图) ./iridium-sniffer -i soapy-0 --position # 带高程辅助以提高精度(海拔高度,单位为米) ./iridium-sniffer -i soapy-0 --position=100 ``` 求解器每 10 秒运行一次,在尝试求解之前,至少需要来自 2 颗以上卫星的 5 次测量。位置估计会显示在 stderr 上,并作为网络地图上的一个绿色标记。在开阔天空和高度辅助下,预计在 5-10 分钟内收敛。随着卫星通过次数的增加,准确性会提高——求解器使用运动验证的空间聚类来拒绝损坏的 IRA 位置,并使用异常值拒绝(3-sigma)来过滤不良测量。 高度辅助将海拔限制为已知值,并显著提高了水平精度。没有它,垂直分量将很难仅通过多普勒测量来确定。 基于:Z. Tan 等人的 "New Method for Positioning Using IRIDIUM Satellite Signals of Opportunity," IEEE Access, vol. 7, 2019。 ## GSMTAP 输出(Wireshark 集成) `--gsmtap` 标志启用原生的 IDA (Iridium Data Access) 帧解码,并通过 UDP 将解码后的 LAPDm 帧发送到 Wireshark。这取代了用于协议分析的 `iridium-parser.py -m gsmtap` Python 管道。 ``` # 启动 Wireshark 监听 GSMTAP wireshark -k -i lo -f "udp port 4729" # 在另一个终端中,启用 GSMTAP 运行 ./iridium-sniffer -i soapy-0 --gsmtap # 自定义目标主机和端口 ./iridium-sniffer -i soapy-0 --gsmtap=192.168.1.100:4729 # 结合网页地图 ./iridium-sniffer -i soapy-0 --web --gsmtap ``` Wireshark 将数据包解码为 GSM/LAPDm 信令。通常看到的消息包括: - **Immediate Assignment / Reject** -- 信道管理(最常见) - **Paging Request** -- 卫星正在寻找手持设备(包含 TMSI) - **Location UpdateReject** -- 卫星拒绝注册尝试 - **System Information** -- 广播参数 - **SBD (Short Burst Data)** 载荷 IDA 解码器实现: - 通过 46 位置换表和 3 个 BCH 分量提取 LCW (Link Control Word) - 载荷解扰:124 位块解交织,使用 poly=3545 的 BCH(31,20) - CRC-CCITT 验证 - 多突发重组(16 个并发时隙,频率/时间/序列匹配) GSMTAP 与正常的 RAW 输出和网络地图同时运行。添加 `--gsmtap` 不会改变标准输出。 ## 内置 ACARS / SBD 解码 这些标志控制 ACARS/SBD 输出,并且可以组合使用: | 标志 | 输出 | |------|--------| | `--acars` | 人类可读的文本输出到 stdout | | `--acars-json` | JSON 输出到 stdout (dumpvdl2/dumphfdl 格式) | | `--acars-udp=HOST:PORT` | 通过 UDP 发送 JSON (dumpvdl2/dumphfdl 格式,可重复,最多 4 个) | | `--feed[=PROTO://HOST:PORT]` | Feed 聚合器 (iridium-toolkit JSON 格式,可重复,最多 4 个) | 这完全取代了 `reassembler.py -m acars` 管道——不需要 Python。安装 [libacars-2](https://github.com/szpajder/libacars) 后,ARINC-622 应用层载荷 (ADS-C、CPDLC、OHMA、MIAM) 将被完全解码。如果没有 libacars,基本的 ACARS 字段提取仍然有效。 ``` # 人类可读的文本输出 ./iridium-sniffer -i usrp-B210-SERIAL --acars # JSON 输出至 stdout ./iridium-sniffer -i usrp-B210-SERIAL --acars-json --station=MYSTATION # 通过 UDP 将 JSON 流式传输至远程聚合器 ./iridium-sniffer -i usrp-B210-SERIAL --acars-udp=192.168.1.100:5555 --station=MYSTATION # 通过 UDP 馈送至 acarshub(iridium-toolkit JSON 格式) ./iridium-sniffer -i usrp-B210-SERIAL --feed=udp://127.0.0.1:5558 --station=MYSTATION # 通过 TCP 直接馈送至 airframes.io(iridium-toolkit JSON 格式) ./iridium-sniffer -i usrp-B210-SERIAL --feed --station=MYSTATION # 同时馈送至 acarshub(UDP)和 airframes.io(TCP) ./iridium-sniffer -i usrp-B210-SERIAL --feed=udp://127.0.0.1:5558 --feed --station=MYSTATION # stdout 上的文本 + UDP JSON 流同时输出 ./iridium-sniffer -i usrp-B210-SERIAL --acars --acars-udp=192.168.1.100:5555 --station=MYSTATION ``` ### 文本输出 **示例(带 libacars):** ``` ACARS: 2026-02-24T13:06:52Z DL [hdr:iridium] ACARS: Reassembly: skipped Reg: .N-XXXXX Mode: 2 Label: H1 Blk id: F More: 0 Ack: ! Sublabel: MD Message: MSG/RX24-FEB-26 1306Z /RXFLIGHT PLANS PXXXX AND PXXXX ARE AVAILABLE FOR UPLINK ``` 心跳 ping(Label `_d`)是 Iridium 上最常见的 ACARS 消息类型。标记为 H1 的消息承载 ARINC-622 应用数据——航空运营控制 (AOC) 消息、飞行计划上行链路、ADS-C 位置报告和 CPDLC 许可。当存在 libacars 时,这些载荷被解码为结构化字段,而不是作为不透明的二进制数据出现。 非 ACARS 的 SBD 流量(IoT 遥测、海事跟踪等)也会显示: ``` SBD: 2026-02-24T12:56:07Z DL 6841542344504f4c4c203635313530 | hAT#DPOLL 65150 ``` ### JSON 格式 JSON 模式(`--acars-json` 或 `--acars-udp`)每行生成一个 JSON 对象。信封格式与 [dumpvdl2](https://github.com/szpajder/dumpvdl2) 和 [dumphfdl](https://github.com/szpajder/dumphfdl) 匹配,使用 `"iridium"` 作为顶级协议键(类似于 `"vdl2"` 和 `"hfdl"`)。`"acars"` 对象内的 ACARS 字段名称与 libacars 生成的完全一致,因此聚合站点可以使用一个解析器接收这三种工具的数据。 **带 libacars**(解码 ARINC-622/ADS-C/CPDLC): ``` { "iridium": { "app": { "name": "iridium-sniffer", "ver": "1.0" }, "station": "MYSTATION", "t": { "sec": 1740412012, "usec": 555856 }, "freq": 1623126868, "sig_level": 29.02, "acars": { "err": false, "crc_ok": true, "more": false, "reg": ".N12345", "mode": "2", "label": "H1", "blk_id": "F", "ack": "!", "sublabel": "DF", "mfi": "01", "msg_text": "...", "arinc622": { "...decoded application payload..." } } } } ``` **不带 libacars**(仅基本 ACARS 字段): ``` { "iridium": { "app": { "name": "iridium-sniffer", "ver": "1.0" }, "station": "MYSTATION", "t": { "sec": 1740412012, "usec": 555856 }, "freq": 1623126868, "sig_level": 29.02, "acars": { "err": false, "crc_ok": true, "more": false, "reg": ".N12345", "mode": "2", "label": "H1", "blk_id": "F", "ack": "!", "msg_text": "..." } } } ``` 无论是否带有 libacars,信封(`app`、`station`、`t`、`freq`、`sig_level`)和 ACARS 字段名(`err`、`crc_ok`、`more`、`reg`、`mode`、`label`、`blk_id`、`ack`、`flight`、`msg_num`、`msg_num_seq`、`msg_text`)都是相同的。区别在于 libacars 添加了解码后的 ARINC-622 应用层对象(`arinc622`、`adsc`、`cpdlc` 等),嵌套在基础 ACARS 字段之后。已经接收 dumpvdl2 或 dumphfdl JSON 的站点可以使用相同的解析器——只需检查 `"iridium"` 键而不是 `"vdl2"` 或 `"hfdl"`。 ### UDP 流传输 `--acars-udp=HOST:PORT` 将每个 ACARS JSON 对象作为 UDP 数据报发送到远程主机。可以多次指定此标志(最多 4 次)以同时向多个聚合器馈送数据。将 `--acars`(在 stdout 上输出文本)与 `--acars-udp` 结合使用,可以在向远程站点馈送数据的同时获得人类可读的本地输出。无论使用何种输出方法,JSON 格式都是相同的。 **关闭统计信息** 打印到 stderr: ``` SBD: 339 packets from 15964 IDA messages (75 short, 260 single, 1 multi-pkt) ACARS: 80 messages decoded (1 with errors) ``` ### 安装 libacars(可选,但推荐) libacars-2 是可选的。没有它,ACARS 消息仍会被解码,但 ARINC-622 应用层载荷将保持为原始文本。有了它,ADS-C、CPDLC 和其他嵌入式协议将被完全解码。 ``` # Ubuntu / Debian / DragonOS sudo apt install libacars-dev # 或从源码构建 git clone https://github.com/szpajder/libacars.git cd libacars && mkdir build && cd build cmake .. && make -j$(nproc) && sudo make install sudo ldconfig ``` CMake 在构建时会报告检测状态: ``` -- libacars: enabled (ARINC-622/ADS-C/CPDLC decoding) ``` 或者: ``` -- libacars: not found (basic ACARS only) ``` ### 馈送 acarshub 和 airframes.io 将 Iridium ACARS 导入聚合器的传统 Python 管道需要将四个进程链接在一起: ``` # 传统管道(gr-iridium + iridium-toolkit + acars.py) iridium-extractor -D 4 rtl-sdr | iridium-parser.py | reassembler.py -m acars -a json | acars.py -s MYSTATION ``` iridium-sniffer 用单个 `--feed` 标志取代了整个链条。馈送输出使用 iridium-toolkit JSON 格式(与 iridium-toolkit 的 `reassembler.py -m acars -a json` 生成的格式相同),因此现有聚合器可以不加修改地接收它。 **直接馈送 airframes.io**(TCP,端口 5590): ``` # 裸 --feed 默认为 tcp://feed.airframes.io:5590 ./iridium-sniffer -i soapy-0 --feed --station=MYSTATION ``` **馈送本地 acarshub 实例**(UDP,端口 5558): ``` ./iridium-sniffer -i soapy-0 --feed=udp://127.0.0.1:5558 --station=MYSTATION ``` **通过 TCP 馈送 acarshub**(也受支持): ``` ./iridium-sniffer -i soapy-0 --feed=tcp://127.0.0.1:15590 --station=MYSTATION ``` **同时馈送 acarshub 和 airframes.io**(`--feed` 可重复,最多 4 个): ``` ./iridium-sniffer -i soapy-0 --feed=udp://127.0.0.1:5558 --feed --station=MYSTATION ``` 在馈送数据时,添加 `--acars` 以在本地获取人类可读的文本输出: ``` ./iridium-sniffer -i soapy-0 --acars --feed --station=MYSTATION ``` **Docker Compose (acarshub):** 设置 `ENABLE_IRDM=true` 并配置传输方式。对于 UDP:`IRDM_CONNECTIONS=udp`(默认端口 5558)。对于 TCP:`IRDM_CONNECTIONS=tcp://HOST:PORT`。有关详细信息,请参阅 [docker-acarshub](https://github.com/sdr-enthusiasts/docker-acarshub) 文档。 **两种 JSON 格式:** iridium-sniffer 针对不同目的生成两种不同的 ACARS JSON 格式: - `--feed` 当前输出 **iridium-toolkit 格式**(顶层的 `"app": {"name": "iridium-toolkit"}`)。这是 acarshub 和 airframes.io 已经接受的成熟格式。请将其用于当前向聚合器馈送数据。 - `--acars-json` / `--acars-udp` 输出 **dumpvdl2/dumphfdl 信封格式**(以 `"iridium"` 作为顶级键,匹配 dumpvdl2 的 `"vdl2"` 和 dumphfdl 的 `"hfdl"` 结构)。这是一种更丰富、结构更严谨的格式,带有完整的 libacars ARINC-622 解码。一旦聚合站点接受了 dumpvdl2 信封,`--feed` 将采用它,并且 `--acars-udp` 可以退役——`--feed` 仍将是用于向聚合器馈送数据的单一标志,无论它承载的是哪种线路格式。 ## 解析后的 IDA 输出 `--parsed` 标志启用内部 IDA 帧解码,并将解析后的 IDA 行直接输出到标准输出。添加此功能主要是为了恢复 ACARS、SBD 和其他基于 IDA 的消息内容,而无需外部 Python `iridium-parser.py` 管道。 ``` # 直接输出至 reassembler(IDA/ACARS/SBD 不需要 iridium-parser.py) ./iridium-sniffer -i soapy-0 --parsed | python3 iridium-toolkit/reassembler.py -m acars # 传统管道(仍然有效,可解码所有帧类型) ./iridium-sniffer -i soapy-0 | python3 iridium-toolkit/iridium-parser.py | python3 iridium-toolkit/reassembler.py -m acars ``` **当前功能和限制:** `--parsed` 目前**仅解码 IDA 帧**。这些是用于承载 ACARS、SBD 消息传递、语音呼叫建立和其他载荷流量的数据帧。IDA 是重组器重建消息所需要的。 `--parsed` **尚未解码**的帧类型(这些作为 `RAW:` 行通过): - IRA(振铃警报)-- 卫星位置和寻呼事件 - IBC(广播信道)-- 卫星 ID、波束、Iridium 时间 - VOC/VOZ (语音) -- 语音编解码器帧 - ISY、ITL、IIU、IMS 和其他信令类型 对于 IRA 和 IBC,`--web` 地图功能已经使用单独的解码器独立解码了这些帧类型。`--parsed` 的限制仅影响标准输出的文本输出。 如果在标准输出上需要所有帧类型(而不仅仅是 IDA),请使用传统管道:`iridium-sniffer | iridium-parser.py`。外部解析器处理所有帧类型;`--parsed` 仅处理 IDA。 在解析模式下,解码的 IDA 帧显示为 `IDA:` 行,其字段与 `iridium-parser.py` 的输出格式匹配。非 IDA 帧继续显示为 `RAW:` 行。`--parsed` 标志不会增加任何可测量的开销。 ## 突发 IQ 捕获 `--save-bursts` 选项将成功解码的突发的 IQ 样本保存到一个目录中,以便进行离线分析、算法开发或研究。 ``` # 保存所有已解码的突发 ./iridium-sniffer -i soapy-0 --save-bursts bursts/ # 处理文件并保存突发 ./iridium-sniffer -f recording.cf32 --format=cf32 --save-bursts bursts/ ``` **每个突发的输出文件:** - `___.cf32` - 复数 float32 IQ 样本(经过 RRC 滤波,对齐至唯一字) - `___.meta` - 元数据(突发 ID、频率、SNR、采样率等) **用例:** - 射频指纹识别和卫星认证研究 - 在没有实时卫星经过的情况下进行算法开发和测试 - 为信号处理研究构建数据集 - 试特定突发上的解调问题 - 使用真实卫星数据进行回归测试 捕获的 IQ 采样率为 250 kHz,每个符号 10 个样本,经过 RRC 匹配滤波。每个文件包含一个完整的突发,可直接进行解调。 ## 用法 ### 文件输入 IQ 格式通过文件扩展名自动检测(`.cf32`/`.fc32`/`.cfile` 对应 cf32,`.ci16`/`.cs16`/`.sc16` 对应 ci16)。具有无法识别的扩展名的文件默认为 ci8。使用 `--format` 进行覆盖。 ``` # 根据扩展名自动检测为 cf32 ./iridium-sniffer -f recording.cf32 # 自动检测为 ci16 ./iridium-sniffer -f recording.cs16 # 显式格式覆盖(例如,实际上是 cf32 的 .raw 文件) ./iridium-sniffer -f recording.raw --format cf32 # 自定义采样率和中心频率 ./iridium-sniffer -f recording.cf32 -r 10000000 -c 1622000000 ``` **SigMF 支持:** 当输入文件的扩展名为 `.sigmf-data` 或 `.sigmf-meta` 时,iridium-sniffer 将读取附带的 `.sigmf-meta` JSON 文件,并自动应用采样率、中心频率和数据格式。这允许对 SigMF 录制进行零配置回放: ``` # 所有参数均从 .sigmf-meta 自动检测 ./iridium-sniffer -f recording.sigmf-data # 直接传递 .sigmf-meta 也有效(自动打开 .sigmf-data) ./iridium-sniffer -f recording.sigmf-meta # 显式标志会覆盖 SigMF 元数据 ./iridium-sniffer -f recording.sigmf-data -r 5000000 ``` 支持的 SigMF 数据类型:`cf32_le`、`ci16_le`、`ci8`、`cu8`。命令行标志(`-r`、`-c`、`--format`)始终优先于 SigMF 元数据。 ### 实时捕获 指定 `-i` 会选择一个 SDR 接口,并暗示实时捕获(不需要 `-l`)。使用 `--list` 查看可用设备: ``` ./iridium-sniffer --list ``` 然后使用 `-i` 指定接口。SoapySDR 设备可以通过索引 (`soapy-N`) 或通过设备参数 (`soapy:driver=X,serial=Y`) 进行选择,以便在连接多个设备时进行确定性选择: ``` # RTL-SDR / Airspy / 其他 SoapySDR 设备(按索引) ./iridium-sniffer -i soapy-0 # 按序列号或驱动参数指定的 SoapySDR 设备 ./iridium-sniffer -i soapy:driver=airspy,serial=ABC123 ./iridium-sniffer -i soapy:driver=rtlsdr,serial=00000001 # HackRF(使用来自 --list 的序列号) ./iridium-sniffer -i hackrf-SERIAL # USRP(使用来自 --list 的序列号) ./iridium-sniffer -i usrp-PRODUCT-SERIAL # SDRplay(原生 API,使用来自 --list 的序列号) ./iridium-sniffer -i sdrplay-SERIAL # BladeRF ./iridium-sniffer -i bladerf1 # 带增益和 bias tee ./iridium-sniffer -i soapy-0 -B --soapy-gain=40 ./iridium-sniffer -i hackrf-SERIAL --hackrf-lna=40 --hackrf-vga=20 ./iridium-sniffer -i usrp-PRODUCT-SERIAL --usrp-gain=50 ./iridium-sniffer -i sdrplay-SERIAL --sdrplay-gain=50 -B # 按元件控制增益(Airspy R2:LNA 0-15,MIX 0-15,VGA 0-15) ./iridium-sniffer -i soapy-0 --soapy-gain-element=LNA:10 --soapy-gain-element=MIX:9 --soapy-gain-element=VGA:10 # 发现您设备可用的增益元件 ./iridium-sniffer -i soapy-0 -v --diagnostic 2>&1 | grep "gain elements" # SoapySDR 设备特定设置 ./iridium-sniffer -i soapy:driver=airspy,serial=ABC --soapy-setting=bitpack:true ./iridium-sniffer -i soapy:driver=bladerf --soapy-setting=biastee_rx:true ``` ### 通过管道传输给 iridium-toolkit ``` # 实时解码 ./iridium-sniffer -i soapy-0 | python3 iridium-toolkit/iridium-parser.py # 直接输出至 reassembler(已解析模式,绕过 iridium-parser.py) ./iridium-sniffer -i soapy-0 --parsed | python3 iridium-toolkit/reassembler.py -m acars # 带完整重组的文件处理(传统管道) ./iridium-sniffer -f recording.cf32 --format cf32 | \ python3 iridium-toolkit/iridium-parser.py | \ python3 iridium-toolkit/reassembler.py ``` ### ZMQ 多消费者输出 `--zmq` 标志通过 ZMQ PUB 套接字发布输出行,使多个独立的 iridium-toolkit 消费者能够同时订阅。这用扇出架构取代了标准输出管道(仅支持单个消费者),与 gr-iridium 的 ZMQ 输出工作方式相匹配。 ``` # 在默认端点(tcp://*:7006)上发布 RAW 输出 ./iridium-sniffer -i soapy-0 --zmq # 自定义端点 ./iridium-sniffer -i soapy-0 --zmq=tcp://*:9999 # ZMQ + ACARS:RAW 行发送至 ZMQ,ACARS 文本发送至 stdout ./iridium-sniffer -i soapy-0 --zmq --acars --station=MYSTATION # ZMQ + 网页地图 ./iridium-sniffer -i soapy-0 --zmq --web ``` 订阅者使用任何 ZMQ SUB 客户端连接。使用 iridium-toolkit: ``` # 终端 1:iridium-parser.py python3 -c " import zmq, sys ctx = zmq.Context() sub = ctx.socket(zmq.SUB) sub.connect('tcp://127.0.0.1:7006') sub.subscribe(b'') while True: print(sub.recv_string()) sys.stdout.flush() " | python3 iridium-toolkit/iridium-parser.py # 终端 2:用于 ACARS 的 reassembler(订阅至相同的 ZMQ) python3 -c " import zmq, sys ctx = zmq.Context() sub = ctx.socket(zmq.SUB) sub.connect('tcp://127.0.0.1:7006') sub.subscribe(b'') while True: print(sub.recv_string()) sys.stdout.flush() " | python3 iridium-toolkit/iridium-parser.py | python3 iridium-toolkit/reassembler.py -m acars ``` 当 `--zmq` 与 `--acars` 结合使用时,RAW 行仍将发布到 ZMQ(因此 iridium-toolkit 消费者可获得完整数据),而 ACARS 文本输出将发送到标准输出。如果不使用 `--acars`,RAW 行将同时发送到标准输出和 ZMQ。 ZMQ PUB 套接字是非阻塞的:如果没有连接订阅者,消息将被静默丢弃,不会影响性能。订阅者可以随时连接和断开。 需要 libzmq(`sudo apt install libzmq3-dev`)。此功能仅在构建时检测到 libzmq 的情况下才会被编译进去。 ### ZMQ SUB 输入 通过 ZMQ PUB 套接字从远程 SDR 接收 IQ 样本。这允许在一台机器上运行 SDR,而在另一台机器上运行 iridium-sniffer,或者跨多个解码器共享单个 SDR 流。 ``` # 从 GNU Radio ZMQ PUB 接收端接收 cf32 IQ 样本 ./iridium-sniffer --zmq-sub=tcp://192.168.1.10:5555 --format=cf32 -r 10000000 # 默认端点(localhost:5555) ./iridium-sniffer --zmq-sub --format=cf32 -r 10000000 # 带网页地图和自定义中心频率 ./iridium-sniffer --zmq-sub=tcp://remote-sdr:5555 --format=cf32 -r 10000000 -c 1622000000 --web ``` 样本格式(`--format`)和采样率(`-r`)必须与发布者发送的内容相匹配。GNU Radio 的 `zeromq.pub_sink` 通常输出 cf32 (复数 float32)。 ### VITA 49 (VRT) 输入 通过 UDP 接收 VITA 49 / VRT 信号数据包形式的 IQ 样本。这允许从输出 VITA 49 的 SDR 平台接收数据,例如 FlexRadio、REDHAWK SCA、Sceptre 或自定义的 VRT 源。 ``` # 从 VRT 上下文包自动配置(采样率,频率,格式) ./iridium-sniffer --vita49 # 指定绑定地址和端口 ./iridium-sniffer --vita49=192.168.1.100:5000 # 覆盖特定值(上下文自动填充其余部分) ./iridium-sniffer --vita49 -c 1626270833 # 带网页地图 ./iridium-sniffer --vita49 --web ``` **从上下文数据包自动配置:** 当 VRT 源发送 IF 上下文数据包(类型 0x4)时,iridium-sniffer 会自动从上下文字段中提取采样率、RF 中心频率和样本格式 (ci8/ci16/cf32)。在启动时,工具最多等待 5 秒钟以获取上下文数据包,然后再回退到命令行值或默认值。 命令行标志(`-r`、`-c`、`--format`)会覆盖自动检测到的值。如果指定了 `--format` 但上下文报告的格式不同,iridium-sniffer 将会退出并报错,因为不匹配的样本格式会产生无用的输出。采样率和中心频率不匹配会产生警告,但会继续运行。 解析器接受带有可选 VRL 帧的 VRT 信号数据包(类型 0x0 和 0x1)。内置了序列间隙检测,并在关闭时记录。不需要外部库——VITA 49 解析仅使用 POSIX 套接字。 ## 命令参考 ``` Usage: iridium-sniffer <-f FILE | -i IFACE> [options] Input (one required): -f, --file=FILE read IQ samples from file -l, --live capture live from SDR (implied by -i) --format=FMT IQ file format: ci8 (default), ci16, cf32 Auto-detected from file extension when not specified SDR options: -i, --interface=IFACE SDR to use (see --list for available devices): soapy-N (by index) or soapy:key=val,... (by args) hackrf-SERIAL, bladerfN, usrp-PRODUCT-SERIAL sdrplay-SERIAL (native SDRplay API) -c, --center-freq=HZ center frequency in Hz (default: 1622000000) -r, --sample-rate=HZ sample rate in Hz (default: 10000000) -B, --bias-tee enable bias tee power --clock-source=SRC clock reference: internal (default), external, gpsdo --time-source=SRC time/PPS reference: internal (default), external, gpsdo Gain options: --hackrf-lna=GAIN HackRF LNA gain in dB (default: 40) --hackrf-vga=GAIN HackRF VGA gain in dB (default: 20) --hackrf-amp enable HackRF RF amplifier --bladerf-gain=GAIN BladeRF gain in dB (default: 40) --usrp-gain=GAIN USRP gain in dB (default: 40) --soapy-gain=GAIN SoapySDR aggregate gain in dB (default: 30) --soapy-gain-element=NAME:VAL set SoapySDR per-element gain (repeatable) e.g. LNA:10, MIX:9, VGA:10 (Airspy R2) skips aggregate --soapy-gain when any element is set use -v to list available gain elements for your device --soapy-setting=K:V SoapySDR device setting (repeatable) e.g. bitpack:true (Airspy), biastee_rx:true (bladeRF) --sdrplay-gain=GAIN SDRplay IF gain reduction 20-59, disables AGC (default: AGC on) Detection: -d, --threshold=DB burst detection threshold in dB (default: 16.0) --no-gpu disable GPU acceleration (use CPU FFTW) Web map: --web[=PORT] enable live web map (default port: 8888) GSMTAP: --gsmtap[=HOST:PORT] send IDA frames as GSMTAP/LAPDm via UDP (default: 127.0.0.1:4729, for Wireshark) ACARS: --acars decode and display ACARS/SBD messages from IDA --acars-json output ACARS as JSON to stdout (dumpvdl2 format) --acars-udp=HOST:PORT stream ACARS JSON via UDP (dumpvdl2 format, repeatable, max 4) --feed[=PROTO://HOST:PORT] feed aggregator (iridium-toolkit JSON format) udp://HOST:PORT for acarshub, tcp://HOST:PORT for airframes.io bare --feed defaults to tcp://feed.airframes.io:5590 repeatable (max 4, mix udp:// and tcp://) --station=ID station identifier for JSON output ZMQ: --zmq[=ENDPOINT] publish output via ZMQ PUB (default: tcp://*:7006) --zmq-sub[=ENDPOINT] receive IQ samples via ZMQ SUB (default: tcp://127.0.0.1:5555) VITA 49: --vita49[=IP:PORT] receive IQ via VITA 49 (VRT) UDP (default: 0.0.0.0:4991) auto-detects -r, -c, and format from VRT context packets Output: --file-info=STR file info string for RAW output (default: auto) --parsed output parsed IDA lines (bypass iridium-parser.py) --chase[=N] Chase soft-decision BCH decoder (experimental) N = flip-bits 0-7 (try --chase=5 for 31 combos) --save-bursts=DIR save IQ samples of decoded bursts to directory --diagnostic setup verification mode (suppresses RAW output) --no-gardner disable Gardner timing recovery (enabled by default) --simd=MODE SIMD kernel selection: auto (default), avx2, sse42, scalar --no-simd alias for --simd=scalar -v, --verbose verbose output to stderr -h, --help show this help --list list available SDR interfaces ``` ## 推荐设置 **中心频率:** 1622 MHz(默认)覆盖整个授权的 Iridium 频段。在 10 MHz 采样率下,这将捕获 1617-1627 MHz,其中包括: - Iridium 专用频段:1618.725-1626.5 MHz (7.775 MHz) - Iridium/Globalstar 共享:1617.775-1618.725 MHz (0.95 MHz) - 振铃警报/单工信道:1626.0-1626.5 MHz 1617.775 MHz 以下是 Globalstar 的专属领域。ITU 分配的频段向下延伸至 1616 MHz,但 Iridium 未被授权在那里发射信号。 **采样率:** 10 MHz(默认)覆盖整个授权的 Iridium 频段,而无需处理空白频谱。具有 12 MHz 容量的 SDR 可以使用 `-r 12000000 -c 1621000000` 以覆盖包括未授权保护频段在内的整个 ITU 分配,但这不会提供额外的 Iridium 信号。没有抽 decimation(`-D`)标志——每个检测到的突发都会自动下变频并在内部抽 decimation 到 250 kHz,而与输入采样率无关。 **窄带 SDR (RTL-SDR):** 对于 RTL-SDR 和其他限制在 2-3 MHz 带宽的 SDR,请使用 `-c 1625500000 -r 2400000` 以将中心对准振铃警报和单工信道 (1624.3-1626.7 MHz)。这会捕获网络地图所需的 IRA 帧。默认的 1622 MHz 中心针对宽带接收机进行了优化,将振铃警报信道置于窄带捕获范围之外。 **阈值:** 16 dB(默认)平衡了灵敏度和误报。较低的值(14 dB)会以更多噪声为代价捕获较弱的突发。较高的值(18-20 dB)更具选择性,但可能会遗漏边缘信号。 ## SDR 硬件 任何能调谐到 L 波段 (1616-1626.5 MHz) 且采样率在 2 MHz 或以上的 SDR 都可以使用。经过测试的硬件: | SDR | ADC | 最大速率 | 备注 | |-----|-----|----------|-------| | Ettus USRP B210 | 12-bit | 56 MHz | 最佳灵敏度,双通道 | | HackRF One | 8-bit | 20 MHz | 广泛可用,性能良好 | | BladeRF | 12-bit | 40 MHz | 良好的灵敏度 | | SDRplay RSPdx/RSP1A/RSP1B | 14-bit | 10 MHz | 原生 API,天线 B 上有偏置供电 (RSPdx/RSP2) | | RTL-SDR (通过 SoapySDR) | 8-bit | 2.4 MHz | 带宽有限,但可用 | | Airspy, LimeSDR 等 | 不定 | 不定 | 通过 SoapySDR | ## 时钟和时间源 为了提高多普勒定位的准确性,具有外部参考输入的 SDR 可以配置为使用受控时钟和/或 GPS 同步时间戳。 ``` # 带 Ettus GPSDO 模块的 USRP(驯服 10 MHz + GPS 时间) ./iridium-sniffer -i usrp-B210-SERIAL --clock-source gpsdo --time-source gpsdo --position # 带外部 GPSDO 提供 10 MHz REF IN + PPS IN 的 USRP ./iridium-sniffer -i usrp-B210-SERIAL --clock-source external --time-source external --position # 带外部 10 MHz 参考时钟的 bladeRF(驯服板载 VCTCXO) ./iridium-sniffer -i bladerf0 --clock-source external # 带 1 PPS 参考时钟的 bladeRF(GPSDO 模式) ./iridium-sniffer -i bladerf0 --clock-source gpsdo ``` | 源 | USRP | bladeRF | SoapySDR | |--------|------|---------|----------| | `internal` (默认) | 板载振荡器 | 板载 VCTCXO | 设备默认 | | `external` | 10 MHz REF IN SMA | VCTCXO tamer (10 MHz) | `setClockSource("external")` | | `gpsdo` | Ettus GPSDO 模块 | VCTCXO tamer (1 PPS) | `setClockSource("gpsdo")` | 当 `--time-source` 设置为 `external` 或 `gpsdo` 时,将使用来自 SDR 的硬件时间戳进行突发定时,而不是主机系统时钟。这消除了操作系统调度抖动和时钟漂移,为多普勒定位提供了亚微秒的突发到达时间。 当未指定时钟/时间源时,其行为与以前的版本相同——不会进行额外的 API 调用。 ## GPU 加速 GPU 加速将突发检测 FFT 卸载到 GPU 上。信号处理管道的其余部分(下变频、解调)无论在何种情况下都在 CPU 上运行。 | 平台 | 后端 | 备注 | |----------|---------|-------| | NVIDIA | OpenCL | 完整的 GPU 管道,性能最佳 | | AMD | OpenCL | ROCm 或 Mesa 驱动程序 | | Intel 集成显卡 | OpenCL | 通过 NEO 或 Beignet | | Raspberry Pi 5 | Vulkan | V3D 通过验证,但无法维持批量 FFT 吞吐量;使用 `--no-gpu` | | 无 GPU | CPU | FFTW 回退,在 x86 上能很好地处理 10 MHz;ARM 需要预先生成的 wisdom(见上文)| 在 10 MHz 的快速 x86 CPU 上,CPU FFTW 路径可以轻松应对。GPU 加速对于桌面/笔记本电脑系统上的连续实时捕获最有益。启动验证测试通过使用已知输入运行测试 FFT 来验证 GPU 的正确性。 在运行时可以使用 `--no-gpu` 禁用这两个后端。 ## 输出格式 标准输出产生 iridium-toolkit RAW 格式: ``` RAW: i-10-t1 0000442.4080 1624960925 N:10.77-71.83 I:00000003560 50% 0.11738 179 001100011011... ``` 字段为:文件信息、时间戳、频率、幅度和噪声基底、突发 ID (B)、置信度 (%)、信号级别 (L)、载荷符号计数和 解调比特。 ### 信号级别 `N:` 字段包含由符号分隔的两个值:**幅度** 和 **噪声基底**,均以 dB 为单位。 - **幅度** (`10*log10(burst_power / baseline)`) 测量突发在 FFT 中高出平均噪声基底的程度。这是一个类似于信噪比 (SNR) 的比率,而不是绝对功率电平。 - **噪声基底** 以 dBFS/Hz 为单位——即突发频率处的平均基线功率谱密度。 幅度计算等同于 gr-iridium 的方法(两者都测量相对于基线的突发功率)。然而,增益设置、采样率、FFT 大小和阈值的差异将改变检测到的突发和报告的值。如果信号级别看起来低于预期,请首先检查增益设置——`--soapy-gain-element` 或特定于设备的增益标志允许微调各个增益级。 `信号级别` 字段(例如 `0.11738`)是线性尺度的原始突发幅度,与 dB 幅度分开。 此输出直接由 [iridium-toolkit](https://github.com/muccc/iridium-toolkit) 用于高层协议解码,包括 ACARS、SBD 消息、寻呼机数据、语音和卫星遥测。 stderr 每秒显示一次状态行,其格式与 gr-iridium 相同,因此现有的监控脚本无需更改即可工作。 ## 架构 有关信号处理管道、线程模型、帧解码器内部结构和解调优化历史的设计文档,请参见 [ARCHITECTURE.md](ARCHITECTURE.md)。 ## 许可证 GNU General Public License v3.0 或更高版本。请参见 [LICENSE](LICENSE)。 ## 致谢 本项目建立在几个开源项目的工作基础之上: - 由 Sec 和 schneider42 (muccc) 开发的 [gr-iridium](https://github.com/muccc/gr-iridium) (GPL-3.0-or-later) -- 用于突发检测、下变频和 QPSK 解调的信号处理算法是 gr-iridium GNU Radio 模块的净室 C 语言移植 - 由 Mike Ryan / ICE9 Consulting LLC 开发的 [ice9-bluetooth-sniffer](https://github.com/mikeryan/ice9-bluetooth-sniffer) (GPL-2.0) -- SDR 后端抽象、构建系统和线程基础设施改编自该项目 - 由 Dmitrii Tolmachev 开发的 [VkFFT](https://github.com/DTolm/VkFFT) (MIT) -- 用于 OpenCL 和 Vulkan 突发检测的仅头文件 GPU FFT 库 - 由 Sec 和 schneider42 开发的 [iridium-toolkit](https://github.com/muccc/iridium-toolkit) (BSD-2-Clause) -- 下游帧解析器和重组器,以及 BCH 纠错和解交织算法的参考实现 - 由 Tomasz Lemiech (szpajder) 开发的 [libacars](https://github.com/szpajder/libacars) (MIT) -- 用于 ACARS 消息中 ARINC-622、ADS-C 和 CPDLC 解码的可选依赖项
标签:ACARS, ADS-C, BladeRF, CPDLC, GSMTAP, HackRF, Iridium, OpenCL, Raspberry Pi, SBD, SDR, SDRplay, SoapySDR, USRP, Veh, Web地图, Wireshark, 信号处理, 信号检测, 信号解调, 内存执行, 卫星通信, 句柄查看, 客户端加密, 嵌入式, 开源, 数据捕获, 无线窃听, 航空通信, 软件定义无线电, 铱星