城市峡谷里跑一圈,回来一看轨迹,水平误差忽大忽小,开阔路段还能压在一两米,拐进高楼夹缝就窜到十几米——这种场景做过北斗终端的人大概都不陌生。传统的做法是调环路带宽、换窄相关、上多径估计延迟锁定环,能压一部分,但压不干净,因为多径的统计特性随环境变,今天在高架下训出来的参数,明天到地下车库入口就未必好使。这几年一个明显的变化是,越来越多的人开始把卷积神经网络(CNN)往卫星导航的接收链路里塞,试图绕开"手工建模多径"这条越走越窄的路。标题写的是"综述",但真正干活的人关心的不是有多少篇论文,而是:信号到底以什么形式喂进去、标签从哪来、模型放在链路的哪一级、端到端定位精度到底涨没涨、涨了多少、代价是什么。下面这些内容,就是我按这条线梳理出来的东西,面向的是已经懂一点基带处理、想动手试的人,也尽量把基础概念讲清楚,刚入门的同学能跟得上。
1. 从城市峡谷的轨迹漂移说起:CNN为什么要进导航链路
1.1 传统基带处理究竟在哪个环节开始失效
先把失效点定准,不然模型放错位置等于白干。北斗B1I信号的测距码周期是1ms,码率2.046Mcps,接收机里最核心的动作就是把本地复现码和 incoming 信号做相关,得到一个相关峰,然后用早码、即时码、晚码三个(或者更多)抽头去算鉴相误差,驱动码环和载波环。理想情况下这个相关峰是三角形(考虑前端带宽后接近),峰顶对应真实码相位。问题出在多径上:直射信号和反射信号叠加后,相关峰不再是干净的三角形,峰会歪、会分裂、会整体偏移,早迟码鉴相器的过零点跟着偏,于是伪距就带了一个系统性偏差。
这个偏差有多大?开阔环境下C/N0通常在40到45 dB-Hz,码跟踪精度可以做到0.1到0.3米量级;到了城市峡谷,C/N0掉到20到30 dB-Hz很常见,加上强反射,伪距误差做到几米甚至十几米都不奇怪,而且它不是白噪声,是有偏的、随时间缓变的,进到最小二乘或者卡尔曼滤波里很难被残差检验吃掉。传统对策里,窄相关把早迟间隔压到0.1码片以内能抑制一部分长延时多径,但会牺牲抗噪性能;MEDLL靠多相关器拟合多径参数,计算量大且依赖模型假设;基于信噪比或者仰角的加权是最省事的,可它只能"降权",不能把已经歪掉的相关峰掰回来。
1.2 换一个思路:让网络自己去学"什么样的相关峰不可信"
这里的关键转变在于,过去我们是先假设一个多径信道模型(比如两径、三径、瑞利分布),再从观测里反解参数;CNN走的是另一条路,直接把一段相关器输出或者一段IQ数据当成一张"图"丢进去,让网络自己学判别特征。它不需要你告诉它"这个峰左边有个肩",它看几千个带标签的样本就能把这个模式记住。这个思路的优势在于对模型假设不敏感,城市、高架、林荫道、室内窗边这些差异极大的场景,只要样本覆盖到了,同一个网络理论上都能吃下来。
但优势也是它的软肋:CNN不会凭空知道物理约束,它对样本分布极度敏感。你在一条固定路线上采的数据训出来的模型,换条街可能就掉点。所以真正决定这套方案能不能落地的,不是网络结构多花哨,而是数据采集方案、标签生成方式、以及模型输出怎么和后面的滤波器和完好性监测衔接。这三点在多数"综述"里被一笔带过,恰恰是工程上最耗时间的部分。
2. 喂给CNN的到底是什么:北斗信号的四类可学习表征
2.1 原始IQ序列:信息最全,也最难训
最直接的方式是把射频前端采样后的复数IQ直接送进网络。以B1I为例,中频常用40.96MHz或者零中频,量化位宽1到4比特,1ms对应四万多个复数样本。直接吃这么长的序列,第一层卷积的感受野要设计得跟码片宽度匹配,B1I一个码片在40.96MHz采样下大约20个采样点,所以第一层卷积核长度设在16到32之间比较合理,相当于让网络先学"一个码片的局部形状"。
实操上的麻烦在于数据量。复数要拆成I、Q两路实数,或者按幅度相位拆,前者保留线性关系、后者对相位噪声更鲁棒。四万点乘两路,单个样本就是8万个浮点数,一个批次32个样本就是两百多万个数,普通显卡训起来很吃力。多数人会先做降采样或者只截取相关峰附近的窗口(比如峰前后各50个码片),把输入压到几千点这个量级,这样既保住了峰形信息,又不至于把显存吃光。
注意:降采样一定要在复数域做完滤波之后再做,直接对IQ抽点会把频谱搬移搞乱,训出来的模型在实测里会莫名其妙地全判成一类。
2.2 相关器输出:性价比最高的一种"伪图像"
如果只能选一种输入形式,我建议从多相关器输出开始。接收机本来就有一排相关器,抽头间隔取0.25或者0.5码片,左右各取5到6个,加上即时支路,一共11到13个抽头,每个抽头在1ms积分后得到一个复数值,连续取N个历元(比如100个),就得到一个13×100的复数矩阵,拆成实虚两通道就是13×100×2,这个尺寸对CNN来说非常友好,一层3×3卷积就能同时看到相邻抽头和相邻时间的关系。
它的好处是物理意义明确:峰形畸变、峰位漂移、峰宽变化全在这张图里,而且它已经过了解扩,信噪比增益做完了,对前端差异不敏感。我在几个项目里对比过,同样的网络结构,用相关器输出做输入比用原始IQ收敛快得多,样本需求也少一个量级。代价是丢掉了扩频前的信息,像窄带干扰这种在频域上很明显、在相关器输出上却可能只表现为整体噪底抬升的现象,就不太容易分辨。
2.3 时频图与C/N0序列:给干扰检测和欺骗识别准备的
干扰和欺骗这两类任务,信息更多藏在频域和时间的宏观变化里。把一段IQ做短时傅里叶变换,窗长取256或者512点,重叠50%,得到一张时频图,尺寸比如128×128,扫频干扰在上面就是一条斜线,脉冲干扰是一列亮点,宽带压制是一片亮区,CNN处理这类图像基本是成熟套路,直接借用图像分类的骨干网络改一改输入通道数就能跑。
C/N0序列则是另一种便宜又好用的表征。单颗卫星的C/N0随时间变化是一条一维曲线,多颗卫星拼起来就是多通道时间序列,用一维卷积处理。欺骗信号的一个典型特征是C/N0出现不符合几何规律的抬升,或者多颗卫星的C/N0同步跳变,一维卷积对这种局部突变很敏感。这类输入的优点是数据量极小,几百个点就够,训起来快,适合做前置的粗筛。
2.4 四类表征怎么选:一张对照表
| 表征形式 | 典型尺寸 | 信息完整度 | 样本需求 | 计算开销 | 适合任务 |
|---|---|---|---|---|---|
| 原始IQ(截窗) | 2×4000 左右 | 最高 | 大 | 高 | 精细多径建模、信号细微畸变分析 |
| 多相关器输出 | 2×13×100 | 中高 | 中 | 中 | 多径/NLOS判别、码相位偏差估计 |
| 时频图 | 1×128×128 | 中(频域强) | 中 | 中 | 干扰分类、欺骗检测 |
| C/N0与残差序列 | 1×N×通道数 | 低但稳定 | 小 | 低 | 粗筛、异常监测、加权决策 |
选择逻辑其实很简单:任务关心的是"解扩前的频谱特征"还是"解扩后的峰形特征"。前者用时频图,后者用相关器输出。两者都要,就做双分支融合,但先别急着上融合,单分支跑通了再说,融合带来的调参成本经常超过收益。
3. 任务侧拆解:CNN在导航链路里被用来干哪几件事
3.1 多径与NLOS信号识别
这是目前落地最多的一类。做法是把每颗卫星每个观测历元的相关器输出打成样本,标签是"直射"或者"非直射",网络输出一个概率,超过阈值就把这颗卫星从定位解算里剔除,或者给它一个更低的权重。相比传统的基于C/N0阈值加仰角门限的方法,CNN的优势体现在"低仰角但确实是直射"和"高仰角但被强反射"这两类难样本上,前者传统方法容易误杀,后者传统方法容易漏放。
我见过效果比较扎实的方案,分类准确率在自采数据集上能做到90%以上,但这个数字要小心解读——如果测试集和训练集来自同一条路线同一天,90%不说明什么。真正有意义的是跨天跨路线的表现,通常会掉到75%到85%之间。所以工程上一般不会让网络单独做决定,而是把它输出的概率作为一个观测量送进抗差估计,比如把概率映射成方差,走加权最小二乘。
3.2 干扰与欺骗信号的时频分类
干扰识别的任务边界比较清楚:扫频、连续波、脉冲、宽带压制,这四类在时频图上的形态差异大,用一个小型CNN(三五层卷积加全局池化)就能做到很高的区分度,训练样本靠信号源加衰减器在屏蔽室里采,一天能采几千个,成本可控。落地时的难点不在分类本身,而在"未知类别"的处理——现场遇到的干扰未必是你训过的那几类,模型容易把没见过的东西硬塞进已知类别里,所以输出端一般会加一个基于能量或者置信度的兜底判决。
欺骗检测更难,因为欺骗信号在单颗卫星的观测量上可能做得很像真的。有效的做法是多星联合:把可见星的C/N0、多普勒、伪距残差拼成一个多通道张量,让网络去学"整体一致性"的破坏。这类模型的解释性差,出问题时很难说清是哪颗星出了问题,所以通常会配合传统的一致性检验一起用。
3.3 伪距残差修正与加权
这一类任务直接对准定位精度,思路是用网络去预测伪距残差,然后从观测里减掉,或者反过来预测观测方差用于加权。两种做法各有拥趸:减残差看着直观,但如果网络预测有偏,会把偏差直接注入解算,风险更大;给方差更稳,最差情况是权重给得不理想,不会把解算带跑偏。我个人偏向后者。
实现上,输入一般不只是单颗卫星的相关器输出,还会把仰角、方位角、C/N0、前一时刻的残差一起拼进去。输出就是一个标量方差或者一个权重。训练标签用"事后用高精度参考轨迹反算出来的残差"生成。这里有个坑:参考轨迹本身的精度决定了标签质量,如果参考系统在城市段的误差就有半米,那你训出来的模型最好也只能逼近这半米,别指望它把误差压到0.2米。
3.4 周跳探测与载波相位质量评估
载波相位这块,传统方法靠 geometry-free 组合、Melbourne-Wübbena组合加多普勒积分来做周跳探测,对小幅周跳(1到2周)和小采样率下的判断经常不够干脆。载波波长B1I约19厘米,B3I约23.6厘米,一周的跳变对应厘米级到分米级的距离突变。CNN在这里的用法是把相位残差的时间序列、C/N0、多普勒变化率拼成多通道输入,做逐历元的二分类。
效果上,对小周跳的检出率确实比单一的GF组合高一些,尤其是在低采样率(1Hz)场景下,因为网络能用上多颗卫星之间的相关性。但代价是引入了一个新的失效模式:模型的漏检和误检都和历史窗口长度强相关,窗口取太短抓不住趋势,取太长又增加时延。工程上一般取30到60个历元,兼顾两者。
3.5 各任务的输入输出与评估口径
| 任务 | 输入 | 输出 | 主要评估指标 | 落地风险点 |
|---|---|---|---|---|
| 多径/NLOS识别 | 多相关器输出 | 直射概率 | 查准率、查全率、跨场景掉点幅度 | 阈值随环境漂移 |
| 干扰分类 | 时频图 | 类别标签+置信度 | 混淆矩阵、未知类拒识率 | 未训类别的误判 |
| 伪距加权 | 相关器+几何+残差 | 方差标量 | 定位RMSE、95分位误差 | 标签质量上限 |
| 周跳探测 | 相位残差序列 | 有无周跳 | 检出率、虚警率、平均时延 | 窗口长度敏感 |
4. 从论文到工程:数据、标签与训练链路的落地细节
4.1 标签从哪来:三条路径的取舍
这是整个流程里最花钱的一环。第一条路是纯仿真:用信号模拟器按设定的多径模型生成IQ,标签天然准确。好处是量大、可控、类别均衡,坏处是仿真信道和真实信道总有差距,训出来的模型到实测往往掉一截,业内叫"仿真到实测的鸿沟"。缓解办法是在仿真里注入实测的背景噪声,或者做域随机化,把多径的延迟、衰减、相位在合理范围内随机扫。
第二条路是半实物:真实接收机采数据,同时在场景里布置参考点,用已知的几何关系反算哪颗星被遮挡。这条路标签质量高,但采不了多少,一条路线跑一天能出几千个样本就不错了。
第三条是弱监督,用定位残差反推:某颗星在某个历元的残差明显偏离,就认为它可疑。标签噪声大,但可以刷量。实际项目里通常是三条路混着来,仿真打底、半实物校准、弱监督扩量。
4.2 数据切分:防止"同一段信号"同时出现在训练和测试里
这个坑踩的人特别多。如果按样本随机切分,同一段连续采集的信号会被切到训练集和测试集两边,相邻样本高度相关,测试准确率虚高十几个点都有可能。正确做法是按采集批次切:同一段路线、同一台设备、同一天的采集归为一个组,整组进训练或者整组进测试。更严格一点,按"场景"切,训练集只用开阔和郊区,测试集专门留给城市峡谷,这样才能看出泛化能力。
4.3 网络结构:别一上来就上大模型
我见过不少方案直接把ResNet-50搬过来,参数两千多万,在几万个样本上训,结果训练集loss掉到0.01,测试集一塌糊涂。卫星导航的信号表征维度其实不高,相关器输出13×100这种尺寸,三五层卷积加两三个全连接足够。一个可以参考的配置是:第一层3×3卷积32通道,接批归一化和ReLU;第二层3×3卷积64通道,接2×2最大池化;第三层3×3卷积128通道;然后全局平均池化接全连接输出。总参数量控制在几十万量级,训练快,端侧也能跑。
import torch import torch.nn as nn class CorrNet(nn.Module): def __init__(self, in_ch=2, n_cls=2): super().__init__() self.features = nn.Sequential( nn.Conv2d(in_ch, 32, 3, padding=1), nn.BatchNorm2d(32), nn.ReLU(inplace=True), nn.Conv2d(32, 64, 3, padding=1), nn.BatchNorm2d(64), nn.ReLU(inplace=True), nn.MaxPool2d(2), nn.Conv2d(64, 128, 3, padding=1), nn.BatchNorm2d(128), nn.ReLU(inplace=True), ) self.head = nn.Sequential( nn.AdaptiveAvgPool2d(1), nn.Flatten(), nn.Dropout(0.3), nn.Linear(128, n_cls) ) def forward(self, x): return self.head(self.features(x))这段代码没什么花哨的,但它能用。真正影响结果的是数据管线和损失函数。类别不均衡在NLOS任务里非常严重,直射样本通常占八成以上,直接训练会让模型倾向于全判直射。用带权交叉熵或者Focal Loss,把少数类的权重提上去,召回率会有明显提升。
4.4 训练中的几个数值问题
相关器输出的动态范围很大,强信号和弱信号可能差三四个数量级,直接送进网络会让梯度爆炸。常规做法是对每个样本的幅度做归一化,或者转成对数域再送进去。相位信息要小心处理,直接取实虚两路在某些情况下会引入载波相位跳变带来的不连续,可以考虑用幅度加相位的正弦余弦编码。
还有一点是输入的时间对齐。相关器输出是按历元排的,如果采集过程中有丢帧,时间轴就断了,训出来的时间卷积实际上在学错误的东西。预处理阶段一定要做时间戳校验,发现断层就整段丢弃,别想着插值补上。
5. 部署侧的现实约束:算力、时延与泛化
5.1 端侧算力预算怎么算
接收机端的处理器通常是ARM Cortex-A系列,算力从几百MOPS到几个GOPS不等,跟手机SoC没法比。一个几十万参数的CNN,单次推理大概在几百万次乘加的量级,跑在1GHz的A核上大概几毫秒到几十毫秒。这个时延对多径识别、周跳探测这类任务完全够用,因为这些决策本来就是秒级或者历元级的,不是毫秒级的。
但要注意,码环和载波环是实时的,环路更新周期可能是1ms或者更短,任何跟环路串联的模型都必须在这个时间窗内完成。所以工程上的普遍做法是模型不进环路,只进观测域:环路照常跑,模型在观测层做判别和加权,这样时延约束就宽松得多。
5.2 量化与剪枝:别在小模型上用力过猛
INT8量化在图像任务上一般掉点不多,但在这种信噪比本来就低的任务上要谨慎。相关器输出的弱信号部分幅度很小,量化到8位之后有效位数不够,弱信号样本的判别精度会明显下降。我的经验是输入层保留FP16或者做逐通道量化,中间层再上INT8,实测精度损失能控制在1到2个百分点以内。
剪枝的收益在小模型上不明显。一个五十万参数的模型剪掉一半,推理速度可能只提升20%,因为瓶颈往往在内存访问而不是计算。不如直接把输入尺寸降下来,比如把13×100的时间窗缩到13×50,效果更直接。
5.3 跨场景泛化:这是最容易被低估的问题
同一个城市,晴天和雨天的多径特性不一样;同一条路,早晚高峰车流不同,反射面也不同。模型在训练集上90%,换到新场景掉到70%是常态。缓解手段有几种:一是做在线自适应,用无标签的新数据做几次微调,但端侧做反向传播代价太大;二是做集成,训几个在不同场景下表现好的模型,用不确定性加权融合;三是把模型输出和传统方法做"与"逻辑,只有两者都认为可疑才剔除,牺牲一点查全率换稳定性。
我个人更倾向第三种,因为导航这个领域对连续性和完好性的要求高于对极限精度的追求。宁可少剔除几颗可疑星,也不能把好星误剔导致几何构型变差、精度反而下降。
6. 评估与踩坑:怎么判断模型是真有用还是过拟合了数据
6.1 别只看分类准确率
分类准确率是最容易好看也最容易骗人的指标。样本不均衡时,全判多数类就能有80%的准确率。要看查全率和查准率的平衡,画ROC曲线算AUC,更重要的是看"在固定虚警率下的检出率"——工程上虚警的代价通常高于漏检,因为频繁剔除卫星会让解算几何变差。可以定一个目标,比如虚警率控制在5%以内,看检出率能到多少,这个数字才有参考价值。
6.2 端到端验证:模型指标好不等于定位精度好
这一点必须单独强调。分类任务涨了两个点,定位精度可能一点没变,甚至变差。原因是定位解算是一个多星加权的过程,单星判别的提升能不能转化成定位提升,取决于被正确判别的那些星在几何构型里占多大权重。验证方法只有一个:把模型接进完整的解算链路,用同一批测试数据跑开环和闭环两种模式,比较水平误差的RMS、95分位误差,还有固定解率(如果用RTK)。只有闭环指标提升了,才算真有用。
6.3 几个踩过的坑
第一个坑是标签泄漏。前面提过按样本随机切分的问题,还有一种更隐蔽的:用参考轨迹反算残差做标签时,如果参考轨迹本身用了待评估的那些卫星,标签里就混进了被测信号的信息,评估结果虚高。
第二个坑是预处理不一致。训练时用了某种归一化,部署时忘了加,或者用了不同的窗长,模型在端上表现断崖式下跌。建议把预处理写成一个独立的、可序列化的模块,训练和推理共用同一份代码。
第三个坑是忽略温度和时间的影响。射频前端的增益随温度漂移,采集时的增益设置如果和部署时不同,相关器输出的绝对幅度就变了。用幅度归一化能缓解,但如果模型偷偷学了绝对幅度的特征(比如靠整体能量高低判断强弱信号),换个增益就失效。可以在训练时做增益随机化,让模型对这个维度不敏感。
第四个坑是过度依赖单一数据源。只用一台设备采的数据,训出来的模型可能学到的是这台设备的滤波器特性、天线方向图,而不是信号本身的物理规律。至少用两三台不同前端的数据混着训,泛化会好很多。
最后分享一个实际体会:这类方案真正的价值不在于把某个指标刷高几个点,而在于它提供了一种"把难以建模的误差源当成模式识别问题来处理"的思路。多径、干扰、欺骗这些东西,物理机制复杂到很难写出一组完备的方程,但它们在观测数据里留下的痕迹是有规律的,CNN擅长的正是抓这种规律。把它的输出当成一个额外的观测量,交给后面的抗差估计和完好性监测去消化,比让它直接接管决策要稳得多。至于模型结构、输入形式、训练技巧,都是在这个框架下逐步磨出来的,先跑通最小闭环,再谈优化。