Python综合实践报告:GPS欺骗信号检测与防御系统
| 项目 | 内容 |
|---|---|
| 课程 | Python程序设计 |
| 班级 | 2431 |
| 姓名 | 代雨航 |
| 学号 | 20243105 |
| 实验教师 | 王志强 |
| 实验日期 | 2026年5月11日 — 6月16日 |
| 必修/选修 | 公选课 |
项目代码通过 PyCharm VCS 推送至远程仓库(源代码见提交附件
sdr_defense.zip)
演示视频:https://www.bilibili.com/video/你的视频ID
一、项目概述
我这个综合实践做的是一个GPS欺骗信号检测系统。起因是我在搞大创项目,研究的是GPS欺骗攻防——简单说就是有人用HackRF这种SDR设备发射假GPS信号,让接收机算出错误的位置。那我想从防御角度出发,用Python搭一套能识别这种欺骗的系统。
项目主要在PyCharm里写,15个.py文件,大概6000多行。另外还有一个HTML仪表盘,浏览器打开就能看到实时的检测数据。
📷 截图1:PyCharm项目结构,展示sdr_defense下所有.py文件
主要用到的Python库:numpy做矩阵运算、scipy做信号处理、sklearn和PyTorch训练模型、tkinter做控制面板、websockets做实时推送。
几个主要功能:
- 信号质量评分:根据SNR、DOP这些指标给定位信号打分(0-100),分数突然跳水就报警
- 残差检测:算GNSS定位和融合定位之间的差距,差值太大说明可能被欺骗了
- 随机森林分类器:用sklearn训练了一个二分类模型判断是否被攻击
- 卡尔曼滤波融合:6状态EKF把GNSS和IMU数据融合,用innovation的统计量辅助检测
- LSTM时序检测:BiLSTM网络对7维特征滑窗20帧,训练出来区分度很高(正常≈0.003,欺骗≈0.993)
- Web仪表盘:tkinter启动HTTP+WebSocket服务,浏览器打开dashboard.html就能看到地图、图表和告警
后面还加了对抗攻防、频谱指纹、联邦学习这些高级模块,但核心检测就靠上面这几个。
二、程序设计
2.1 整体架构与数据流
整个系统分为四层:数据输入层→信号检测层→智能分类与融合层→可视化仪表盘。
第一层数据输入有两种模式:仿真模式下用 numpy 生成模拟 GPS 定位数据(包含位置、SNR、DOP 等),真实模式通过 NMEA-0183 协议从 SR01 接收机的串口读取 $GPGGA 语句。HackRF 也可以作为攻击端注入虚假 GPS 信号。
第二层信号检测从原始数据中提取特征并做初步判断。信号质量评分模块综合 SNR、DOP、卫星数三个维度给出 0-100 的评分,低于阈值就触发预警。残差分析模块计算 GNSS 定位结果和其他定位源(IMU 航位推算、WiFi 指纹)之间的差距,如果 GNSS 突然跳变而其他定位源保持连续,就高度怀疑被欺骗。
第三层智能分类与融合是核心。随机森林分类器用 sklearn 训练了一个二分类模型,输入特征包括 SNR 均值、HDOP、卫星数、信号质量评分等,输出正常/欺骗的概率。BiLSTM 时序检测器用 7 维特征滑窗 20 帧送入双向 LSTM 网络,训练出来区分度很高(正常评分约 0.003,欺骗评分约 0.993),因为它能捕捉到欺骗信号在时序上的不连续性。卡尔曼滤波的 6 状态 EKF 把 GNSS 位置和 IMU 加速度融合,计算 innovation 的马氏距离——正常情况下远小于 4,一旦超过阈值就判定为欺骗,因为假信号会导致滤波器的预估值和观测值严重偏离。
第四层可视化仪表盘是一个单页 HTML 应用。选用 Leaflet 渲染高德地图瓦片,WebSocket 接收后端推送的 JSON 数据流,实时更新地图追踪、SNR 柱状图和检测状态。仪表盘参照 QT 桌面端设计了四页面布局:监控中心(收录了所有功能到同一页面,6 项统计卡片、仿真轨迹追踪、8 颗卫星的信号柱状图、轨迹进度条、模块状态列表)、信号生成(信号参数配置、攻击控制、功放开关、循环发射、命令日志)、卫星分析(HTML 交互式 SkyPlot 天图显示 GPS/北斗卫星方位仰角,悬停弹出卫星详情,用国旗图标区分 GPS 和北斗)、抗干扰设置(信噪比阈值、仰角限制、多径抑制三种模式)。
2.2 模块清单与技术栈
15 个 Python 模块按功能分为五类,各自承担不同的算法角色:
基础检测层(2 个模块):
| 模块 | 核心技术 | 功能 |
|---|---|---|
spoofing_detector.py |
信号质量评分 + 残差分析 | 综合 SNR/DOP/卫星数打分,检测 GNSS 与 IMU/WiFi 的定位偏差 |
rf_classifier.py |
sklearn 随机森林 | 13 维特征二分类,判断正常/欺骗,模型可持久化为 .pkl 文件 |
融合定位层(3 个模块):
| 模块 | 核心技术 | 功能 |
|---|---|---|
kalman_fusion.py |
6 状态扩展卡尔曼滤波 | GNSS+IMU 松耦合,innovation 马氏距离辅助欺骗检测 |
fusion_engine.py |
动态权重融合 | 根据各定位源置信度动态分配权重,输出最优融合位置 |
wifi_fingerprint.py |
WiFi RSSI 指纹匹配 | 基于 WiFi 信号强度的室内定位,作为 GNSS 之外的独立定位参考 |
深度学习层(2 个模块):
| 模块 | 核心技术 | 功能 |
|---|---|---|
lstm_detector.py |
PyTorch BiLSTM | 7 维特征滑窗 20 帧,双向时序建模,捕捉欺骗信号的不连续性 |
cnn_scene_classifier.py |
1D-CNN 场景分类 | 根据信号特征自动区分开阔/城市/室内场景,调整检测策略 |
创新攻防层(5 个模块):
| 模块 | 核心技术 | 功能 |
|---|---|---|
adversarial_defense.py |
FGSM 对抗训练 | 防御针对检测模型的对抗样本攻击 |
rf_fingerprint.py |
射频指纹认证 | 提取发射机硬件特征,区分真实卫星和 HackRF 伪卫星 |
federated_detection.py |
联邦学习 | 多节点协同训练检测模型,保护数据隐私 |
gnn_topology.py |
图神经网络 | 分析卫星空间拓扑关系,检测异常卫星分布 |
rl_battle.py |
强化学习 | 攻防博弈框架,训练自适应欺骗策略和反制策略 |
控制与接口层(2 个模块):
| 模块 | 核心技术 | 功能 |
|---|---|---|
hackrf_controller.py |
libhackrf 封装 | 控制 HackRF 发射 GPS 欺骗信号,支持固定/渐进/压制三种模式 |
nmea_bridge.py |
NMEA-0183 协议解析 | 串口读取 $GPGGA 等语句,解析为结构化数据供上层使用 |
前端仪表盘(1 个模块):
| 文件 | 核心技术 | 功能 |
|---|---|---|
dashboard.html |
Leaflet + WebSocket + 高德瓦片 | 纯前端单页应用,四页面布局,内置平滑仿真引擎,交互式 SkyPlot,编辑模式可点击地图添加航点,支持圆形轨迹生成和 CSV 导入导出 |
2.3 核心代码
卡尔曼滤波(GNSSIMUKalmanFilter 类,检测的核心算法):
📷 截图3:PyCharm中打开 kalman_fusion.py,展示 EKF 核心代码
class KalmanFusion:def __init__(self):self.x = np.zeros(6) # [lat, lon, alt, vN, vE, vD]self.P = np.eye(6) * 100self.Q = np.eye(6) * 0.1self.R = np.eye(3) * 5def predict(self, dt):F = np.eye(6)F[0,3] = dt / 111000 # 速度(m/s)转经纬度(deg/s)F[1,4] = dt / 111000F[2,5] = dtself.x = F @ self.xself.P = F @ self.P @ F.T + self.Qdef update(self, z):innov = z - self.H @ self.xS = self.H @ self.P @ self.H.T + self.Rd2 = innov.T @ np.linalg.inv(S) @ innovif d2 > 4.0: # 马氏距离超阈值→欺骗return None, TrueK = self.P @ self.H.T @ np.linalg.inv(S)self.x = self.x + K @ innovself.P = (np.eye(6) - K @ self.H) @ self.P
这里面有一个坑——F矩阵里速度单位是m/s,但经纬度单位是度,不除以111000的话P矩阵会爆炸。这个bug调了我半天。
Web仪表盘采用了 Leaflet + 高德地图瓦片 + WebSocket 架构。选择高德瓦片是因为 OpenStreetMap 在国内加载极慢,换成高德后秒开。参照 QT 桌面端设计了四页面布局,并把轨迹编辑功能整合进了监控中心(同一个地图,通过侧栏的"切换编辑模式"按钮切换点击行为:监控模式下点击地图即居中,编辑模式下点击地图即添加航点)。SkyPlot 用纯 HTML/CSS 实现,每颗卫星用 GPS 或北斗的国旗emoji标识,悬停弹出 PRN、方位角、仰角、SNR 详情。内置了一个平滑的圆周仿真引擎,不连 Python 后端也能演示红紫色的轨迹追踪,进度条实时显示当前走到了预定轨迹的百分之多少。左侧导航底部加了全局控制按钮(清除橙色轨迹、仿真暂停/运行)。欺骗演示通过点击监控中心横幅一键切换,切换后地图自动隐藏真实 GNSS 轨迹只显示欺骗红点。踩过不少坑:
- 导航栏在Edge里点不了——JS语法错误导致整个script没执行,拆成两个script标签解决
- Chart.js CDN被拦截——换成纯CSS柱状图,鼠标悬停显示卫星PRN和数值
- Leaflet和OSM瓦片在国内加载不了——CDN换jsdelivr,瓦片换高德
- 下拉菜单在暗色主题下白底灰字看不清——option强制暗色背景
2.4 遇到的问题和解决
- F矩阵单位问题:卡尔曼滤波的P矩阵爆炸到1.32,检查发现速度(m/s)没转经纬度(deg)。加除以111000后正常。
- PyTorch在Windows上报错:
getpass.getuser()失败,需设TORCHINDUCTOR_CACHE_DIR和USERNAME环境变量。 - 导航栏点不了:从改CSS到改JS折腾了四五版,最后发现是一个JS语法错误导致整个script没执行,拆成两个script标签解决了。
- 地图加载不出来:Leaflet CDN(unpkg.com)和OpenStreetMap瓦片在国内被墙,CDN换成jsdelivr,瓦片换成高德地图,秒开。
- 下拉菜单白底灰字:暗色主题下
<select>的<option>默认白底灰字完全看不清,加option{background:#10141c}解决。 - SkyPlot太简陋:Canvas版没有交互,改成HTML实现后支持悬停弹出卫星详情、国旗标识国别、添加图例。
- 两个地图冗余:监控和轨迹编辑各有一个Leaflet实例,布局重复、维护麻烦。合并为单地图 + 模式切换,点击行为按需切换。
三、运行结果
📷 截图4:PyCharm终端运行
python sdr_monitor.py --simulate
📷 截图5:浏览器仪表盘——正常状态(绿色,显示"系统正常")
欺骗激活后——红色告警,地图上出现红色欺骗标记
轨迹编辑页面——在地图上点了几下加了航点
信号生成页面——HackRF攻击控制面板
见附件及视频
结果总结:
- 正常场景EKF收敛后定位精度约1.8米
- 注入500米偏移后innovation的统计量从0.01跳到136,远超阈值4,触发告警
- BiLSTM在400条数据上准确率100%,正常评分≈0.003、欺骗≈0.993
- CNN场景分类准确率92.5%
四、全课总结
4.1 知识点总结
1. Python 基础语法
Python 和 C 语言最大的区别是不用声明变量类型、不用分号、靠缩进定义代码块。刚开始老是忘缩进报 IndentationError,写多了才形成肌肉记忆。变量赋值直接用等号,支持 a, b = 1, 2 这种同时赋值。注释用 #,多行用三引号。
2. 数字类型与运算符
整数、浮点数、复数三种,Python 的整数没有溢出限制。算术运算符 + - * / // % **,比较运算符 == != < >,逻辑运算符 and or not。写卡尔曼滤波器时矩阵运算全靠 @ 运算符。
3. 条件与循环
if-elif-else 判断分支,for 遍历列表/range,while 条件循环。break 跳出、continue 跳过本次。仿真引擎里的定时循环就是 while True 套 time.sleep。
4. 序列类型
- 列表
[]:可变,增删改查都能做,append、sort、切片最常用 - 元组
():不可变,存坐标这种不需要改的数据 - 字典
{}:键值对,存配置参数很方便 - 集合
{}:自动去重,WebSocket 客户端集合就是这么用的
5. 字符串与正则
strip() 去空格、split() 分割、f"{变量}" 格式化。正则 re.search、re.findall、re.sub,NMEA 解析和 AI 返回结果提取全靠这个。
6. 函数与面向对象
def 定义函数,参数可以设默认值,return 返回值。面向对象三大特性——封装(class 把数据和操作包一起)、继承(tkinter 的 Frame 继承来做自定义面板)、多态。整个检测系统就是面向对象设计的:DataEngine、KalmanFusion、WSBridge 各是一个类。
7. 异常处理
try-except-finally,最重要的习惯是在可能炸的地方加 try。WebSocket 连不上、串口打不开、API 调用失败——不用 try 程序直接崩。
8. 文件操作
open 打开、read/write 读写、with 自动关闭。配置参数读写、CSV 导出行迹都用到。
9. 网络通信
socket 基础的 TCP/UDP,websockets 做实时推送,http.server 搭简单的文件服务。仪表盘就是 HTTP(端口8766)+ WebSocket(端口8765)双通道。
10. 爬虫基础
requests 发 GET/POST 请求、加 headers 伪装。虽然本项目的 API 调用是 WebSocket 不是 HTTP,但理解请求/响应模型是共通的。
11. 数据处理
numpy 矩阵运算(卡尔曼滤波的状态转移全靠这个)、scipy.signal 做滤波和谱分析、matplotlib 画图。
12. 机器学习
sklearn 训练随机森林分类器,PyTorch 搭建 BiLSTM 和 CNN。学会了数据预处理→训练→评估→保存→加载的完整流程。
13. GUI 开发
tkinter 做控制面板(串口选择、模式切换、一键启动),HTML+Leaflet 做仪表盘。两个方案各有适用场景。
14. 版本管理与协作
Gitee 托管代码、git commit/push,写 commit message 的习惯也养成了。
4.2 课程感悟
选这门课之前,我只在 C 语言课上学过一点基础语法,Python 对我来说只是一个"据说很简单"的语言。第一次在 PyCharm 里敲出 print("Hello World"),看到控制台弹出一行字,竟然有点激动——原来让计算机听我的话就这么简单。
之后一路从变量、循环、列表学到面向对象、多线程、网络通信。印象最深的是学到 socket 那章,突然反应过来小时候玩 MC 要输 IP 地址联机,原来底层就是 socket 通信——那一刻真切感受到了"学以致用"是什么意思。
综合实践做 GPS 欺骗检测,把前面学的几乎全用上了。卡尔曼滤波那块我印象最深——从论文里抄来矩阵公式,一行一行翻译成 NumPy,结果 P 矩阵跑到 1.32 直接炸了。调了半天发现是速度单位没转经纬度,除以 111000 就正常了。这种"公式是对的但工程实现有坑"的经历,比光听课印象深刻一百倍。
还有仪表盘上导航栏点不了的那个 bug,从改 CSS 到改 JS,来来回回搞了四五版。有一次差点把整个 HTML 删了重写,最后发现就一个语法错误导致所有 JS 没执行——修复之后那种"终于通了"的感觉太好了。
半学期很短,但 Python 带给我的不只是语法和库,更是一种"遇到问题别怕,先试试再说"的心态。
4.3 代码优缺点分析
优点:
- 模块化设计:15 个模块按功能分层(检测/融合/创新/控制),互不耦合,单独测试和替换都很方便
- 多层级检测:从信号层(SNR、DOP)到算法层(残差、LSTM、RF)再到系统层(EKF、WiFi),不同维度互补,单层被绕过还有后备
- 仿真+真实双模式:没硬件也能跑仿真演示,有 SR01 和 HackRF 直接切换,不依赖特定设备
- Web 可视化:仪表盘浏览器打开就能看,不需要装额外软件,演示效果直观
- 容错性好:大部分地方加了 try-except,WebSocket 断线自动重连,串口打开失败自动回退仿真
缺点与改进方向:
- 缺少真实数据验证:目前核心检测模块用的是仿真数据训练和测试,BiLSTM 虽然仿真准确率 100%,但真实环境效果未知
- 部分高级模块未实战:对抗攻防、联邦学习、GNN 这些做了仿真但还没接入实际数据流
- 依赖 Python 环境:部署需要先装一堆库,没有打包成 exe
- 仪表盘参考QT设计:五页面布局(监控/信号/卫星/轨迹/抗干扰),交互式SkyPlot悬停查看卫星详情,高德瓦片国内秒开
4.4 意见和建议
- 综合实践如果能在学期中就开始布置,边学边做,可能会比期末集中赶更从容一些
- 建议增加一些 Git 版本管理、虚拟环境配置、debug 调试技巧方面的实践内容,这些在实际写项目的时候特别实用
- Python 的很多第三方库更新很快,建议课上可以适当带着翻一翻官方文档,帮助养成查文档的习惯
- 实验课可以考虑增加一些开放式的项目题目,给定需求让学生自己设计实现方案,自由度大一点会更有意思
这次还有很多没做好的地方:真实 HackRF 信号数据还没采集到,几个高级模块也只做了仿真。后面大创项目继续完善,争取拿真实数据跑一遍验证。
五、参考资料
[1] GPS Interface Specification IS-GPS-200. Navstar GPS Space Segment/Navigation User Segment Interfaces, 2021.
[2] Tippenhauer N O, Popper C, Rasmussen K B, et al. On the Requirements for Successful GPS Spoofing Attacks[C]. ACM Conference on Computer and Communications Security (CCS), 2011: 75-86.
[3] Kalman R E. A New Approach to Linear Filtering and Prediction Problems[J]. Journal of Basic Engineering, 1960, 82(1): 35-45.
[4] Hochreiter S, Schmidhuber J. Long Short-Term Memory[J]. Neural Computation, 1997, 9(8): 1735-1780.
[5] PyTorch Documentation[EB/OL]. https://pytorch.org/docs/stable/
[6] scikit-learn Documentation[EB/OL]. https://scikit-learn.org/stable/
[7] Leaflet Documentation[EB/OL]. https://leafletjs.com/reference.html
[8] NumPy Documentation[EB/OL]. https://numpy.org/doc/stable/
[9] gps-sdr-sim GitHub Repository[EB/OL]. https://github.com/osqzss/gps-sdr-sim
附录
附录A:项目文件清单
| 文件 | 功能 |
|---|---|
sdr_monitor.py |
主入口程序,tkinter 控制面板 + 引擎启动 |
一键启动.bat |
双击启动,自动选择模式 |
sdr_defense/spoofing_detector.py |
残差检测 + 信号质量评分 |
sdr_defense/fusion_engine.py |
动态权重融合引擎 |
sdr_defense/kalman_fusion.py |
6状态 EKF 卡尔曼滤波 |
sdr_defense/lstm_detector.py |
BiLSTM 时序异常检测 |
sdr_defense/cnn_scene_classifier.py |
1D-CNN 场景分类 |
sdr_defense/rf_classifier.py |
随机森林分类器 |
sdr_defense/wifi_fingerprint.py |
WiFi 指纹定位 |
sdr_defense/adversarial_defense.py |
对抗样本攻防 |
sdr_defense/rf_fingerprint.py |
射频指纹认证 |
sdr_defense/federated_detection.py |
联邦学习检测 |
sdr_defense/gnn_topology.py |
GNN 卫星拓扑分析 |
sdr_defense/rl_battle.py |
强化学习攻防博弈 |
sdr_defense/hackrf_controller.py |
HackRF 发射控制 |
sdr_defense/nmea_bridge.py |
NMEA-0183 串口解析 |
dashboard.html |
Web 可视化仪表盘 |
附录B:运行命令
# 安装依赖
pip install numpy scipy scikit-learn torch pyserial websockets# 仿真模式(无需硬件)
python sdr_monitor.py --simulate# 浏览器打开仪表盘
# http://localhost:8766/dashboard.html# 真实串口模式(需SR01接收机)
python sdr_monitor.py --serial COM3
附录C:主要依赖库
numpy >= 1.21
scipy >= 1.7
scikit-learn >= 1.2
torch >= 1.13
matplotlib
pyserial
websockets




