简介:这份资源围绕全球导航卫星系统GNSS中的欺骗攻击与欺骗检测算法展开,面向卫星导航安全、组合导航方向的研究人员、工程师及定位技术开发者,重点解决GNSS信号易被伪造、定位结果遭恶意操纵时的检测与鲁棒性问题。内容以IMU与GNSS融合定位为主线,讲解如何借助惯性测量单元的连续加速度与角速度数据,在信号受扰或遮蔽时维持定位连续性,并结合信号特征、位置速度一致性及统计方法识别欺骗信号,同时涉及支持向量机、随机森林、神经网络等机器学习手段在欺骗识别中的应用。资源包共30个文件,以xml文档结构、png与jpg插图为主,另有rels关系文件,压缩包约1.99MB,便于查阅算法流程与结果图示。已有44人学习下载。读者可据此理解融合系统下欺骗检测的设计思路与鲁棒性要求,并借助附带的Matlab代码在仿真环境中复现算法、验证检测性能,兼顾学术研究与工程实践参考。
1. 从一次定位漂移说起:这套 GNSS 欺骗检测资源到底能干什么
如果你做过车载或无人机定位,大概率遇到过这种玄学现象:接收机输出的经纬度平滑得像抹了黄油,轨迹却整体偏移了几十米,甚至朝着一个固定方向匀速“漂”走。多数人第一反应是天线遮挡或多路径,但还有一种更隐蔽的可能——GNSS 欺骗。欺骗信号不是让定位丢失,而是让你“定位得很自信地错着”。这套资源围绕的就是这个问题:用 IMU 与 GNSS 融合做定位,再通过一致性检验把欺骗揪出来,附带的 MATLAB 代码把从数据仿真、融合滤波到检测指标统计的链路都串了一遍。它适合做导航、自动驾驶感知、无人机飞控的从业者,也适合正在找“能跑通、能改参数、能出图”的课程设计或论文复现素材的人。下面我按自己拆包复现的顺序,把这份资源讲透。
2. GNSS 欺骗的机理与 IMU 融合检测的选型逻辑
2.1 欺骗信号为什么比干扰更难缠
干扰是压制,接收机直接失锁,你立刻知道出问题了。欺骗是伪造:攻击者发射与真实卫星信号结构相同、但码相位和载波多普勒被篡改的信号,接收机在捕获跟踪阶段被“拉偏”,最终解算出错误的伪距和位置。常见手法分两类,一类是转发式,把真实信号延迟后转发,造成缓慢的位置偏移;另一类是生成式,直接合成伪造的导航电文和测距码,可以精确控制目标位置。前者隐蔽性强,后者灵活度高。
从检测角度看,纯 GNSS 域的方法有局限。接收机自主完好性监测(RAIM)依赖冗余卫星的伪距一致性,如果攻击者同时篡改多颗星且保持内部自洽,RAIM 的检验统计量可能不超限。信号质量监测能看载噪比异常,但转发式欺骗的载噪比可以做得很自然。所以这套资源走的是另一条路:引入 IMU 这个独立信息源,用惯性递推的短时高精度去和 GNSS 的长期稳定做交叉验证。IMU 在几秒内不会突变,而欺骗要拉偏位置,必然在某个时刻让 GNSS 与惯性预测产生不可调和的残差。
2.2 为什么选 IMU+GNSS 融合而不是纯 GNSS 检测
选型理由有三条。第一,信息冗余。GNSS 给绝对位置但可被篡改,IMU 给相对运动但会漂移,两者误差特性互补,融合后的新息序列天然携带不一致信息。第二,物理约束。载体运动学有连续性,位置和速度不会瞬变,欺骗注入的阶跃或斜坡在加速度层面会露出马脚。第三,工程可落地。IMU 现在成本很低,MEMS 器件就能提供足够的短时角速度和比力,融合框架用扩展卡尔曼滤波(EKF)就能搭起来,不需要重新设计接收机固件。
资源里的融合架构是松组合:GNSS 输出位置和速度作为量测,IMU 做状态预测,EKF 估计位置、速度、姿态和传感器偏置。检测逻辑挂在滤波之后,对新息和新息协方差做统计检验。这样做的好处是检测模块和滤波模块解耦,你换滤波算法或换检测门限都不影响另一部分。
2.3 资源里的算法链路拆解
拆开代码包,主链路大致是:轨迹与 IMU 数据生成 → GNSS 量测模拟(含欺骗注入开关)→ EKF 预测与更新 → 新息计算 → 卡方检验与 CUSUM 检验 → 检测结果与轨迹对比绘图。数据生成部分用预设轨迹加噪声,方便你控制变量;欺骗注入支持阶跃、斜坡和慢漂移三种模式,对应不同的攻击强度。检测部分给了两种统计量,卡方检验看单历元新息是否超限,CUSUM 看累积偏差,后者对慢漂移更敏感。
这里要强调一个参数:新息协方差矩阵 S。EKF 里 S = H P H' + R,H 是量测雅可比,P 是状态协方差,R 是量测噪声阵。检测门限由卡方分布的自由度和置信水平决定,量测是三维位置加三维速度时自由度是 6。如果你只用量测位置,自由度就是 3,门限会变。代码里这个自由度是写死的,改量测维度时记得同步改,否则门限对不上,检测要么虚警爆炸要么完全失灵。
3. 把 MATLAB 代码跑起来:数据生成、EKF 融合与检测实现
3.1 环境准备与文件结构确认
拿到的是 .docx.rar,先解压。里面通常有一份说明文档和若干 .m 文件。我一般会先确认三件事:MATLAB 版本是否支持用到的函数(比如chi2inv需要统计工具箱),当前文件夹是否已切换到代码所在目录,以及有没有依赖的 .mat 数据文件。建议单独建一个工作目录,把解压后的文件全部放进去,避免路径污染。
% 检查环境和路径,放在脚本最前面跑一次 clc; clear; close all; % 确认统计工具箱可用,卡方检验门限要用 if isempty(which('chi2inv')) error('缺少统计工具箱,chi2inv 不可用,请安装或改用查表法'); end % 切换到代码所在目录,避免读写文件找不到 cd(fileparts(mfilename('fullpath'))); disp('环境检查通过');这段代码做两件事:清空工作区防止旧变量干扰,检查chi2inv是否存在。mfilename('fullpath')拿到当前脚本的完整路径,再取父目录切换过去,这样无论你从哪里启动 MATLAB 都能定位到数据文件。如果你的 MATLAB 没装统计工具箱,可以自己算卡方分位数或者用固定门限先跑通流程,但检测性能会打折扣。
3.2 轨迹与 IMU/GNSS 数据生成
数据生成脚本负责造一条已知真值的轨迹,再分别生成 IMU 的理想输出和加噪输出,以及 GNSS 量测。欺骗注入通过一个开关和模式参数控制。常见做法是用匀速转弯或蛇形机动作为基础轨迹,因为这类运动在加速度上有明显变化,融合滤波的可观测性更好。
% 生成基础轨迹:匀速直线加一段转弯,采样率 100Hz,时长 60s dt = 0.01; T = 60; t = 0:dt:T-dt; N = length(t); % 真值位置:前 30s 直线,后 30s 转弯 pos = zeros(3, N); vel = zeros(3, N); for k = 2:N if t(k) < 30 acc = [0.5; 0; 0]; % 直线段小幅加速 else acc = [0; 0.8; 0]; % 转弯段侧向加速度 end vel(:,k) = vel(:,k-1) + acc*dt; pos(:,k) = pos(:,k-1) + vel(:,k-1)*dt + 0.5*acc*dt^2; end % IMU 加噪:陀螺和加计各加零均值高斯噪声 gyro_noise = 0.01; acc_noise = 0.05; gyro_meas = randn(3,N)*gyro_noise; acc_meas = repmat(acc,1,N) + randn(3,N)*acc_noise; % GNSS 量测:位置加速度噪声,并注入欺骗 gnss_noise = 1.5; gnss_pos = pos + randn(3,N)*gnss_noise; spoof_on = true; spoof_start = 40; spoof_rate = 0.5; % 40s 后斜坡欺骗 if spoof_on idx = t >= spoof_start; gnss_pos(:,idx) = gnss_pos(:,idx) + spoof_rate*(t(idx)-spoof_start); end参数说明:dt是采样间隔,决定 IMU 积分精度;acc是各段加速度,影响可观测性;gyro_noise和acc_noise是 IMU 噪声标准差,太小检测太容易,太大滤波发散;gnss_noise是 GNSS 位置噪声,单位是米;spoof_start和spoof_rate控制欺骗起始时间和漂移速率,斜坡欺骗比阶跃更难检测,适合调参练手。注意这里加速度变量acc在循环外被复用,实际代码里要按段赋值,别直接抄成常量。
3.3 EKF 融合与检测统计量计算
融合部分用松组合 EKF,状态取 9 维:位置、速度、姿态误差,或者简化成位置速度 6 维。资源里为了突出检测,状态维数不高。预测用 IMU 的比力和角速度积分,更新用 GNSS 位置速度。检测统计量在新息上算。
% 简化 EKF:状态 [px py pz vx vy vz],量测为 GNSS 位置 nx = 6; nz = 3; x = zeros(nx,1); P = eye(nx)*10; Q = diag([0.01 0.01 0.01 0.1 0.1 0.1]); % 过程噪声 R = eye(nz)*gnss_noise^2; % 量测噪声 H = [eye(3) zeros(3,3)]; % 量测矩阵,只测位置 thr = chi2inv(0.99, nz); % 卡方门限,自由度=量测维数 detect = zeros(1,N); innov_norm = zeros(1,N); for k = 2:N % 预测:用 IMU 加速度推进速度位置 F = [eye(3) eye(3)*dt; zeros(3) eye(3)]; B = [0.5*dt^2*eye(3); dt*eye(3)]; x = F*x + B*acc_meas(:,k); P = F*P*F' + Q; % 更新:GNSS 位置 z = gnss_pos(:,k); y = z - H*x; % 新息 S = H*P*H' + R; % 新息协方差 K = P*H'/S; x = x + K*y; P = (eye(nx)-K*H)*P; % 检测:马氏距离平方与门限比较 d2 = y'/S*y; innov_norm(k) = d2; detect(k) = d2 > thr; end逻辑说明:F是状态转移矩阵,位置由速度积分,速度保持不变;B把加速度映射到状态,acc_meas来自 IMU。新息y是 GNSS 量测减预测,S是新息协方差,d2是马氏距离平方,服从卡方分布。thr用chi2inv(0.99, nz)算,置信水平 0.99,自由度等于量测维数 3。detect记录每个历元是否超限。这里把加速度当控制输入,实际 IMU 还要做姿态投影,简化版先跑通逻辑。注意Q和R的比例决定滤波信任谁,R 调大滤波更信 IMU,检测对 GNSS 偏差更敏感,但也更容易虚警。
3.4 检测结果可视化与指标统计
跑完融合和检测,要把结果画出来才能判断。资源里一般会画三条轨迹:真值、融合输出、GNSS 原始输出,再叠加检测标志。指标统计包括检测率、虚警率和检测延迟。
% 画轨迹对比和检测统计量 figure; subplot(2,1,1); plot(pos(1,:), pos(2,:), 'k-', 'LineWidth', 1.5); hold on; plot(gnss_pos(1,:), gnss_pos(2,:), 'r--'); plot(x(1,:), x(2,:), 'b-'); % 注意 x 是最后时刻状态,实际要存历史 legend('真值','GNSS','融合'); xlabel('东向/m'); ylabel('北向/m'); title('轨迹对比'); subplot(2,1,2); plot(t, innov_norm); hold on; yline(thr, 'r--', '门限'); plot(t(detect==1), innov_norm(detect==1), 'ro'); xlabel('时间/s'); ylabel('马氏距离平方'); title('检测统计量'); % 指标:以 spoof_start 为界统计 spoof_idx = t >= spoof_start; det_rate = sum(detect(spoof_idx))/sum(spoof_idx); fa_rate = sum(detect(~spoof_idx))/sum(~spoof_idx); fprintf('检测率 %.2f,虚警率 %.2f\n', det_rate, fa_rate);这段代码里有个坑:x在循环里被覆盖,画轨迹要提前存x_hist(:,k),否则画出来是一条线。指标统计用spoof_start做真值标签,检测率是欺骗段内超限比例,虚警率是非欺骗段超限比例。检测延迟可以找欺骗段内第一个超限历元减去spoof_start对应的时间。门限thr直接决定这两个指标的权衡,调置信水平就能看到此消彼长。
4. 避坑与排查:复现时最容易翻车的五个地方
4.1 现象:检测率很高但虚警也高,轨迹图上看不出问题
原因:门限设得太松,或者量测噪声R设得偏小,导致新息协方差S偏小,马氏距离平方整体偏大。也可能是自由度写错,量测三维却用了自由度 6 的门限,门限偏低。
解决:先确认nz和chi2inv的第二个参数一致。再把R调到和实际 GNSS 噪声匹配,可以用静止段数据估一下位置噪声标准差。最后画innov_norm的直方图,非欺骗段应该大部分落在门限以下,如果整体右移就是S偏小。
4.2 现象:滤波轨迹在欺骗开始后跟着 GNSS 一起偏
原因:过程噪声Q太小,滤波过度信任 IMU 的积分,但 IMU 有偏置,长时间后预测本身也偏;或者Q太大,滤波过度信任 GNSS,直接把欺骗量测吃进去。
解决:调Q和R的比例。一个实用做法是先用无欺骗数据跑一遍,看新息是否零均值白噪声,再注入欺骗看新息是否出现系统性偏差。如果融合轨迹跟着偏,说明滤波对 GNSS 的信任过高,适当增大Q或减小R让预测权重更大。但注意Q太大会让滤波对真实机动响应变慢。
4.3 现象:CUSUM 检测对阶跃灵敏但对慢漂移没反应
原因:CUSUM 的累积和参数没调好,漂移速率低于累积阈值增长斜率,累积量被遗忘因子压住。或者漂移方向与载体运动方向一致,新息本身变化不明显。
解决:调 CUSUM 的参考值k和判决阈值h。k一般取新息偏差的一半,h取 4 到 5 倍标准差。对慢漂移,可以先把新息做滑动平均再累积,或者改用广义似然比检验。资源里如果只给了卡方检验,慢漂移场景要自己补 CUSUM,别指望单历元检验能抓住。
4.4 现象:换一组轨迹数据后检测完全失效
原因:检测门限和噪声参数是针对原轨迹调的,换了运动模式后新息统计特性变了。比如原轨迹是直线,新轨迹频繁转弯,加速度变化让预测误差增大,非欺骗段新息就超限了。
解决:检测参数要跟着数据走。每次换数据集,先用前一段无欺骗数据做自适应估计,算新息的均值和协方差,再定门限。代码里可以把前 10 秒设为初始化段,不检测只估计。另外姿态投影别省,IMU 加速度要转到导航系,否则转弯时重力分量混进来,新息直接爆掉。
4.5 现象:MATLAB 报错矩阵维度不一致,定位到H*P*H'
原因:状态维数和量测维数没对齐,或者P在循环里被更新成了非方阵。常见于把K*H写成H*K,或者S求逆时用了/而不是\导致维度错。
解决:在循环里加断言,assert(isequal(size(P),[nx nx])),assert(size(H,2)==nx)。S是标量还是矩阵要分清,单量测时S是标量可以直接除,多量测时用S\y或inv(S)*y。调试时把nx、nz、size(H)、size(P)打出来,一眼就能看出哪一步维度变了。
5. 进阶技巧:用自适应门限和残差白化把检测做稳
跑通基础版之后,真正决定这套东西能不能用在工程里的,是门限的自适应和残差的白化处理。固定门限在实验室数据上好看,换场景就崩,这是血泪经验。我一般会做两件事。
第一,残差白化。EKF 的新息理论上应该是白噪声,但实际因为模型误差和 IMU 偏置,新息会有色。做法是对新息序列做在线估计,算滑动窗口内的均值和协方差,用S_hat代替理论S去算马氏距离。这样门限对模型误差不敏感。代码上就是在检测前加一个窗口长度 50 到 100 的滑动统计。
% 自适应新息协方差估计,窗口 50 win = 50; S_adapt = R; % 初始用理论值 for k = 2:N % ... 预测和更新同上 ... y = z - H*x; if k > win Y_win = innov_hist(:, k-win:k-1); S_adapt = cov(Y_win') + R; % 滑动协方差加量测噪声 end d2 = y'/S_adapt*y; detect(k) = d2 > chi2inv(0.99, nz); innov_hist(:,k) = y; end第二,多统计量联合判决。单靠卡方检验对慢漂移不够,加上 CUSUM 和新息变化率。三个统计量各自设门限,用多数投票或者逻辑或。代价是虚警率上升,所以门限要相应收紧。我一般把卡方置信水平提到 0.995,CUSUM 阈值取 5 倍标准差,变化率门限取 3 倍标准差,联合下来虚警能压到 1% 以下,检测延迟在 1 到 2 秒。
验证方法上,别只看检测率。构造几组对照:无欺骗、阶跃欺骗、斜坡欺骗、慢漂移欺骗,每组跑 20 次蒙特卡洛,统计检测率和虚警率的均值和方差。如果某组方差特别大,说明参数对该场景敏感,要单独调。另外把检测时刻和欺骗起始时刻对齐画出来,看延迟分布,工程上延迟超过 3 秒基本就来不及做切换了。
最后说个习惯:每次改完参数,我都会把Q、R、门限、窗口长度记在一个表里,跑完对照指标填进去。这套资源的价值不在于代码多完美,而在于它把欺骗注入和检测评估的闭环搭好了,你可以在这个骨架上换滤波、换检测、换轨迹,快速验证自己的想法。希望帮到你。
本文还有配套的精品资源,点击获取