diff --git a/architecture_diagrams.html b/architecture_diagrams.html deleted file mode 100644 index 4604f173..00000000 --- a/architecture_diagrams.html +++ /dev/null @@ -1,516 +0,0 @@ - - - - -智途投送系统 - 软件体系结构图 - - - - -

智途投送系统 — 软件体系结构图

-

按《软件体系结构》课程规范绘制 | 管道-过滤器 / 分层 / 客户端-服务器 / 发布-订阅

- - -
-
图1 系统整体体系结构 — 分层 + 客户端-服务器风格
- - - - - - - - - - - - - - 单兵终端APP(客户端) - Client-Server 架构 / 分层结构 - - - - 后勤保障系统(服务器端) - Layered 分层架构 / REST API - - - - 无人机软件系统 - Pipe-Filter + Pub-Sub 混合架构 - - - - 表示层 (Presentation) - UI界面 / 地图 / 交互控件 - - - 业务逻辑层 (Service) - 需求上报 / 位置同步 / 策略选择 - - - 数据访问层 (Data Access) - REST API调用 / 本地存储 - - - 硬件抽象层 (HAL) - GPS / 网络 / 摄像头 - - - - - - - - - 表示层 (Web前端) - HTML/CSS/JS / 地图可视化 - - - 应用层 (Flask API) - REST路由 / 任务调度 / 身份认证 - - - 业务逻辑层 (Services) - 路径规划 / 资源分配 / 威胁融合 - - - 数据层 (Data) - SQLite / 内存数据 / 日志 - - - - - - - - - ROS 节点层 (Pub-Sub) - 威胁发布 / 航点订阅 / 状态广播 - - - 感知流水线层 (Pipe-Filter) - 声学/视觉/热成像 → 威胁地图 - - - 算法核心层 (Core) - GCC-PHAT / CNN-GRU / SPL - - - 硬件接口层 (Drivers) - 麦克风 / 相机 / IMU / GPS - - - - - - - - - - HTTP/REST - - - ROS/WebSocket - - - - rosbridge / WebSocket(间接通信,经由后勤保障系统或直接) - -

- 设计说明:三大子系统各自内部采用分层架构,子系统间采用客户端-服务器风格交互。 - 上层(单兵APP、Web前端)通过 REST API 与后勤保障系统通信;后勤保障系统通过 ROS 网络与无人机交互。 - 分层架构的约束:每一层只使用直接下层提供的服务,层与层之间通过定义好的接口协议交互。 -

-
- - -
-
图2 声源分析模块 — 管道-过滤器体系结构(我负责部分)
- - - - - - - - - - - - - - 数据流:原始音频 → [缓冲 → 特征 → 分类 → 定位/测距 → 跟踪] → 威胁事件 - - - - - 数据源 - 麦克风阵列 - WAV文件 - - - - Filter 1 - AudioBuffer - 循环缓冲区 - 滑动窗口管理 - - - - Filter 2 - FeatureExtractor - Mel频谱图提取 - FFT + Mel滤波器组 - - - - Filter 3 - GunshotClassifier - CNN-GRU分类 - ONNX Runtime推理 - - - - Filter 4a - GccPhatLocalizer - GCC-PHAT定位 - 时延估计 → 方位角/俯仰角 - - - - Filter 4b - DistanceEstimator - SPL距离估计 - 声压级衰减 + Kalman滤波 - - - - Filter 5 - ThreatTracker - 威胁跟踪/去重 - 时域去重 + ID分配 - - - - 数据汇点 - AcousticThreat 事件 - - - - - float[] - - - - float[] - - - - MatrixXf - - - - label+conf - - - - label - - - - azimuth,elevation - - - - distance - - - - AcousticFrame - - - - VAD门控 - 能量+过零率检测 - - - - - 时序平滑 - 滑动窗口平均 - - - - - 过滤器组件 - (独立处理单元) - - - 数据源/汇点 - (系统边界) - - - 管道 (数据流) - -

- 管道-过滤器风格的四个核心特征在本模块的体现:
- ① 过滤器独立性:每个 Filter(如 FeatureExtractor、GunshotClassifier)都是独立的类,不与其他 Filter 共享状态;
- ② 数据流驱动:音频数据沿管道单向流动,无循环(符合「不允许出现环」的约束);
- ③ 局部变换:每个 Filter 只负责一种局部变换(时域→频域→概率→方位→距离);
- ④ 黑盒复用:GunshotClassifier 可独立替换为其他模型(如 Transformer),只要输入输出 Mel 频谱图格式不变。 -

-
- - -
-
图3 声源分析模块 — 分层体系结构(静态视角)
- - - - - - - - - - Layer 3:应用/集成层 (Application/Integration) - ROS 包装器 / 节点生命周期管理 / 话题发布订阅 - acoustic_node.cpp | threat_publisher.cpp - - - Layer 2:业务逻辑层 (Business Logic / Pipeline) - 流水线编排 (Pipeline) / 配置管理 / 数据类型定义 - pipeline.cpp | types.h | 配置解析 (YAML) - - - Layer 1:算法核心层 (Algorithm Core) - 音频缓冲 (AudioBuffer) | 特征提取 (FeatureExtractor) | 分类器 (GunshotClassifier) - 声源定位 (GccPhatLocalizer) | 距离估计 (DistanceEstimator) | 威胁跟踪 (ThreatTracker) - FFT工具 (fft_utils) | IO适配 (WavFileSource, MobilePhoneSource) - - - - - - - - 上层 → 下层:只允许向下依赖(依赖倒置原则) - core 层完全不依赖 ROS / yaml-cpp / 操作系统 - - - - Ubuntu (实机部署) - BUILD_ROS_WRAPPER=ON - ROS节点 + 麦克风阵列驱动 - - - Windows / Linux (仿真调试) - BUILD_ROS_WRAPPER=OFF - 离线WAV测试 + 单元测试 - - - - - 分层架构约束:① 每一层只使用直接下层的服务 ② 层间通过接口交互,不直接访问实现 ③ 下层修改不影响上层(只要接口不变) - - -

- 设计说明:通过分层隔离,算法核心层(Layer 1)完全与 ROS、操作系统解耦。 - 这意味着同一套 C++ 声学算法既可以在 Ubuntu 上作为 ROS 节点运行(控制真实无人机), - 也可以在 Windows 上编译为独立可执行文件做离线仿真测试,实现了"一次开发,多处部署"。 -

-
- - -
-
图4 无人机感知系统 — 发布-订阅(Pub-Sub)运行时交互
- - - - - - - - - - ROS Master - 节点注册 / 话题匹配 - - - - ROS Topic 总线(异步消息通道) - /microphone_array/audio | /acoustic_threat | /threat_map | /dynamic_waypoints - - - - Publisher - 麦克风阵列驱动节点 - 发布:/microphone_array/audio - 数据类型:Float32MultiArray - - - - Publisher(我负责) - 声学分析节点 (acoustic_node) - 订阅:/microphone_array/audio - 发布:/acoustic_threat - - - - Subscriber + Publisher - 多模态融合节点 - 订阅:/acoustic_threat + /vision_threat - 发布:/threat_map - - - - Subscriber - 动态路径规划节点 - 订阅:/threat_map - 发布:/dynamic_waypoints - - - - - - 音频数据流 - - - - - AcousticThreat 事件 - - - - - 融合后的 ThreatMap - - - - - 发布-订阅特征:① 发布者与订阅者完全解耦,互不知道对方存在 ② 支持一对多广播(一个威胁事件可被多个消费者处理) ③ 异步非阻塞,适合实时感知系统的低延迟要求 - - -

- 设计说明:发布-订阅风格使得声学分析节点无需关心"谁会使用威胁结果"。 - 在仿真阶段,可以订阅 /acoustic_threat 做可视化验证;在实机阶段,同一个话题被多模态融合节点订阅。 - 这种「隐式调用」机制大幅降低了系统各模块间的耦合度。 -

-
- - -
-
图5 PIMPL 惯用法 — 信息隐藏与编译隔离
- - - - - - - - - - 公开头文件 (Public API) - pipeline.h / feature_extractor.h - - - class Pipeline { - public: - Process(audio) - FromYaml(path) - Reset() - private: - Impl* impl_; - }; - - - - 实现文件 (Private Implementation) - pipeline.cpp - - - struct Pipeline::Impl { - AudioBuffer* - FeatureExtractor* - GunshotClassifier* - GccPhatLocalizer* - ... - }; - - - - 编译依赖 - (.cpp 包含所有头文件) - - - 无反向依赖(接口不感知实现细节) - - - - 编译防火墙 - - - - - 效果:修改 Impl 内部(如替换 FFT 库、新增滤波器)→ 无需重新编译依赖 pipeline.h 的其他模块 → 大幅缩短编译时间,降低模块耦合 - - -

- 设计说明:PIMPL(Pointer to Implementation)是 C++ 中实现「信息隐藏」的经典惯用法。 - 它将类的实现细节完全移入 .cpp 文件,头文件中只暴露接口指针。 - 这符合软件体系结构「接口与实现分离」的原则,也提升了系统的可修改性质量属性。 -

-
- -
- 智途投送系统 — 软件体系结构汇报用图 | 绘制规范参考《软件体系结构》课程 -
- - - diff --git a/fix_server.py b/fix_server.py deleted file mode 100644 index 427daa1b..00000000 --- a/fix_server.py +++ /dev/null @@ -1,132 +0,0 @@ -#!/usr/bin/env python3 -"""服务器端修复脚本:解决内存计数器重启归零导致的主键冲突""" -import os, sys - -APP_PATH = "/opt/zhitu/app.py" -if not os.path.exists(APP_PATH): - print(f"错误:找不到 {APP_PATH}") - sys.exit(1) - -# 备份 -bak = APP_PATH + ".bak." + str(int(os.time())) -os.system(f"cp {APP_PATH} {bak}") -print(f"已备份: {bak}") - -with open(APP_PATH, "r", encoding="utf-8") as f: - s = f.read() - -# 1. 删除内存计数器 -s = s.replace( - "_demand_id_counter = 0\n_task_id_counter = 0\n_danger_id_counter = 0", - "# 计数器已从内存变量改为数据库查询,避免服务重启后主键冲突" -) - -# 2. 添加辅助函数 -helper = '''def _next_demand_id(): - """从数据库查询当前最大需求ID,生成下一个(避免内存计数器重启归零导致主键冲突)""" - conn = get_db() - row = conn.execute("SELECT id FROM demands WHERE id LIKE 'REQ-%' ORDER BY id DESC LIMIT 1").fetchone() - conn.close() - if row: - try: - num = int(row["id"].replace("REQ-", "")) - except ValueError: - num = 0 - else: - num = 0 - return "REQ-" + str(num + 1).zfill(3) - - -def _next_task_id(): - """从数据库查询当前最大任务ID,生成下一个""" - conn = get_db() - row = conn.execute("SELECT id FROM tasks WHERE id LIKE '#%' ORDER BY id DESC LIMIT 1").fetchone() - conn.close() - if row: - try: - num = int(row["id"].replace("#", "")) - except ValueError: - num = 0 - else: - num = 0 - return "#" + str(num + 1).zfill(3) - -''' - -marker = "# ===== REST API: 物资需求(单兵APP) =====" -if marker in s and "_next_demand_id" not in s: - s = s.replace(marker, helper + marker) - -# 3. 修改 post_demand -s = s.replace( - " global _demand_id_counter\n data = request.get_json(force=True)\n _demand_id_counter += 1", - " data = request.get_json(force=True)" -) -s = s.replace( - ' demand_id = "REQ-" + str(_demand_id_counter).zfill(3)', - ' demand_id = _next_demand_id()' -) - -# 4. 修改 add_danger_zone -s = s.replace( - ''' global _danger_id_counter - data = request.get_json(force=True) - _danger_id_counter += 1 - zone = { - "id": _danger_id_counter,''', - ''' data = request.get_json(force=True) - zone = {''' -) -s = s.replace( - ''' conn.execute(''' - INSERT INTO danger_zones (lat, lng, radius, description, created_at) - VALUES (?, ?, ?, ?, ?) - ''', (zone["lat"], zone["lng"], zone["radius"], zone["description"], zone["created_at"])) - conn.commit() - conn.close() - return jsonify({"ok": True, "id": zone["id"]})''', - ''' cur = conn.execute(''' - INSERT INTO danger_zones (lat, lng, radius, description, created_at) - VALUES (?, ?, ?, ?, ?) - ''', (zone["lat"], zone["lng"], zone["radius"], zone["description"], zone["created_at"])) - zone_id = cur.lastrowid - conn.commit() - conn.close() - return jsonify({"ok": True, "id": zone_id})''' -) - -# 5. 修改 dispatch_task -s = s.replace( - ''' global _task_id_counter - data = request.get_json(force=True) - soldier_id = data.get("soldier_id", "unknown") - _task_id_counter += 1''', - ''' data = request.get_json(force=True) - soldier_id = data.get("soldier_id", "unknown")''' -) -s = s.replace( - ''' "id": "#" + str(_task_id_counter).zfill(3),''', - ''' "id": _next_task_id(),''' -) - -# 6. 修改 sos -s = s.replace( - ''' # 同时标记为危险区域 - global _danger_id_counter - _danger_id_counter += 1 - conn.execute('''', - ''' # 同时标记为危险区域 - conn.execute('''' -) - -with open(APP_PATH, "w", encoding="utf-8") as f: - f.write(s) - -# 语法检查 -result = os.system(f"python3 -m py_compile {APP_PATH}") -if result == 0: - print("✅ 修复完成,语法检查通过") -else: - print("❌ 语法检查失败,已恢复备份") - os.system(f"cp {bak} {APP_PATH}") - sys.exit(1) diff --git a/generate_blog_doc.js b/generate_blog_doc.js deleted file mode 100644 index 9449c9cd..00000000 --- a/generate_blog_doc.js +++ /dev/null @@ -1,287 +0,0 @@ -const { Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell, - HeadingLevel, AlignmentType, BorderStyle, WidthType, ShadingType, - PageBreak, Header, Footer, PageNumber } = require('docx'); -const fs = require('fs'); - -const border = { style: BorderStyle.SINGLE, size: 1, color: "CCCCCC" }; -const borders = { top: border, bottom: border, left: border, right: border }; - -function cell(text, width, opts = {}) { - return new TableCell({ - borders, - width: { size: width, type: WidthType.DXA }, - shading: opts.shading ? { fill: opts.shading, type: ShadingType.CLEAR } : undefined, - margins: { top: 60, bottom: 60, left: 100, right: 100 }, - children: [new Paragraph({ - children: [new TextRun({ text, bold: opts.bold, size: 20, font: "微软雅黑" })] - })] - }); -} - -function h1(text) { - return new Paragraph({ - heading: HeadingLevel.HEADING_1, - children: [new TextRun({ text, bold: true, size: 32, font: "微软雅黑", color: "1a1a2e" })] - }); -} - -function h2(text) { - return new Paragraph({ - heading: HeadingLevel.HEADING_2, - children: [new TextRun({ text, bold: true, size: 28, font: "微软雅黑", color: "2d3436" })] - }); -} - -function h3(text) { - return new Paragraph({ - heading: HeadingLevel.HEADING_3, - children: [new TextRun({ text, bold: true, size: 24, font: "微软雅黑", color: "2d3436" })] - }); -} - -function body(text, opts = {}) { - return new Paragraph({ - children: [new TextRun({ text, size: 21, font: "微软雅黑", ...opts })], - spacing: { after: 120, line: 360 } - }); -} - -function quote(text) { - return new Paragraph({ - children: [new TextRun({ text, italics: true, size: 21, font: "微软雅黑", color: "636e72" })], - spacing: { after: 120, line: 360 }, - indent: { left: 400 } - }); -} - -function code(text) { - return new Paragraph({ - children: [new TextRun({ text, size: 18, font: "Consolas", color: "2d3436" })], - shading: { fill: "f5f6fa", type: ShadingType.CLEAR }, - spacing: { after: 60 } - }); -} - -const doc = new Document({ - styles: { - default: { document: { run: { font: "微软雅黑", size: 21 } } }, - paragraphStyles: [ - { id: "Heading1", name: "Heading 1", basedOn: "Normal", next: "Normal", quickFormat: true, - run: { size: 32, bold: true, font: "微软雅黑", color: "1a1a2e" }, - paragraph: { spacing: { before: 300, after: 200 }, outlineLevel: 0 } }, - { id: "Heading2", name: "Heading 2", basedOn: "Normal", next: "Normal", quickFormat: true, - run: { size: 28, bold: true, font: "微软雅黑", color: "2d3436" }, - paragraph: { spacing: { before: 240, after: 160 }, outlineLevel: 1 } }, - { id: "Heading3", name: "Heading 3", basedOn: "Normal", next: "Normal", quickFormat: true, - run: { size: 24, bold: true, font: "微软雅黑", color: "2d3436" }, - paragraph: { spacing: { before: 200, after: 120 }, outlineLevel: 2 } }, - ] - }, - sections: [{ - properties: { - page: { size: { width: 11906, height: 16838 }, margin: { top: 1440, right: 1440, bottom: 1440, left: 1440 } } - }, - headers: { - default: new Header({ children: [new Paragraph({ - children: [new TextRun({ text: "知识荟 · 技术博客", size: 16, color: "888888", font: "微软雅黑" })] - })] }) - }, - footers: { - default: new Footer({ children: [new Paragraph({ - alignment: AlignmentType.CENTER, - children: [new TextRun({ children: ["第 ", PageNumber.CURRENT, " 页"], size: 16, color: "888888", font: "微软雅黑" })] - })] }) - }, - children: [ - // 标题 - new Paragraph({ spacing: { before: 600 } }), - new Paragraph({ - alignment: AlignmentType.CENTER, - children: [new TextRun({ text: "基于 C++ 的无人机声源分析模块设计与实现", bold: true, size: 40, font: "微软雅黑", color: "1a1a2e" })] - }), - new Paragraph({ - alignment: AlignmentType.CENTER, - children: [new TextRun({ text: "——「智途投送」战场末端补给系统的多模态感知实践", size: 26, font: "微软雅黑", color: "636e72" })], - spacing: { after: 400 } - }), - new Paragraph({ - alignment: AlignmentType.CENTER, - children: [new TextRun({ text: "作者:国防科大计算机学院 23 级软件工程小班", size: 21, font: "微软雅黑", color: "636e72" })] - }), - new Paragraph({ - alignment: AlignmentType.CENTER, - children: [new TextRun({ text: "2026 年 4 月", size: 21, font: "微软雅黑", color: "636e72" })], - spacing: { after: 600 } - }), - - // 摘要 - h1("摘要"), - body("在城市作战环境下,战场末端补给的「最后一公里」始终是制约作战效能的关键瓶颈。本文介绍「智途投送」软件系统中声源分析模块(Acoustic Analyzer)的设计与实现过程。该模块通过麦克风阵列采集音频信号,结合 GCC-PHAT 声源定位算法与 ONNX Runtime 神经网络推理引擎,实现了枪炮声的实时识别、方位估计与距离推算。模块采用 C++17 开发,遵循构件化设计原则,核心算法零 ROS 依赖,支持临时方案(手机单通道)与最终方案(麦克风阵列)的无缝切换。本文详细阐述了系统架构、核心算法、工程实践中的关键决策及踩坑记录,为同类嵌入式感知系统开发提供参考。"), - new Paragraph({ spacing: { before: 100 } }), - body("关键词:无人机;声源定位;GCC-PHAT;ONNX Runtime;构件化设计;战场感知", { bold: true }), - - // 一、项目背景 - h1("一、项目背景与需求分析"), - h2("1.1 战场末端补给的痛点"), - body("近年来多场局部战争的实战经验反复证明,后勤补给的「最后一公里」已成为制约战场持续作战能力的核心瓶颈。2023 年以哈战争中,以军在加沙城市巷战环境遭遇严重后勤困境;2022 年俄乌冲突中,前线部队长期面临弹药、食品、急救药品严重短缺。传统有人运输在最后几公里内频繁遭遇炮火覆盖,伤亡率极高。即便引入无人机等无人平台,也因缺乏统一调度、智能路径规划和安全投放策略,末端配送效率低下、协调困难。"), - body("针对这一现实挑战,我们团队设计开发了「智途投送」智能化末端补给系统,通过无人机替代有人运输,结合多模态感知与智能路径规划,实现战场物资的安全精准投送。"), - - h2("1.2 声源分析模块的定位"), - body("在「智途投送」系统的多模态感知架构中,声源分析模块与视觉分析模块、热成像分析模块并列,共同构成威胁感知层。其具体功能需求包括:"), - body("• 枪炮声识别:区分枪声、炮声、爆炸声与环境噪声"), - body("• 声源定位:通过麦克风阵列估计威胁源的方位角与俯仰角"), - body("• 距离估计:基于信号能量衰减模型推算威胁距离"), - body("• 威胁跟踪:对连续帧检测结果进行关联与生命周期管理"), - body("• 构件化设计:核心算法与 ROS 解耦,支持独立编译与测试"), - - // 二、系统架构 - h1("二、系统架构设计"), - h2("2.1 总体架构"), - body("模块采用三层架构设计,严格遵循「关注点分离」原则:"), - new Paragraph({ spacing: { before: 200 } }), - code("┌──────────────────────────────────────────┐"), - code("│ ROS 封装层(acoustic_node) │"), - code("│ - 话题订阅:/microphone_array/audio │"), - code("│ - 话题发布:/acoustic/threats │"), - code("├──────────────────────────────────────────┤"), - code("│ IO 抽象层(AudioSource 接口) │"), - code("│ - WavFileSource (离线测试) │"), - code("│ - MobilePhoneSource (临时方案)[TEMP] │"), - code("│ - MicArraySource (最终方案)[FINAL] │"), - code("├──────────────────────────────────────────┤"), - code("│ Core 算法层(零 ROS 依赖) │"), - code("│ Pipeline → {FeatureExtractor, │"), - code("│ GunshotClassifier, │"), - code("│ GccPhatLocalizer, │"), - code("│ DistanceEstimator, │"), - code("│ ThreatTracker} │"), - code("└──────────────────────────────────────────┘"), - new Paragraph({ spacing: { before: 200 } }), - - h2("2.2 构件化设计的工程意义"), - body("将 Core 层设计为纯 C++ 库(零 ROS 依赖)带来了显著的工程优势:"), - body("1. 可测试性:可在无 ROS 环境中运行单元测试,CI/CD 友好"), - body("2. 可移植性:未来迁移至 ROS2 时,仅需重写 ROS 层,Core 与 IO 层零改动"), - body("3. 可复用性:Core 库可独立部署于地面站笔记本,用于离线数据分析"), - body("4. 可分离性:满足课程项目对「构件化」的要求,模块边界清晰"), - - // 三、核心算法 - h1("三、核心算法详解"), - h2("3.1 Mel Spectrogram 特征提取"), - body("由于项目采用 C++ 开发,无法直接使用 Python 生态的 librosa 库。我们在 C++ 端从零实现了完整的 Mel Spectrogram 提取流程:"), - body("预加重 → 分帧加窗(Hamming)→ FFT(Kiss FFT)→ 功率谱 → Mel 滤波器组 → 对数压缩"), - body("实现中特别注意了与 Python librosa 的参数对齐:"), - new Table({ - width: { size: 9360, type: WidthType.DXA }, - columnWidths: [3000, 3000, 3360], - rows: [ - new TableRow({ children: [ - cell("参数", 3000, { bold: true, shading: "f0f2f5" }), - cell("C++ 值", 3000, { bold: true, shading: "f0f2f5" }), - cell("librosa 对应", 3360, { bold: true, shading: "f0f2f5" }) - ] }), - new TableRow({ children: [cell("sample_rate", 3000), cell("16000", 3000), cell("sr=16000", 3360)] }), - new TableRow({ children: [cell("n_fft", 3000), cell("2048", 3000), cell("n_fft=2048", 3360)] }), - new TableRow({ children: [cell("hop_length", 3000), cell("512", 3000), cell("hop_length=512", 3360)] }), - new TableRow({ children: [cell("n_mels", 3000), cell("64", 3000), cell("n_mels=64", 3360)] }), - new TableRow({ children: [cell("f_max", 3000), cell("8000.0", 3000), cell("fmax=8000", 3360)] }), - new TableRow({ children: [cell("preemphasis", 3000), cell("0.97", 3000), cell("coef=0.97", 3360)] }), - new TableRow({ children: [cell("window", 3000), cell("Hamming", 3000), cell("window='hamming'", 3360)] }), - new TableRow({ children: [cell("center", 3000), cell("false", 3000), cell("center=False", 3360)] }), - ] - }), - new Paragraph({ spacing: { before: 200 } }), - body("其中 center=false 是关键对齐点。librosa 默认 center=true(帧中心对齐),会导致帧数比 C++ 实现多 1-2 帧。我们在训练脚本中显式设置 center=False,并在 C++ 端使用 (n_samples - n_fft) / hop + 1 的帧数计算,确保训练-推理特征完全一致。"), - - h2("3.2 GCC-PHAT 声源定位"), - body("GCC-PHAT(Generalized Cross-Correlation with Phase Transform)是一种经典的时延估计(TDOA)算法。其核心思想是通过相位变换加权消除信号幅度的影响,仅保留相位信息用于互相关计算:"), - quote("R_ij(τ) = IFFT{ X_i(f) · X_j*(f) / |X_i(f) · X_j*(f)| }"), - body("我们在实现中做了以下工程优化:"), - body("• 抛物线插值:在 GCC-PHAT 峰值附近进行抛物线拟合,将时延分辨率从采样点级提升至亚采样级"), - body("• 最小二乘方向解算:利用多对麦克风的 TDOA 构建超定方程组,通过 SVD 求解声源方向向量"), - body("• 阵列几何自适应:支持十字、线性、圆形及自定义阵列布局,通过配置文件热切换"), - - h2("3.3 枪炮声分类模型"), - body("分类器采用轻量级 CNN-GRU 网络结构:"), - code("输入 (1, 64, T) → Conv1D(64→128→256) → MaxPool → GRU(128, bidirectional)"), - code(" → GlobalAvgPool → Dense(64) → Dropout(0.3) → Dense(4) → Softmax"), - new Paragraph({ spacing: { before: 200 } }), - body("模型推理使用 ONNX Runtime C++ API,相比 LibTorch 轻量一个数量级,推理延迟约 10-50ms,满足实时性要求。模型从 PyTorch 训练后导出为 ONNX 格式,支持动态 batch 和动态时间轴。"), - - h2("3.4 距离估计与威胁跟踪"), - body("距离估计采用能量衰减模型:"), - quote("d = d₀ · 10^((L₀ - L_measured) / (20·α))"), - body("其中 L₀ 根据分类结果动态选择(枪声 150dB、炮声 180dB、爆炸 170dB),α 为城市环境衰减系数(默认 0.6)。为降低单帧估计噪声,引入一维卡尔曼滤波进行时序平滑。"), - body("威胁跟踪采用最近邻数据关联算法:连续帧中方位角差 < 15° 且类型一致则判定为同一威胁,分配唯一 ID 并持续跟踪,连续 5 帧未检测到则淘汰。"), - - // 四、工程实践 - h1("四、工程实践与关键决策"), - h2("4.1 临时方案与最终方案的分离设计"), - body("项目初期面临一个现实问题:麦克风阵列硬件尚未到位,但需要提前验证算法通路和系统集成。我们设计了一套「source_type」配置切换机制:"), - body("• mobile_phone:手机通过 WiFi/UDP 发送单通道音频,仅做分类检测,定位模块自动跳过"), - body("• mic_array:4 通道阵列,完整分类+定位+距离估计"), - body("• wav_file:离线 WAV 回放,用于算法调试"), - body("这种设计使得团队可以在无硬件条件下并行推进软件开发,硬件到位后仅需修改一行配置即可切换至最终方案。"), - - h2("4.2 踩坑记录"), - h3("坑 1:librosa center 参数导致的训练-推理不一致"), - body("初期发现 C++ 端 Mel Spectrogram 与 Python 端存在系统性偏差,排查后发现是 librosa 默认 center=true 导致的帧数差异。修复方案:训练时显式设置 center=False,并在 C++ 端严格对齐分帧逻辑。"), - h3("坑 2:ONNX 导出动态轴与 torch 2.x 的兼容性"), - body("torch 2.11 默认使用 dynamo 导出器,对 GRU 层的动态轴支持存在问题。修复方案:使用传统 TorchScript 导出器(dynamo=False),并将 opset 提升至 13。"), - h3("坑 3:数据增强导致时间维度变化"), - body("训练脚本中的时间拉伸增强改变了 Mel Spectrogram 的时间帧数,导致 batch 拼接失败。修复方案:增强后统一插值对齐到目标帧数(63 帧)。"), - - // 五、实验验证 - h1("五、实验验证"), - h2("5.1 合成数据训练验证"), - body("在硬件到位前,我们使用合成数据集验证了完整的训练-导出-部署流程:"), - new Table({ - width: { size: 9360, type: WidthType.DXA }, - columnWidths: [4000, 5360], - rows: [ - new TableRow({ children: [ - cell("指标", 4000, { bold: true, shading: "f0f2f5" }), - cell("结果", 5360, { bold: true, shading: "f0f2f5" }) - ] }), - new TableRow({ children: [cell("数据集", 4000), cell("200 合成样本 + 10 份模拟无人机噪声", 5360)] }), - new TableRow({ children: [cell("训练 epoch", 4000), cell("30", 5360)] }), - new TableRow({ children: [cell("验证准确率", 4000), cell("100%(合成数据,过拟合预期)", 5360)] }), - new TableRow({ children: [cell("ONNX 模型大小", 4000), cell("1.9 MB", 5360)] }), - new TableRow({ children: [cell("ONNX 推理验证", 4000), cell("枪声识别置信度 97.92%", 5360)] }), - new TableRow({ children: [cell("C++ 编译", 4000), cell("g++ 15.2 + CMake 4.1 通过", 5360)] }), - ] - }), - new Paragraph({ spacing: { before: 200 } }), - body("需要强调的是,合成数据上的高准确率不代表真实场景性能。当前模型仅用于验证代码通路,后续需用真实数据集(MIVIA、FSD50K 等)重新训练。"), - - h2("5.2 特征一致性验证"), - body("我们编写了纯 NumPy 参考实现与 C++ FeatureExtractor 进行比对验证。在相同 WAV 输入下,两者 Mel Spectrogram 的逐元素最大误差 < 1e-4,验证了 C++ 端特征提取的正确性。"), - - // 六、总结与展望 - h1("六、总结与展望"), - h2("6.1 已完成工作"), - body("• 完成了声源分析模块的全部 C++ 代码开发(34 个文件)"), - body("• 实现了 Mel Spectrogram、GCC-PHAT、ONNX 推理、距离估计、威胁跟踪五大核心算法"), - body("• 设计了临时/最终方案分离机制,支持无硬件条件下的软件开发"), - body("• 在 Windows 上完成了 Python 训练环境搭建、模型训练、ONNX 导出与验证"), - h2("6.2 后续计划"), - body("• 下载真实数据集(MIVIA、FSD50K、UrbanSound8K)替换合成数据"), - body("• 录制无人机自噪声作为 ambient 负样本,解决旋翼噪声误报问题"), - body("• 在 Ubuntu + ROS Noetic 环境下编译 C++ 代码,完成特征一致性端到端验证"), - body("• 麦克风阵列硬件到位后,实现 ALSA 驱动并完成实机联调"), - body("• 考虑模型量化(INT8)以进一步降低 Jetson 平台的推理延迟"), - - // 参考文献 - h1("参考文献"), - body("[1] Knapp C H, Carter G C. The generalized correlation method for estimation of time delay[J]. IEEE Trans. on ASSP, 1976."), - body("[2] Microsoft. ONNX Runtime documentation[EB/OL]. https://onnxruntime.ai/docs/"), - body("[3] McFee B, et al. librosa: Audio and Music Signal Analysis in Python[C]. SciPy, 2015."), - body("[4] 智途投送软件开发方案(内部文档),国防科大计算机学院,2026."), - ] - }] -}); - -Packer.toBuffer(doc).then(buffer => { - fs.writeFileSync("基于C++的无人机声源分析模块设计与实现_技术博客.docx", buffer); - console.log("技术博客已生成:基于C++的无人机声源分析模块设计与实现_技术博客.docx"); -}); diff --git a/generate_handover_doc.js b/generate_handover_doc.js deleted file mode 100644 index f487b8c6..00000000 --- a/generate_handover_doc.js +++ /dev/null @@ -1,291 +0,0 @@ -const { Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell, - HeadingLevel, AlignmentType, BorderStyle, WidthType, ShadingType, - PageBreak, Header, Footer, PageNumber } = require('docx'); -const fs = require('fs'); - -const border = { style: BorderStyle.SINGLE, size: 1, color: "CCCCCC" }; -const borders = { top: border, bottom: border, left: border, right: border }; - -function cell(text, width, opts = {}) { - return new TableCell({ - borders, - width: { size: width, type: WidthType.DXA }, - shading: opts.shading ? { fill: opts.shading, type: ShadingType.CLEAR } : undefined, - margins: { top: 60, bottom: 60, left: 100, right: 100 }, - children: [new Paragraph({ - children: [new TextRun({ text, bold: opts.bold, size: 20, font: "微软雅黑" })] - })] - }); -} - -function h1(text) { - return new Paragraph({ - heading: HeadingLevel.HEADING_1, - children: [new TextRun({ text, bold: true, size: 32, font: "微软雅黑", color: "1a1a2e" })] - }); -} - -function h2(text) { - return new Paragraph({ - heading: HeadingLevel.HEADING_2, - children: [new TextRun({ text, bold: true, size: 28, font: "微软雅黑", color: "2d3436" })] - }); -} - -function body(text, opts = {}) { - return new Paragraph({ - children: [new TextRun({ text, size: 21, font: "微软雅黑", ...opts })], - spacing: { after: 120, line: 360 } - }); -} - -function code(text) { - return new Paragraph({ - children: [new TextRun({ text, size: 18, font: "Consolas", color: "2d3436" })], - shading: { fill: "f5f6fa", type: ShadingType.CLEAR }, - spacing: { after: 80 } - }); -} - -const doc = new Document({ - styles: { - default: { document: { run: { font: "微软雅黑", size: 21 } } }, - paragraphStyles: [ - { id: "Heading1", name: "Heading 1", basedOn: "Normal", next: "Normal", quickFormat: true, - run: { size: 32, bold: true, font: "微软雅黑", color: "1a1a2e" }, - paragraph: { spacing: { before: 300, after: 200 }, outlineLevel: 0 } }, - { id: "Heading2", name: "Heading 2", basedOn: "Normal", next: "Normal", quickFormat: true, - run: { size: 28, bold: true, font: "微软雅黑", color: "2d3436" }, - paragraph: { spacing: { before: 240, after: 160 }, outlineLevel: 1 } }, - ] - }, - sections: [{ - properties: { - page: { size: { width: 11906, height: 16838 }, margin: { top: 1440, right: 1440, bottom: 1440, left: 1440 } } - }, - headers: { - default: new Header({ children: [new Paragraph({ - children: [new TextRun({ text: "智途投送 · 声源分析模块 · 项目交接文档", size: 16, color: "888888", font: "微软雅黑" })] - })] }) - }, - footers: { - default: new Footer({ children: [new Paragraph({ - alignment: AlignmentType.CENTER, - children: [new TextRun({ children: ["第 ", PageNumber.CURRENT, " 页"], size: 16, color: "888888", font: "微软雅黑" })] - })] }) - }, - children: [ - // 封面 - new Paragraph({ spacing: { before: 2000 } }), - new Paragraph({ - alignment: AlignmentType.CENTER, - children: [new TextRun({ text: "智途投送", bold: true, size: 56, font: "微软雅黑", color: "1a1a2e" })] - }), - new Paragraph({ - alignment: AlignmentType.CENTER, - children: [new TextRun({ text: "声源分析模块(Acoustic Analyzer)", bold: true, size: 36, font: "微软雅黑", color: "2d3436" })], - spacing: { after: 400 } - }), - new Paragraph({ - alignment: AlignmentType.CENTER, - children: [new TextRun({ text: "项目开发交接文档", size: 32, font: "微软雅黑", color: "636e72" })] - }), - new Paragraph({ spacing: { before: 800 } }), - new Paragraph({ - alignment: AlignmentType.CENTER, - children: [new TextRun({ text: "国防科大计算机学院 23 级软件工程小班", size: 24, font: "微软雅黑", color: "636e72" })] - }), - new Paragraph({ - alignment: AlignmentType.CENTER, - children: [new TextRun({ text: "2026 年 4 月", size: 24, font: "微软雅黑", color: "636e72" })] - }), - new Paragraph({ children: [new PageBreak()] }), - - // 一、项目概述 - h1("一、项目概述"), - body("声源分析模块是「智途投送」无人机软件系统的核心感知构件之一,负责通过麦克风阵列音频信号实现:"), - body("• 枪炮声识别分类(枪声 / 炮声 / 爆炸声 / 环境噪声)"), - body("• GCC-PHAT 声源定位(方位角、俯仰角)"), - body("• 基于能量衰减模型的距离估计"), - body("• 多帧威胁跟踪与信息融合"), - body("模块采用 C++17 开发,核心算法零 ROS 依赖,通过 ONNX Runtime 进行神经网络推理,最终作为 ROS1 Noetic 节点部署于 P600 无人机机载电脑。"), - - // 二、已完成工作总览 - h1("二、已完成工作总览"), - h2("2.1 代码开发"), - body("已完成全部 34 个代码文件的编写,覆盖 Core 算法层、IO 抽象层、ROS 封装层及配套脚本:"), - - new Table({ - width: { size: 9360, type: WidthType.DXA }, - columnWidths: [2400, 5000, 1960], - rows: [ - new TableRow({ children: [ - cell("层级", 2400, { bold: true, shading: "1a1a2e" }), - cell("文件", 5000, { bold: true, shading: "1a1a2e" }), - cell("状态", 1960, { bold: true, shading: "1a1a2e" }) - ] }), - new TableRow({ children: [cell("Core 层", 2400), cell("fft_utils.h/cpp, audio_buffer.h/cpp, feature_extractor.h/cpp", 5000), cell("✅ 完成", 1960)] }), - new TableRow({ children: [cell("Core 层", 2400), cell("gunshot_classifier.h/cpp, gcc_phat_localizer.h/cpp", 5000), cell("✅ 完成", 1960)] }), - new TableRow({ children: [cell("Core 层", 2400), cell("distance_estimator.h/cpp, threat_tracker.h/cpp, pipeline.h/cpp", 5000), cell("✅ 完成", 1960)] }), - new TableRow({ children: [cell("IO 层", 2400), cell("audio_source.h, wav_file_source.h/cpp, mobile_phone_source.h/cpp", 5000), cell("✅ 完成", 1960)] }), - new TableRow({ children: [cell("ROS 层", 2400), cell("acoustic_node.h/cpp, threat_publisher.h/cpp, main.cpp", 5000), cell("✅ 完成", 1960)] }), - new TableRow({ children: [cell("消息定义", 2400), cell("AcousticThreat.msg, AcousticThreatArray.msg", 5000), cell("✅ 完成", 1960)] }), - new TableRow({ children: [cell("构建系统", 2400), cell("CMakeLists.txt, package.xml", 5000), cell("✅ 完成", 1960)] }), - new TableRow({ children: [cell("Python 脚本", 2400), cell("train_classifier.py, export_onnx.py, verify_onnx.py", 5000), cell("✅ 完成", 1960)] }), - new TableRow({ children: [cell("Python 脚本", 2400), cell("generate_sim_audio.py, mobile_audio_bridge.py, android_audio_sender.py", 5000), cell("✅ 完成", 1960)] }), - new TableRow({ children: [cell("测试", 2400), cell("test_core_lib.cpp, extract_mel_cpp.cpp, test_classifier_cpp.cpp", 5000), cell("✅ 完成", 1960)] }), - new TableRow({ children: [cell("构建脚本", 2400), cell("build_core_test.bat, build_cmake_mingw.bat", 5000), cell("✅ 完成", 1960)] }), - ] - }), - new Paragraph({ spacing: { before: 200 } }), - - h2("2.2 模型训练与 ONNX 导出"), - body("在 Windows 环境下使用合成数据集完成了端到端训练验证:"), - body("• 数据集:200 个合成样本(每类 50 个)+ 10 份模拟无人机噪声"), - body("• 训练:30 epoch,CNN-GRU 网络,验证准确率 100%(合成数据过拟合属预期现象)"), - body("• ONNX 导出:gunshot_classifier.onnx(1.9MB,opset 13)"), - body("• ONNX 验证:枪声识别置信度 97.92%"), - - h2("2.3 临时方案与最终方案分离"), - body("已实现 source_type 配置切换机制:"), - body("• mobile_phone:手机单通道麦克风通过 UDP → ROS 话题传输,仅做分类"), - body("• mic_array:4 通道麦克风阵列(最终方案),完整分类+定位+距离估计"), - body("• wav_file:离线 WAV 文件回放,用于测试验证"), - - h2("2.4 C++ 编译环境搭建与测试跑通"), - body("已在 Windows + MinGW 环境下完成 C++ 编译链路打通:"), - body("• Eigen3:使用 bundled 版本 third_party/eigen-3.4.0,无需安装"), - body("• yaml-cpp:自动检测 conda 环境(C:/Users//miniconda3/Library),CMake 已适配"), - body("• ONNX Runtime C++ v1.20.1:通过 Python 包提取 DLL + GitHub raw 下载头文件 + gendef/dlltool 生成 MinGW 导入库"), - body("• 全部测试通过:test_core_lib(7项)、extract_mel_cpp、test_classifier_cpp(ONNX 推理 OK)"), - body("• 已知限制:项目路径含中文时,CMake + Ninja/MinGW Makefiles 无法直接工作,需通过 build_cmake_mingw.bat 自动复制到临时英文目录构建"), - - h2("2.5 代码 Bug 修复记录"), - body("搭建过程中发现并修复的问题:"), - body("• gcc_phat_localizer.cpp:缺少 #include ,导致 BDCSVD 不完整类型错误"), - body("• threat_tracker.cpp:数据关联更新检测时丢失原有 threat_id,导致多帧跟踪失败"), - body("• test_core_lib.cpp:audio_buffer_wraparound 测试期望值错误(5 应为 6);gcc_phat_cross_array 对简化信号断言过严"), - body("• gunshot_classifier.cpp/h:升级至 ONNX Runtime C++ v1.20.1 RAII API,适配 wchar_t 路径(Windows)"), - body("• CMakeLists.txt:添加 MinGW 适配(-D_USE_MATH_DEFINES、-Wa,-mbig-obj、_stdcall 覆盖、yaml-cpp 自动检测)"), - - // 三、架构设计 - h1("三、架构设计"), - body("模块采用三层构件化架构,核心算法层完全独立于 ROS,确保可分离、可测试、可移植:"), - new Paragraph({ spacing: { before: 200 } }), - code("┌─────────────────────────────────────────┐"), - code("│ ROS 层(acoustic_node / threat_publisher)│ ← 话题订阅/发布"), - code("├─────────────────────────────────────────┤"), - code("│ IO 层(WavFileSource / MobilePhoneSource)│ ← 音频源抽象"), - code("├─────────────────────────────────────────┤"), - code("│ Core 层(Pipeline 编排以下模块) │ ← 零 ROS 依赖"), - code("│ • FeatureExtractor (Mel Spectrogram) │"), - code("│ • GunshotClassifier (ONNX Runtime) │"), - code("│ • GccPhatLocalizer (GCC-PHAT + TDOA) │"), - code("│ • DistanceEstimator (能量衰减 + 卡尔曼) │"), - code("│ • ThreatTracker (多帧关联跟踪) │"), - code("└─────────────────────────────────────────┘"), - new Paragraph({ spacing: { before: 200 } }), - - // 四、当前环境与依赖 - h1("四、当前环境与依赖"), - h2("4.1 Python 训练环境(Windows 已验证)"), - new Table({ - width: { size: 9360, type: WidthType.DXA }, - columnWidths: [3000, 3000, 3360], - rows: [ - new TableRow({ children: [ - cell("包名", 3000, { bold: true, shading: "f0f2f5" }), - cell("版本", 3000, { bold: true, shading: "f0f2f5" }), - cell("用途", 3360, { bold: true, shading: "f0f2f5" }) - ] }), - new TableRow({ children: [cell("Python", 3000), cell("3.14.3", 3000), cell("训练与脚本运行", 3360)] }), - new TableRow({ children: [cell("torch", 3000), cell("2.11.0+cpu", 3000), cell("模型定义与训练", 3360)] }), - new TableRow({ children: [cell("librosa", 3000), cell("0.11.0", 3000), cell("Mel Spectrogram 提取", 3360)] }), - new TableRow({ children: [cell("onnx", 3000), cell("1.21.0", 3000), cell("ONNX 模型验证", 3360)] }), - new TableRow({ children: [cell("numpy", 3000), cell("2.4.4", 3000), cell("数值计算", 3360)] }), - new TableRow({ children: [cell("scipy", 3000), cell("1.17.1", 3000), cell("信号处理", 3360)] }), - ] - }), - new Paragraph({ spacing: { before: 200 } }), - - h2("4.2 C++ 编译环境(Windows 已配置)"), - body("• 编译器:g++ (MinGW-W64 15.2.0) 已安装 ✅"), - body("• CMake:4.1.0 已安装 ✅"), - body("• Eigen3:bundled third_party/eigen-3.4.0 ✅"), - body("• ONNX Runtime C++:v1.20.1 已配置(头文件 + DLL + MinGW 导入库)✅"), - body("• yaml-cpp:conda 0.8.0 已检测,CMake 自动链接 ✅"), - body("• 构建方式:"), - body(" – 快速命令行:build_core_test.bat(一键编译全部测试)"), - body(" – 标准 CMake:build_cmake_mingw.bat(自动处理中文路径问题)"), - - // 五、待办事项 - h1("五、待办事项与下一步计划"), - new Table({ - width: { size: 9360, type: WidthType.DXA }, - columnWidths: [600, 4200, 2160, 2400], - rows: [ - new TableRow({ children: [ - cell("优先级", 600, { bold: true, shading: "f0f2f5" }), - cell("任务", 4200, { bold: true, shading: "f0f2f5" }), - cell("负责人", 2160, { bold: true, shading: "f0f2f5" }), - cell("状态", 2400, { bold: true, shading: "f0f2f5" }) - ] }), - new TableRow({ children: [cell("P0", 600), cell("下载真实数据集(MIVIA / FSD50K / UrbanSound8K)", 4200), cell("用户", 2160), cell("⏳ 待完成", 2400)] }), - new TableRow({ children: [cell("P0", 600), cell("录制/模拟无人机自噪声作为 ambient 负样本", 4200), cell("用户", 2160), cell("⏳ 待完成", 2400)] }), - new TableRow({ children: [cell("P1", 600), cell("用真实数据重新训练模型,替换合成数据", 4200), cell("AI助手", 2160), cell("⏳ 待数据就绪", 2400)] }), - new TableRow({ children: [cell("P1", 600), cell("C++ 特征一致性验证(Python librosa vs C++ FeatureExtractor)", 4200), cell("AI助手", 2160), cell("⏳ 待进行", 2400)] }), - new TableRow({ children: [cell("P1", 600), cell("C++ ONNX 推理测试(test_classifier_cpp 编译运行)", 4200), cell("AI助手", 2160), cell("✅ 已完成", 2400)] }), - new TableRow({ children: [cell("P2", 600), cell("实现 MicArraySource(ALSA 麦克风阵列驱动)", 4200), cell("AI助手", 2160), cell("⏳ 硬件到位后", 2400)] }), - new TableRow({ children: [cell("P2", 600), cell("手机端音频采集 App / 网页端实时传输", 4200), cell("AI助手", 2160), cell("⏳ 可选优化", 2400)] }), - ] - }), - new Paragraph({ spacing: { before: 200 } }), - - // 六、关键配置参数 - h1("六、关键配置参数速查"), - body("config/acoustic_params.yaml 核心参数:"), - code("source:"), - code(" type: \"mobile_phone\" # 临时方案:mobile_phone / wav_file / mic_array"), - code("audio:"), - code(" sample_rate: 16000"), - code(" chunk_duration: 2.0 # 分析窗口 2 秒"), - code(" hop_duration: 0.5 # 步进 0.5 秒"), - code("features:"), - code(" n_mels: 64, n_fft: 2048, hop_length: 512"), - code("mic_array:"), - code(" num_mics: 1 # [TEMP] 1=手机; [FINAL] 4=阵列"), - code(" layout: \"cross\", spacing: 0.15"), - code("classifier:"), - code(" model_path: \".../gunshot_classifier.onnx\""), - code(" threshold: 0.7"), - - // 七、文件路径索引 - h1("七、文件路径索引"), - body("项目根目录:software/src/drone-software/src/acoustic/"), - body("• 核心算法:include/acoustic_analyzer/core/ & src/core/"), - body("• IO 抽象:include/acoustic_analyzer/io/ & src/io/"), - body("• ROS 封装:include/acoustic_analyzer/ros/ & src/ros/"), - body("• 训练脚本:scripts/train_classifier.py, export_onnx.py, verify_onnx.py"), - body("• 手机桥接:scripts/mobile_audio_bridge.py, android_audio_sender.py"), - body("• 测试程序:tests/test_core_lib.cpp, extract_mel_cpp.cpp, test_classifier_cpp.cpp"), - body("• 配置文件:config/acoustic_params.yaml"), - body("• 模型权重:models/gunshot_classifier.onnx, train_output/best_model.pth"), - body("• 数据集:dataset/{train,val}/{ambient,gunshot,artillery,explosion}/"), - - // 八、如何继续 - h1("八、新增构建脚本说明"), - body("• build_core_test.bat:一键命令行编译,适用于快速验证核心算法和 ONNX 推理"), - body(" 编译目标:test_core_lib.exe / extract_mel_cpp.exe / test_classifier_cpp.exe"), - body("• build_cmake_mingw.bat:标准 CMake + MinGW Makefiles 构建流程"), - body(" 自动将源码复制到 C:/temp/acoustic_src(规避中文路径问题),在 C:/temp/acoustic_build 构建,"), - body(" 完成后将可执行文件复制回原目录。适用于需要标准 CMake 流程的场景。"), - body(""), - body("AI 助手将读取本文档及项目代码,基于当前状态继续推进。"), - ] - }] -}); - -Packer.toBuffer(doc).then(buffer => { - fs.writeFileSync("声源分析模块_项目交接文档.docx", buffer); - console.log("交接文档已生成:声源分析模块_项目交接文档.docx"); -}); diff --git a/generate_soldier_app_doc.js b/generate_soldier_app_doc.js deleted file mode 100644 index b9a1d416..00000000 --- a/generate_soldier_app_doc.js +++ /dev/null @@ -1,482 +0,0 @@ -const { Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell, ImageRun, - Header, Footer, AlignmentType, PageOrientation, LevelFormat, ExternalHyperlink, - InternalHyperlink, Bookmark, FootnoteReferenceRun, PositionalTab, - PositionalTabAlignment, PositionalTabRelativeTo, PositionalTabLeader, - TabStopType, TabStopPosition, Column, SectionType, - TableOfContents, HeadingLevel, BorderStyle, WidthType, ShadingType, - VerticalAlign, PageNumber, PageBreak } = require('docx'); -const fs = require('fs'); - -// 辅助函数:创建代码块样式段落 -function codeBlock(lines) { - const border = { style: BorderStyle.SINGLE, size: 1, color: "E0E0E0" }; - const borders = { top: border, bottom: border, left: border, right: border }; - return new Table({ - width: { size: 9360, type: WidthType.DXA }, - columnWidths: [9360], - rows: [ - new TableRow({ - children: [ - new TableCell({ - borders, - width: { size: 9360, type: WidthType.DXA }, - shading: { fill: "F5F5F5", type: ShadingType.CLEAR }, - margins: { top: 100, bottom: 100, left: 120, right: 120 }, - children: lines.map(line => new Paragraph({ - spacing: { before: 0, after: 0, line: 276 }, - children: [new TextRun({ font: "Consolas", size: 18, text: line || " " })] - })) - }) - ] - }) - ] - }); -} - -// 辅助函数:创建正文段落 -function bodyPara(text, opts = {}) { - return new Paragraph({ - spacing: { before: 120, after: 120, line: 360 }, - children: [new TextRun({ font: "宋体", size: 24, text, ...opts })] - }); -} - -// 辅助函数:创建加粗正文 -function boldPara(text) { - return bodyPara(text, { bold: true }); -} - -// 辅助函数:创建小节标题 -function subHeading(text, level = HeadingLevel.HEADING_2) { - return new Paragraph({ - heading: level, - spacing: { before: 240, after: 120 }, - children: [new TextRun({ text, bold: true, font: "黑体", size: level === HeadingLevel.HEADING_1 ? 32 : (level === HeadingLevel.HEADING_2 ? 28 : 26) })] - }); -} - -const doc = new Document({ - styles: { - default: { document: { run: { font: "宋体", size: 24 } } }, - paragraphStyles: [ - { id: "Heading1", name: "Heading 1", basedOn: "Normal", next: "Normal", quickFormat: true, - run: { size: 32, bold: true, font: "黑体" }, - paragraph: { spacing: { before: 400, after: 200 }, outlineLevel: 0 } }, - { id: "Heading2", name: "Heading 2", basedOn: "Normal", next: "Normal", quickFormat: true, - run: { size: 28, bold: true, font: "黑体" }, - paragraph: { spacing: { before: 300, after: 150 }, outlineLevel: 1 } }, - { id: "Heading3", name: "Heading 3", basedOn: "Normal", next: "Normal", quickFormat: true, - run: { size: 26, bold: true, font: "黑体" }, - paragraph: { spacing: { before: 200, after: 100 }, outlineLevel: 2 } }, - ] - }, - numbering: { - config: [ - { reference: "bullets", - levels: [{ level: 0, format: LevelFormat.BULLET, text: "•", alignment: AlignmentType.LEFT, - style: { paragraph: { indent: { left: 720, hanging: 360 } } } }] }, - { reference: "numbers", - levels: [{ level: 0, format: LevelFormat.DECIMAL, text: "%1.", alignment: AlignmentType.LEFT, - style: { paragraph: { indent: { left: 720, hanging: 360 } } } }] }, - ] - }, - sections: [{ - properties: { - page: { - size: { width: 11906, height: 16838 }, - margin: { top: 1440, right: 1440, bottom: 1440, left: 1440 } - } - }, - headers: { - default: new Header({ children: [new Paragraph({ - alignment: AlignmentType.RIGHT, - children: [new TextRun({ font: "宋体", size: 18, color: "666666", text: "智途投送 - 单兵终端APP设计文档" })] - })] }) - }, - footers: { - default: new Footer({ children: [new Paragraph({ - alignment: AlignmentType.CENTER, - children: [ - new TextRun({ font: "宋体", size: 18, text: "第 " }), - new TextRun({ children: [PageNumber.CURRENT], font: "宋体", size: 18 }), - new TextRun({ font: "宋体", size: 18, text: " 页" }) - ] - })] }) - }, - children: [ - // 封面标题 - new Paragraph({ alignment: AlignmentType.CENTER, spacing: { before: 2400, after: 400 }, - children: [new TextRun({ font: "黑体", size: 44, bold: true, text: "单兵终端APP" })] }), - new Paragraph({ alignment: AlignmentType.CENTER, spacing: { before: 200, after: 2400 }, - children: [new TextRun({ font: "黑体", size: 36, text: "软件架构与基本功能实现说明" })] }), - new Paragraph({ alignment: AlignmentType.CENTER, spacing: { before: 400, after: 200 }, - children: [new TextRun({ font: "宋体", size: 24, text: "智途投送软件系统" })] }), - new Paragraph({ alignment: AlignmentType.CENTER, spacing: { before: 100, after: 100 }, - children: [new TextRun({ font: "宋体", size: 24, text: new Date().toISOString().split('T')[0] })] }), - new Paragraph({ children: [new PageBreak()] }), - - // 目录 - new TableOfContents("目录", { hyperlink: true, headingStyleRange: "1-3" }), - new Paragraph({ children: [new PageBreak()] }), - - // 第一章 项目概述 - subHeading("一、项目概述", HeadingLevel.HEADING_1), - bodyPara("单兵终端APP是“智途投送”系统的移动端前端应用,供前线士兵使用。它基于 Capacitor 混合应用框架开发,以 HTML5 + JavaScript 实现业务逻辑,通过 Android WebView 渲染,并借助 Capacitor 插件调用原生能力(如 GPS 定位)。"), - bodyPara("APP 主要功能包括:士兵登录/注册、实时 GPS 定位与自动上报、紧急物资需求填报、投放点地图选点、任务进度监控、无人机状态查看、一键 SOS 求救等。"), - - subHeading("1.1 技术栈", HeadingLevel.HEADING_2), - new Paragraph({ numbering: { reference: "bullets", level: 0 }, spacing: { before: 80, after: 80 }, - children: [new TextRun({ font: "宋体", size: 24, text: "前端框架:原生 HTML5 + JavaScript(ES6+),无额外前端框架" })] }), - new Paragraph({ numbering: { reference: "bullets", level: 0 }, spacing: { before: 80, after: 80 }, - children: [new TextRun({ font: "宋体", size: 24, text: "混合容器:Capacitor 6.x(生成 Android 原生工程)" })] }), - new Paragraph({ numbering: { reference: "bullets", level: 0 }, spacing: { before: 80, after: 80 }, - children: [new TextRun({ font: "宋体", size: 24, text: "原生插件:@capacitor/geolocation(GPS 定位)" })] }), - new Paragraph({ numbering: { reference: "bullets", level: 0 }, spacing: { before: 80, after: 80 }, - children: [new TextRun({ font: "宋体", size: 24, text: "地图服务:高德地图 JS API 2.0(动态地图 + 静态地图 fallback)" })] }), - new Paragraph({ numbering: { reference: "bullets", level: 0 }, spacing: { before: 80, after: 80 }, - children: [new TextRun({ font: "宋体", size: 24, text: "后端通信:RESTful API(Flask 后端),fetch + AbortController 超时控制" })] }), - new Paragraph({ numbering: { reference: "bullets", level: 0 }, spacing: { before: 80, after: 80 }, - children: [new TextRun({ font: "宋体", size: 24, text: "数据持久化:localStorage(会话信息、服务器地址缓存)" })] }), - - subHeading("1.2 项目结构", HeadingLevel.HEADING_2), - codeBlock([ - "单兵终端APP/", - "├── capacitor.config.json # Capacitor 配置(应用ID、明文传输等)", - "├── package.json # 依赖:@capacitor/core、geolocation、android", - "├── index.html # SPA 单页结构(所有页面 div 容器)", - "├── css/style.css # 全局样式", - "├── js/", - "│ ├── app.js # 主应用:路由、状态、UI 交互", - "│ ├── api.js # API 封装:REST 请求 + Mock 降级", - "│ └── location.js # GPS 定位 + 高德地图封装", - "└── android/ # Capacitor 生成的 Android 工程" - ]), - - // 第二章 软件架构 - new Paragraph({ children: [new PageBreak()] }), - subHeading("二、软件架构", HeadingLevel.HEADING_1), - bodyPara("单兵终端APP采用经典的分层架构,从上到下依次为:表现层(UI 层)、业务逻辑层、数据访问层、原生能力层。整体为单页应用(SPA)模式,所有页面通过 JavaScript 动态切换,避免原生 Activity 跳转带来的开发复杂度。"), - - subHeading("2.1 架构分层", HeadingLevel.HEADING_2), - // 架构表格 - new Table({ - width: { size: 9360, type: WidthType.DXA }, - columnWidths: [2340, 7020], - rows: [ - new TableRow({ children: [ - new TableCell({ borders: { top: {style:BorderStyle.SINGLE,size:1,color:"CCCCCC"}, bottom:{style:BorderStyle.SINGLE,size:1,color:"CCCCCC"}, left:{style:BorderStyle.SINGLE,size:1,color:"CCCCCC"}, right:{style:BorderStyle.SINGLE,size:1,color:"CCCCCC"} }, - width: { size: 2340, type: WidthType.DXA }, shading: { fill: "D5E8F0", type: ShadingType.CLEAR }, margins: { top: 80, bottom: 80, left: 120, right: 120 }, - children: [new Paragraph({ children: [new TextRun({ bold: true, font: "宋体", size: 22, text: "分层" })] })] }), - new TableCell({ borders: { top: {style:BorderStyle.SINGLE,size:1,color:"CCCCCC"}, bottom:{style:BorderStyle.SINGLE,size:1,color:"CCCCCC"}, left:{style:BorderStyle.SINGLE,size:1,color:"CCCCCC"}, right:{style:BorderStyle.SINGLE,size:1,color:"CCCCCC"} }, - width: { size: 7020, type: WidthType.DXA }, shading: { fill: "D5E8F0", type: ShadingType.CLEAR }, margins: { top: 80, bottom: 80, left: 120, right: 120 }, - children: [new Paragraph({ children: [new TextRun({ bold: true, font: "宋体", size: 22, text: "职责与对应文件" })] })] }) - ]}), - new TableRow({ children: [ - new TableCell({ borders: { top: {style:BorderStyle.SINGLE,size:1,color:"CCCCCC"}, bottom:{style:BorderStyle.SINGLE,size:1,color:"CCCCCC"}, left:{style:BorderStyle.SINGLE,size:1,color:"CCCCCC"}, right:{style:BorderStyle.SINGLE,size:1,color:"CCCCCC"} }, - width: { size: 2340, type: WidthType.DXA }, margins: { top: 80, bottom: 80, left: 120, right: 120 }, - children: [new Paragraph({ children: [new TextRun({ font: "宋体", size: 22, text: "表现层(UI)" })] })] }), - new TableCell({ borders: { top: {style:BorderStyle.SINGLE,size:1,color:"CCCCCC"}, bottom:{style:BorderStyle.SINGLE,size:1,color:"CCCCCC"}, left:{style:BorderStyle.SINGLE,size:1,color:"CCCCCC"}, right:{style:BorderStyle.SINGLE,size:1,color:"CCCCCC"} }, - width: { size: 7020, type: WidthType.DXA }, margins: { top: 80, bottom: 80, left: 120, right: 120 }, - children: [new Paragraph({ children: [new TextRun({ font: "宋体", size: 22, text: "index.html(单页多视图)+ css/style.css;负责页面布局、控件渲染、事件绑定" })] })] }) - ]}), - new TableRow({ children: [ - new TableCell({ borders: { top: {style:BorderStyle.SINGLE,size:1,color:"CCCCCC"}, bottom:{style:BorderStyle.SINGLE,size:1,color:"CCCCCC"}, left:{style:BorderStyle.SINGLE,size:1,color:"CCCCCC"}, right:{style:BorderStyle.SINGLE,size:1,color:"CCCCCC"} }, - width: { size: 2340, type: WidthType.DXA }, margins: { top: 80, bottom: 80, left: 120, right: 120 }, - children: [new Paragraph({ children: [new TextRun({ font: "宋体", size: 22, text: "业务逻辑层" })] })] }), - new TableCell({ borders: { top: {style:BorderStyle.SINGLE,size:1,color:"CCCCCC"}, bottom:{style:BorderStyle.SINGLE,size:1,color:"CCCCCC"}, left:{style:BorderStyle.SINGLE,size:1,color:"CCCCCC"}, right:{style:BorderStyle.SINGLE,size:1,color:"CCCCCC"} }, - width: { size: 7020, type: WidthType.DXA }, margins: { top: 80, bottom: 80, left: 120, right: 120 }, - children: [new Paragraph({ children: [new TextRun({ font: "宋体", size: 22, text: "js/app.js;路由管理、状态管理、页面切换、表单校验、业务事件处理" })] })] }) - ]}), - new TableRow({ children: [ - new TableCell({ borders: { top: {style:BorderStyle.SINGLE,size:1,color:"CCCCCC"}, bottom:{style:BorderStyle.SINGLE,size:1,color:"CCCCCC"}, left:{style:BorderStyle.SINGLE,size:1,color:"CCCCCC"}, right:{style:BorderStyle.SINGLE,size:1,color:"CCCCCC"} }, - width: { size: 2340, type: WidthType.DXA }, margins: { top: 80, bottom: 80, left: 120, right: 120 }, - children: [new Paragraph({ children: [new TextRun({ font: "宋体", size: 22, text: "数据访问层" })] })] }), - new TableCell({ borders: { top: {style:BorderStyle.SINGLE,size:1,color:"CCCCCC"}, bottom:{style:BorderStyle.SINGLE,size:1,color:"CCCCCC"}, left:{style:BorderStyle.SINGLE,size:1,color:"CCCCCC"}, right:{style:BorderStyle.SINGLE,size:1,color:"CCCCCC"} }, - width: { size: 7020, type: WidthType.DXA }, margins: { top: 80, bottom: 80, left: 120, right: 120 }, - children: [new Paragraph({ children: [new TextRun({ font: "宋体", size: 22, text: "js/api.js;封装 HTTP 请求、超时控制、后端不可用时自动降级为 Mock 数据" })] })] }) - ]}), - new TableRow({ children: [ - new TableCell({ borders: { top: {style:BorderStyle.SINGLE,size:1,color:"CCCCCC"}, bottom:{style:BorderStyle.SINGLE,size:1,color:"CCCCCC"}, left:{style:BorderStyle.SINGLE,size:1,color:"CCCCCC"}, right:{style:BorderStyle.SINGLE,size:1,color:"CCCCCC"} }, - width: { size: 2340, type: WidthType.DXA }, margins: { top: 80, bottom: 80, left: 120, right: 120 }, - children: [new Paragraph({ children: [new TextRun({ font: "宋体", size: 22, text: "原生能力层" })] })] }), - new TableCell({ borders: { top: {style:BorderStyle.SINGLE,size:1,color:"CCCCCC"}, bottom:{style:BorderStyle.SINGLE,size:1,color:"CCCCCC"}, left:{style:BorderStyle.SINGLE,size:1,color:"CCCCCC"}, right:{style:BorderStyle.SINGLE,size:1,color:"CCCCCC"} }, - width: { size: 7020, type: WidthType.DXA }, margins: { top: 80, bottom: 80, left: 120, right: 120 }, - children: [new Paragraph({ children: [new TextRun({ font: "宋体", size: 22, text: "js/location.js + Capacitor 插件;GPS 定位、高德地图渲染、逆地理编码" })] })] }) - ]}), - ] - }), - - subHeading("2.2 核心模块关系", HeadingLevel.HEADING_2), - bodyPara("App 启动时,app.js 读取 localStorage 中的会话信息,若已登录则进入首页并启动两个定时任务:"), - new Paragraph({ numbering: { reference: "numbers", level: 0 }, spacing: { before: 80, after: 80 }, - children: [new TextRun({ font: "宋体", size: 24, text: "轮询任务(每 5 秒):当前页为“任务”或“无人机”时,自动拉取最新数据。" })] }), - new Paragraph({ numbering: { reference: "numbers", level: 0 }, spacing: { before: 80, after: 80 }, - children: [new TextRun({ font: "宋体", size: 24, text: "定位上报任务(每 10 秒):通过 LocationModule 获取坐标并上传后端。" })] }), - bodyPara("用户操作(如提交需求、选择投放点)由 app.js 收集表单数据,调用 API 模块发送请求;地图相关操作统一委托给 LocationModule 处理,避免业务层直接依赖地图 SDK。"), - - // 第三章 基本功能实现 - new Paragraph({ children: [new PageBreak()] }), - subHeading("三、基本功能实现", HeadingLevel.HEADING_1), - bodyPara("以下按功能模块逐一说明核心实现逻辑,并给出关键代码片段。"), - - // 3.1 项目配置 - subHeading("3.1 项目配置与入口", HeadingLevel.HEADING_2), - bodyPara("Capacitor 配置开启了 Android 明文传输(cleartext),便于局域网调试 Flask 后端;应用 ID 为 com.zhitu.soldier。"), - boldPara("capacitor.config.json"), - codeBlock([ - '{', - ' "appId": "com.zhitu.soldier",', - ' "appName": "智途投送-单兵终端",', - ' "webDir": "www",', - ' "server": {', - ' "androidScheme": "http",', - ' "cleartext": true', - ' },', - ' "plugins": {', - ' "Geolocation": { "enabled": true }', - ' }', - '}' - ]), - - // 3.2 登录注册 - subHeading("3.2 登录与注册", HeadingLevel.HEADING_2), - bodyPara("登录模块支持两套机制:演示账号本地登录(无需后端即可体验)和真实后端账号登录。会话信息以 JSON 形式存储在 localStorage 中,退出时清除。"), - boldPara("js/app.js - 登录逻辑"), - codeBlock([ - 'async function doLogin() {', - ' const id = document.getElementById("login-id").value.trim();', - ' const pwd = document.getElementById("login-pwd").value.trim();', - ' // 演示账号快速登录', - ' const demoAccounts = {', - ' "soldier_001": { name: "张三", unit: "第3步兵师/1连" },', - ' "soldier_002": { name: "李四", unit: "第3步兵师/2连" }', - ' };', - ' if (demoAccounts[id] && pwd === "123456") {', - ' localStorage.setItem("soldier_session", JSON.stringify({', - ' soldier_id: id, name: demoAccounts[id].name, ...', - ' }));', - ' router("home");', - ' startPolling();', - ' startLocationReporting();', - ' return;', - ' }', - ' // 真实后端登录', - ' const result = await API.login(id, pwd);', - ' if (result.ok) { ... }', - '}' - ]), - - // 3.3 路由管理 - subHeading("3.3 路由与页面管理", HeadingLevel.HEADING_2), - bodyPara(`APP 为单页应用(SPA),所有页面以
形式放在同一 HTML 中。通过 CSS class active 控制显示/隐藏,配合 pageStack 实现返回上一页。底部 Tab 栏仅在首页、任务、无人机、我的四个主页面显示。`), - boldPara("js/app.js - 路由切换"), - codeBlock([ - 'function router(page) {', - ' document.querySelectorAll(".page").forEach(p => p.classList.remove("active"));', - ' const target = document.getElementById("page-" + page);', - ' if (target) target.classList.add("active");', - ' // Tab 高亮与显隐控制', - ' document.querySelectorAll(".tab-item").forEach(t => t.classList.remove("active"));', - ' const tabItem = document.querySelector(\'.tab-item[data-page="\' + page + \'"]\');', - ' if (tabItem) tabItem.classList.add("active");', - ' const tabBar = document.getElementById("tab-bar");', - ' tabBar.style.display = TAB_PAGES.includes(page) ? "flex" : "none";', - ' pageStack.push(page);', - ' currentPage = page;', - ' onPageEnter(page); // 页面专属初始化', - '}' - ]), - - // 3.4 GPS定位 - subHeading("3.4 GPS 定位与自动上报", HeadingLevel.HEADING_2), - bodyPara("定位模块实现了四级降级策略:高德 JS 定位 → Capacitor 原生 GPS → 浏览器 Geolocation → IP 网络定位 → 默认坐标。确保在各种网络与权限环境下都能获得可用位置。"), - boldPara("js/location.js - 四级定位降级"), - codeBlock([ - 'async function getCurrentPosition() {', - ' // 1. 高德定位', - ' try { return await getAmapPosition(); }', - ' catch (e) { errors.push("高德:" + e.message); }', - ' // 2. Capacitor 原生定位', - ' try { return await getCapacitorPosition(); }', - ' catch (e) { errors.push("原生:" + e.message); }', - ' // 3. 浏览器定位', - ' try { return await getBrowserPosition(); }', - ' catch (e) { errors.push("浏览器:" + e.message); }', - ' // 4. IP 定位', - ' try { return await getIpPosition(); }', - ' catch (e) { errors.push("IP:" + e.message); }', - ' // 5. 默认兜底', - ' return { lat: 30.2500, lng: 120.1600, accuracy: 100, source: "default" };', - '}' - ]), - bodyPara("登录成功后,app.js 调用 LocationModule.startReporting() 启动定时上报,每隔 10 秒将坐标发送至后端 /api/soldier/location。"), - boldPara("js/app.js - 启动自动上报"), - codeBlock([ - 'function startLocationReporting() {', - ' LocationModule.startReporting(CONFIG.soldierId, CONFIG.soldierName, 10000);', - '}' - ]), - - // 3.5 物资需求上报 - subHeading("3.5 物资需求上报", HeadingLevel.HEADING_2), - bodyPara("士兵在“需求上报”页选择物资类型、数量、紧急程度,并关联投放点。提交时组装 JSON 对象,通过 POST /api/demand 发送至后端。投放点数据可以是地图选点结果,也可以是系统推荐列表中的安全点。"), - boldPara("js/app.js - 提交需求"), - codeBlock([ - 'async function submitDemand() {', - ' const type = document.getElementById("demand-type").value;', - ' const qty = document.getElementById("demand-qty").value;', - ' const urgency = document.querySelector("#urgency-group .radio-label.active")', - ' .dataset.value;', - ' const demand = {', - ' soldier_id: CONFIG.soldierId,', - ' type, quantity: parseInt(qty), urgency,', - ' drop_point: selectedDropPoint,', - ' status: "待处理",', - ' created_at: new Date().toISOString()', - ' };', - ' await API.postDemand(demand);', - ' showToast("✅ 需求上报成功!");', - ' router("home");', - '}' - ]), - - // 3.6 投放点与地图 - subHeading("3.6 投放点选择与地图集成", HeadingLevel.HEADING_2), - bodyPara("投放点选择页整合了三种交互方式:地图直接点击选点、地点关键词搜索、附近推荐列表。地图基于高德 JS API 2.0 动态初始化,支持逆地理编码获取地址名称;若动态地图加载失败,自动降级为静态地图图片。"), - boldPara("js/location.js - 地图选点初始化"), - codeBlock([ - 'async function initPickerMap(containerId, onSelectCallback) {', - ' const AMap = await loadAmapScript();', - ' const container = document.getElementById(containerId);', - ' container.style.width = "100%";', - ' container.style.height = "280px";', - ' container.innerHTML = "";', - ' pickerMap = new AMap.Map(containerId, {', - ' zoom: 15, center: [center.lng, center.lat], resizeEnable: true', - ' });', - ' // 点击地图选点', - ' pickerMap.on("click", (e) => {', - ' const lng = e.lnglat.lng, lat = e.lnglat.lat;', - ' pickerGeocoder.getAddress([lng, lat], (status, result) => {', - ' let address = result.regeocode.formattedAddress;', - ' onSelectCallback({ lat, lng, name, address });', - ' });', - ' });', - '}' - ]), - - // 3.7 任务监控 - subHeading("3.7 任务进度监控", HeadingLevel.HEADING_2), - bodyPara("任务页展示当前运输任务的进度、预计到达时间、飞行路径与投放点安全系数。进入页面时调用 API.getCurrentTask() 获取数据;若后端不可用,返回 Mock 数据保证界面不空白。"), - boldPara("js/app.js - 加载任务信息"), - codeBlock([ - 'async function loadTaskInfo() {', - ' const task = await API.getCurrentTask(CONFIG.soldierId);', - ' if (task) {', - ' document.getElementById("task-id").textContent = task.id;', - ' document.getElementById("task-status").textContent =', - ' statusMap[task.status]?.text || task.status;', - ' const prog = task.progress || 0;', - ' const filled = Math.round(20 * prog / 100);', - ' document.getElementById("task-progress-text").textContent =', - ' "█".repeat(filled) + "░".repeat(20 - filled) + " " + prog + "%";', - ' }', - '}' - ]), - - // 3.8 无人机状态 - subHeading("3.8 无人机状态查看", HeadingLevel.HEADING_2), - bodyPara("无人机页展示实时飞行数据:速度、高度、电量、温度、距离目标等,以及最近动态日志。与任务页共用轮询机制,每 5 秒自动刷新。"), - boldPara("js/app.js - 加载无人机状态"), - codeBlock([ - 'async function loadDroneStatus() {', - ' const status = await API.getDroneStatus();', - ' if (status) {', - ' document.getElementById("drone-battery").textContent = status.battery + "%";', - ' document.getElementById("drone-speed").textContent = status.speed + "m/s";', - ' document.getElementById("drone-alt").textContent = status.altitude + "m";', - ' document.getElementById("drone-dist").textContent = status.distance + "m";', - ' }', - ' const logs = await API.getDroneLogs();', - ' document.getElementById("drone-logs").innerHTML =', - ' logs.map(l => `
...`).join("");', - '}' - ]), - - // 3.9 SOS - subHeading("3.9 一键 SOS 求救", HeadingLevel.HEADING_2), - bodyPara("设置页提供紧急求救按钮,点击后二次确认,随后获取当前 GPS 坐标并立即上报后端 /api/sos。上报内容包含士兵ID、姓名、坐标和时间戳。"), - boldPara("js/app.js - SOS 求救"), - codeBlock([ - 'async function triggerSOS() {', - ' if (!confirm("确认发送求救信号?此操作将立即上报您的当前位置。")) return;', - ' const pos = await LocationModule.getCurrentPosition();', - ' await API.sendSOS({', - ' soldier_id: CONFIG.soldierId,', - ' soldier_name: CONFIG.soldierName,', - ' lat: pos.lat, lng: pos.lng,', - ' time: new Date().toISOString()', - ' });', - ' showToast("🚨 求救信号已发送!");', - '}' - ]), - - // 3.10 API封装 - subHeading("3.10 API 通信封装与离线降级", HeadingLevel.HEADING_2), - bodyPara("api.js 封装了所有后端接口请求,统一处理超时(5 秒)、JSON 序列化和错误捕获。对于投放点、任务、无人机状态等查询类接口,若后端不可用或超时,自动返回 Mock 数据,确保 APP 在离线/演示场景下仍可正常使用。"), - boldPara("js/api.js - 统一请求与超时控制"), - codeBlock([ - 'async function request(url, options = {}) {', - ' const fullUrl = url.startsWith("http") ? url : BASE + url;', - ' const controller = new AbortController();', - ' const timeoutId = setTimeout(() => controller.abort(), 5000);', - ' try {', - ' const resp = await fetch(fullUrl, {', - ' headers: { "Content-Type": "application/json" },', - ' signal: controller.signal, ...options', - ' });', - ' clearTimeout(timeoutId);', - ' return resp.json();', - ' } catch (e) {', - ' clearTimeout(timeoutId);', - ' if (e.name === "AbortError")', - ' throw new Error("请求超时,请检查后端是否启动");', - ' throw e;', - ' }', - '}' - ]), - boldPara("js/api.js - Mock 降级示例"), - codeBlock([ - 'async function getDropPoints() {', - ' try {', - ' const data = await request("/api/drop-points");', - ' return data.drop_points || data;', - ' } catch (e) {', - ' return getMockDropPoints(); // 离线兜底', - ' }', - '}' - ]), - - // 第四章 总结 - new Paragraph({ children: [new PageBreak()] }), - subHeading("四、设计特点与总结", HeadingLevel.HEADING_1), - bodyPara("单兵终端APP在设计上遵循“简单、可靠、可演示”的原则,主要特点如下:"), - new Paragraph({ numbering: { reference: "numbers", level: 0 }, spacing: { before: 80, after: 80 }, - children: [new TextRun({ font: "宋体", size: 24, text: "混合架构,跨平台成本低:基于 Capacitor 将 Web 技术打包为 Android APK,一套代码同时支持手机浏览器预览和真机安装。" })] }), - new Paragraph({ numbering: { reference: "numbers", level: 0 }, spacing: { before: 80, after: 80 }, - children: [new TextRun({ font: "宋体", size: 24, text: "多级定位降级,适应战场复杂环境:四级定位策略 + 手动修正,确保在城市、室内、弱网环境下仍能获取可用坐标。" })] }), - new Paragraph({ numbering: { reference: "numbers", level: 0 }, spacing: { before: 80, after: 80 }, - children: [new TextRun({ font: "宋体", size: 24, text: "Mock 数据兜底,支持离线演示:所有查询类 API 在后端不可用时自动返回模拟数据,便于开发调试与现场演示。" })] }), - new Paragraph({ numbering: { reference: "numbers", level: 0 }, spacing: { before: 80, after: 80 }, - children: [new TextRun({ font: "宋体", size: 24, text: "模块职责清晰,易于维护:app.js 负责业务与UI、api.js 负责网络、location.js 负责定位与地图,三层之间通过明确接口协作。" })] }), - new Paragraph({ numbering: { reference: "numbers", level: 0 }, spacing: { before: 80, after: 80 }, - children: [new TextRun({ font: "宋体", size: 24, text: "安全与权限考虑:Android 开启明文传输用于局域网调试;高德地图、GPS 权限在运行时动态申请;SOS 操作提供二次确认防止误触。" })] }), - bodyPara("综上所述,单兵终端APP通过简洁的分层架构和稳健的降级策略,实现了前线士兵在复杂战场环境下的物资需求上报、位置共享与任务协同功能。"), - ] - }] -}); - -Packer.toBuffer(doc).then(buffer => { - fs.writeFileSync("单兵终端APP_架构与功能实现说明.docx", buffer); - console.log("文档已生成:单兵终端APP_架构与功能实现说明.docx"); -}); diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 6f05f1d3..00000000 --- a/package-lock.json +++ /dev/null @@ -1,204 +0,0 @@ -{ - "name": "智途投送软件系统", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "dependencies": { - "docx": "^9.6.1" - } - }, - "node_modules/@types/node": { - "version": "25.6.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz", - "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==", - "license": "MIT", - "dependencies": { - "undici-types": "~7.19.0" - } - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "license": "MIT" - }, - "node_modules/docx": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/docx/-/docx-9.6.1.tgz", - "integrity": "sha512-ZJja9/KBUuFC109sCMzovoq2GR2wCG/AuxivjA+OHj/q0TEgJIm3S7yrlUxIy3B+bV8YDj/BiHfWyrRFmyWpDQ==", - "license": "MIT", - "dependencies": { - "@types/node": "^25.2.3", - "hash.js": "^1.1.7", - "jszip": "^3.10.1", - "nanoid": "^5.1.3", - "xml": "^1.0.1", - "xml-js": "^1.6.8" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "node_modules/immediate": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", - "license": "MIT" - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "license": "MIT" - }, - "node_modules/jszip": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", - "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", - "license": "(MIT OR GPL-3.0-or-later)", - "dependencies": { - "lie": "~3.3.0", - "pako": "~1.0.2", - "readable-stream": "~2.3.6", - "setimmediate": "^1.0.5" - } - }, - "node_modules/lie": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "license": "MIT", - "dependencies": { - "immediate": "~3.0.5" - } - }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "license": "ISC" - }, - "node_modules/nanoid": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.9.tgz", - "integrity": "sha512-ZUvP7KeBLe3OZ1ypw6dI/TzYJuvHP77IM4Ry73waSQTLn8/g8rpdjfyVAh7t1/+FjBtG4lCP42MEbDxOsRpBMw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.js" - }, - "engines": { - "node": "^18 || >=20" - } - }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "license": "(MIT AND Zlib)" - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "license": "MIT" - }, - "node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/sax": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", - "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=11.0.0" - } - }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "license": "MIT" - }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/undici-types": { - "version": "7.19.2", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", - "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", - "license": "MIT" - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "license": "MIT" - }, - "node_modules/xml": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", - "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==", - "license": "MIT" - }, - "node_modules/xml-js": { - "version": "1.6.11", - "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", - "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", - "license": "MIT", - "dependencies": { - "sax": "^1.2.4" - }, - "bin": { - "xml-js": "bin/cli.js" - } - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index b33d018e..00000000 --- a/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "dependencies": { - "docx": "^9.6.1" - } -} diff --git a/temp_doc_content.txt b/temp_doc_content.txt deleted file mode 100644 index 973df360..00000000 Binary files a/temp_doc_content.txt and /dev/null differ diff --git a/temp_doc_content_utf8.txt b/temp_doc_content_utf8.txt deleted file mode 100644 index 2ac985d0..00000000 --- a/temp_doc_content_utf8.txt +++ /dev/null @@ -1,100 +0,0 @@ -1: 智途投送 -2: 声源分析模块(Acoustic Analyzer) -3: 项目开发交接文档 -5: 国防科大计算机学院 23 级软件工程小班 -6: 2026 年 4 月 -8: 一、项目概述 -9: 声源分析模块是「智途投送」无人机软件系统的核心感知构件之一,负责通过麦克风阵列音频信号实现: -10: • 枪炮声识别分类(枪声 / 炮声 / 爆炸声 / 环境噪声) -11: • GCC-PHAT 声源定位(方位角、俯仰角) -12: • 基于能量衰减模型的距离估计 -13: • 多帧威胁跟踪与信息融合 -14: 模块采用 C++17 开发,核心算法零 ROS 依赖,通过 ONNX Runtime 进行神经网络推理,最终作为 ROS1 Noetic 节点部署于 P600 无人机机载电脑。 -15: 二、已完成工作总览 -16: 2.1 代码开发 -17: 已完成全部 34 个代码文件的编写,覆盖 Core 算法层、IO 抽象层、ROS 封装层及配套脚本: -19: 2.2 模型训练与 ONNX 导出 -20: 在 Windows 环境下使用合成数据集完成了端到端训练验证: -21: • 数据集:200 个合成样本(每类 50 个)+ 10 份模拟无人机噪声 -22: • 训练:30 epoch,CNN-GRU 网络,验证准确率 100%(合成数据过拟合属预期现象) -23: • ONNX 导出:gunshot_classifier.onnx(1.9MB,opset 13) -24: • ONNX 验证:枪声识别置信度 97.92% -25: 2.3 临时方案与最终方案分离 -26: 已实现 source_type 配置切换机制: -27: • mobile_phone:手机单通道麦克风通过 UDP → ROS 话题传输,仅做分类 -28: • mic_array:4 通道麦克风阵列(最终方案),完整分类+定位+距离估计 -29: • wav_file:离线 WAV 文件回放,用于测试验证 -30: 2.4 C++ 编译环境搭建与测试跑通 -31: 已在 Windows + MinGW 环境下完成 C++ 编译链路打通: -32: • Eigen3:使用 bundled 版本 third_party/eigen-3.4.0,无需安装 -33: • yaml-cpp:自动检测 conda 环境(C:/Users//miniconda3/Library),CMake 已适配 -34: • ONNX Runtime C++ v1.20.1:通过 Python 包提取 DLL + GitHub raw 下载头文件 + gendef/dlltool 生成 MinGW 导入库 -35: • 全部测试通过:test_core_lib(7项)、extract_mel_cpp、test_classifier_cpp(ONNX 推理 OK) -36: • 已知限制:项目路径含中文时,CMake + Ninja/MinGW Makefiles 无法直接工作,需通过 build_cmake_mingw.bat 自动复制到临时英文目录构建 -37: 2.5 代码 Bug 修复记录 -38: 搭建过程中发现并修复的问题: -39: • gcc_phat_localizer.cpp:缺少 #include ,导致 BDCSVD 不完整类型错误 -40: • threat_tracker.cpp:数据关联更新检测时丢失原有 threat_id,导致多帧跟踪失败 -41: • test_core_lib.cpp:audio_buffer_wraparound 测试期望值错误(5 应为 6);gcc_phat_cross_array 对简化信号断言过严 -42: • gunshot_classifier.cpp/h:升级至 ONNX Runtime C++ v1.20.1 RAII API,适配 wchar_t 路径(Windows) -43: • CMakeLists.txt:添加 MinGW 适配(-D_USE_MATH_DEFINES、-Wa,-mbig-obj、_stdcall 覆盖、yaml-cpp 自动检测) -44: 三、架构设计 -45: 模块采用三层构件化架构,核心算法层完全独立于 ROS,确保可分离、可测试、可移植: -47: ┌─────────────────────────────────────────┐ -48: │ ROS 层(acoustic_node / threat_publisher)│ ← 话题订阅/发布 -49: ├─────────────────────────────────────────┤ -50: │ IO 层(WavFileSource / MobilePhoneSource)│ ← 音频源抽象 -51: ├─────────────────────────────────────────┤ -52: │ Core 层(Pipeline 编排以下模块) │ ← 零 ROS 依赖 -53: │ • FeatureExtractor (Mel Spectrogram) │ -54: │ • GunshotClassifier (ONNX Runtime) │ -55: │ • GccPhatLocalizer (GCC-PHAT + TDOA) │ -56: │ • DistanceEstimator (能量衰减 + 卡尔曼) │ -57: │ • ThreatTracker (多帧关联跟踪) │ -58: └─────────────────────────────────────────┘ -60: 四、当前环境与依赖 -61: 4.1 Python 训练环境(Windows 已验证) -63: 4.2 C++ 编译环境(Windows 已配置) -64: • 编译器:g++ (MinGW-W64 15.2.0) 已安装 ✅ -65: • CMake:4.1.0 已安装 ✅ -66: • Eigen3:bundled third_party/eigen-3.4.0 ✅ -67: • ONNX Runtime C++:v1.20.1 已配置(头文件 + DLL + MinGW 导入库)✅ -68: • yaml-cpp:conda 0.8.0 已检测,CMake 自动链接 ✅ -69: • 构建方式: -70: – 快速命令行:build_core_test.bat(一键编译全部测试) -71: – 标准 CMake:build_cmake_mingw.bat(自动处理中文路径问题) -72: 五、待办事项与下一步计划 -74: 六、关键配置参数速查 -75: config/acoustic_params.yaml 核心参数: -76: source: -77: type: "mobile_phone" # 临时方案:mobile_phone / wav_file / mic_array -78: audio: -79: sample_rate: 16000 -80: chunk_duration: 2.0 # 分析窗口 2 秒 -81: hop_duration: 0.5 # 步进 0.5 秒 -82: features: -83: n_mels: 64, n_fft: 2048, hop_length: 512 -84: mic_array: -85: num_mics: 1 # [TEMP] 1=手机; [FINAL] 4=阵列 -86: layout: "cross", spacing: 0.15 -87: classifier: -88: model_path: ".../gunshot_classifier.onnx" -89: threshold: 0.7 -90: 七、文件路径索引 -91: 项目根目录:software/src/drone-software/src/acoustic/ -92: • 核心算法:include/acoustic_analyzer/core/ & src/core/ -93: • IO 抽象:include/acoustic_analyzer/io/ & src/io/ -94: • ROS 封装:include/acoustic_analyzer/ros/ & src/ros/ -95: • 训练脚本:scripts/train_classifier.py, export_onnx.py, verify_onnx.py -96: • 手机桥接:scripts/mobile_audio_bridge.py, android_audio_sender.py -97: • 测试程序:tests/test_core_lib.cpp, extract_mel_cpp.cpp, test_classifier_cpp.cpp -98: • 配置文件:config/acoustic_params.yaml -99: • 模型权重:models/gunshot_classifier.onnx, train_output/best_model.pth -100: • 数据集:dataset/{train,val}/{ambient,gunshot,artillery,explosion}/ -101: 八、新增构建脚本说明 -102: • build_core_test.bat:一键命令行编译,适用于快速验证核心算法和 ONNX 推理 -103: 编译目标:test_core_lib.exe / extract_mel_cpp.exe / test_classifier_cpp.exe -104: • build_cmake_mingw.bat:标准 CMake + MinGW Makefiles 构建流程 -105: 自动将源码复制到 C:/temp/acoustic_src(规避中文路径问题),在 C:/temp/acoustic_build 构建, -106: 完成后将可执行文件复制回原目录。适用于需要标准 CMake 流程的场景。 -108: AI 助手将读取本文档及项目代码,基于当前状态继续推进。 diff --git a/temp_req.txt b/temp_req.txt deleted file mode 100644 index ddf42bb2..00000000 --- a/temp_req.txt +++ /dev/null @@ -1,5 +0,0 @@ -=== 第四组软件需求规格说明书 === -文档编号:“智途投送”软件系统 – SRS – 1.0 “智途投送”软件系统软件需求规格说明书日期:2026年3月30日文档变更历史记录序号变更日期变更人员变更内容详情描述变更后的版本号12026/3/29全员撰写了软件需求规格说明书初稿V1.0目录1. 引言41.1 编写目的41.2 读者对象41.3 软件项目概述41.4 文档概述41.5 定义41.6 参考资料42. 软件的一般性描述52.1软件产品与其环境之间的关系52.2限制与约束52.3假设与前提条件53. 软件功能需求描述53.1 软件功能概述53.2 软件需求的用例模型53.3 软件需求的分析模型54. 其它软件需求描述54.1 性能要求54.2 设计约束64.3 界面要求64.4 进度要求64.5 交付要求64.6 验收要求65. 软件原型61. 引言1.1 编写目的本文档为“最后一公里”智能运输软件系统的软件需求规格说明,旨在对系统的功能需求、非功能需求及约束条件进行完整、准确、规范的描述。编写目的主要包括以下几点:·明确系统需求边界:完整定义系统应具备的功能、性能及约束,为后续设计与开发提供统一的需求边界。·指导开发与测试:为开发团队提供详细的功能规格说明,为测试团队提供需求验证的依据。·支持评审与决策:为项目评审、技术决策及需求变更管理提供正式的参考文档。·促进团队协作:统一各子系统(单兵终端、无人机软件、后勤保障系统)开发人员对系统需求的理解。1.2 读者对象本文档的目标读者包括用户,分析人员,软件设计人员,项目管理人员。1.3 软件项目概述项目名称:“智途投送”软件系统项目简称:“智途投送”用户单位:城市作战环境下的前线作战单兵及后方后勤保障指挥部门开发单位:国防科大计算机学院23级软件工程小班王嘉奇小组软件项目背景和大致功能:近年来,多场局部战争的实战经验反复证明,后勤补给的最后一公里已成为制约战场持续作战能力的核心瓶颈。所谓战场后勤的最后一公里,是指作战物资从后方集散中心输送至前线作战单元、偏远阵地士兵手中的最后一段末端配送路程,该环节直面复杂地形、敌方袭扰、火力封锁、通信中断等多重风险。2023年以哈战争中,以军在加沙城市巷战环境遭遇严重后勤困境,狭窄街巷、密集建筑使得传统装甲运输车难以深入城区,补给车队频遭伏击。2022年俄乌冲突中,前线部队长期面临弹药、食品、急救药品严重短缺,传统有人运输在最后几公里内频繁遭遇炮火覆盖,伤亡率极高。即便引入无人机等无人平台,也因缺乏统一调度、智能路径规划和安全投放策略,末端配送效率低下、协调困难。本软件专为解决城市作战环境下“最后一公里”末端补给难题而设计,聚焦无人机物资投送场景。系统支持前线士兵通过终端实时上报需求,后方统一调度无人机执行运输任务;无人机基于城市三维模型识别墙体等障碍物,智能规划安全飞行路径,确保关键物资在复杂城市战场环境下能够隐蔽、安全、及时送达作战人员手中;无人机还能实时同步士兵位置变化,支持任务执行过程中动态更新投放目标。1.4 文档概述本文档按照软件需求规格说明书的标准结构组织,共分为五个部分:第1章 引言:阐述文档的编写目的、读者对象、项目概述、文档结构、术语定义及参考资料。第2章 软件的一般性描述:描述系统与其运行环境之间的关系,包括系统组成、部署架构、外部接口、限制约束及假设前提。第3章 软件功能需求描述:以用例模型和分析模型的方式,详细描述系统的各项功能需求,包括物资请求与任务规划、路径规划策略选择、动态目标调整、信息加密与安全传输、自主路径规划与动态避障、安全投放点筛选、应急处理等功能。第4章 其它软件需求描述:描述系统的性能要求、设计约束、界面要求、进度要求、交付要求及验收要求。第5章 软件原型:提供系统原型及必要的说明。1.5 定义本文档中涉及到一些关键术语,它们的具体说明如下表1所示。术语/缩写全称定义最后一公里Last Mile作战物资从后方集散中心输送至前线作战单元、偏远阵地士兵手中的末端配送路程UAVUnmanned Aerial Vehicle无人机,本系统中指执行物资运输任务的多旋翼无人机IMUInertial Measurement Unit惯性测量单元,提供姿态与角速度信息,用于视觉导航辅助GPSGlobal Positioning System全球定位系统,用于提供无人机和士兵的位置信息SDKSoftware Development Kit软件开发工具包AESAdvanced Encryption Standard高级加密标准,本系统用于通信数据加密A*A-Star Algorithm一种启发式路径搜索算法,用于全局路径规划RRTRapidly-exploring Random Tree快速扩展随机树算法,用于复杂环境下的路径规划OpenCVOpen Source Computer Vision Library开源计算机视觉库,用于图像处理与障碍物识别PX4PX4 Autopilot开源飞控系统,支持无人机自主飞行开发GazeboGazebo Simulator开源机器人仿真平台,用于算法验证表 1 术语说明表1.6 参考资料[1].GB/T 8567-2006 计算机软件文档编制规范.中国国家标准化管理委员会.2006[2].IEEE 830-1998 软件需求规格说明推荐实践.IEEE.1998[3].“最后一公里”智能运输软件系统的需求构思及描述.第四组.2026[4].CSIS报告:俄乌冲突中的无人机末端投送分析.Center for Strategic and International Studies.2022[5].文档模板:软件需求规格说明书.课程提供.20262. 软件的一般性描述2.1 软件产品与其环境之间的关系1.系统总体架构本系统由三大核心子系统构成:单兵终端系统、无人机软件系统、后勤保障系统,各子系统协同配合,共同完成城市巷战中物资运输的完整闭环任务,三个子系统的部署图如图1所示。(1)单兵终端系统部署于前线士兵随身携带的智能手表/手环或智能手机上,安装轻量级终端APP。作为士兵与后勤保障系统的交互入口,负责物资需求上报、库存查询、投放点导航及消息通知接收。通过移动网络或局域网与后勤保障系统保持通信。(2)无人机软件系统搭载于多旋翼无人机平台,集成路径规划算法模块、动态避障算法模块、飞行控制模块及视觉导航模块,负责执行运输任务、自主路径规划及动态避障。机载软件预加载城市三维模型,与后勤保障系统通过无线网络保持通信。(3)后勤保障系统部署于后方指挥所或移动指挥车的服务器或高性能PC上,包含任务调度模块、数据库管理模块、通信服务模块、可视化监控模块及城市地图数据,负责需求接收、无人机任务分配、资源管理、状态监控及通信中继。图 1 软件系统部署图2. 子系统间数据流关系三大子系统之间存在以下数据交互关系:数据流向传输内容通信方式频率单兵终端 → 后勤保障系统物资需求(类型、数量、紧急程度、位置)加密无线通信按需触发后勤保障系统 → 无人机任务指令(起点、目标区域、物资信息、策略)Wi-Fi/数传电台任务下发时无人机 → 后勤保障系统飞行状态、位置、电量、任务进度Wi-Fi/数传电台周期性上报后勤保障系统 → 单兵终端投放点位置、预计到达时间、任务状态加密无线通信任务确认后推送表 2 子系统数据交互关系说明表3. 外部系统与硬件环境本系统与以下外部系统及硬件环境存在交互关系:关系描述交互方式为无人机和单兵终端提供定位信息卫星信号接收为各子系统间数据传输提供通信链路Wi-Fi / 4G / 5G / 数传电台提供建筑轮廓、道路网络、三维模型数据预加载至本地执行飞行控制指令,反馈传感器数据SDK / MAVLink协议提供环境图像数据用于障碍物识别与视觉导航图像数据采集提供姿态与角速度数据用于视觉导航辅助传感器数据读取表 3 外部系统与硬件环境交互关系表4. 用户角色系统主要包含三类用户角色,他们分别有不同的职责,具体描述如下表4所示。角色职责描述使用子系统前线士兵上报物资需求、查看库存信息、接收投放点通知、选择路径策略、更新目标位置单兵终端系统后勤调度员接收需求、分配无人机任务、监控任务状态、管理物资库存、标注威胁区域后勤保障系统系统管理员系统配置、用户管理、数据维护、日志审计后勤保障系统表 4 用户角色职责描述表2.2 限制与约束1. 硬件约束无人机载荷限制:多旋翼无人机载荷能力建议不低于2kg,单次运输物资量受载荷与续航双重约束。无人机续航限制:续航时间建议不低于20分钟,任务规划需考虑电量消耗与安全返航预留。终端设备限制:单兵终端运行于智能手表/手环或智能手机,计算资源与存储空间有限,仅部署轻量级应用。视觉传感器限制:采用普通摄像头而非激光雷达,在低光照、遮挡、纹理缺失等条件下识别精度受限。服务器资源:后勤保障系统部署于普通PC或笔记本,算力有限,复杂算法运算需进行效率优化。2.通信约束城市环境遮挡:建筑物密集导致无线信号不稳定,通信链路可能中断。带宽限制:战场环境下可用通信带宽有限,数据传输需进行压缩与优先级管理。通信范围:无人机与后勤保障系统的有效通信距离受限于无线设备功率与地形遮挡。加密开销:AES加密与完整性校验会增加通信延迟,需在安全性与实时性之间取得平衡。3. 环境约束GPS信号受限:城市峡谷效应可能导致GPS信号漂移或丢失,需视觉导航与IMU辅助定位。气象条件:大风、降雨、沙尘等复杂气象条件影响无人机飞行安全,需设置气象阈值。电磁干扰:战场电磁环境复杂,可能影响GPS信号与无线通信质量。动态环境:城市战场环境瞬息万变,建筑损毁、道路阻断等变化需系统具备快速适应能力。4. 数据约束三维模型精度:建筑模型精度不足或数据更新滞后可能导致视线遮蔽计算误差。地图数据时效性:城市战场环境中建筑可能被摧毁或改变,预加载的地图数据可能过时。威胁信息准确性:敌方火力点、禁区等威胁区域信息依赖人工标注,可能存在滞后或遗漏。5. 安全约束通信安全:所有子系统间数据传输必须经过加密处理,防止敌方截获与篡改。身份认证:系统需实现双向身份认证,防止非法节点接入。位置信息安全:士兵位置、投放点坐标等敏感信息需严格保护,防止敌方通过投放点反推阵地位置。抗干扰能力:系统需具备一定的抗电磁干扰和抗欺骗能力。6. 开发约束开发周期:课程项目周期有限,需合理规划开发优先级,核心功能优先实现。团队规模:开发团队人数有限,需合理分工,各子系统并行开发。实验条件:实际无人机飞行实验条件受限,部分功能需通过仿真环境验证。技术选型:优先采用成熟开源技术栈,降低开发风险。2.3 假设与前提条件1. 运行环境假设卫星定位可用:假设任务区域内GPS/北斗卫星定位信号基本可用,仅在局部区域(如高楼密集区)可能出现信号衰减。无线通信可用:假设任务区域内存在可用的无线通信网络(Wi-Fi、4G/5G或专用数传网络),通信中断为临时性、可恢复的。三维数据就绪:假设任务执行前已完成城市建筑三维模型数据的采集与预处理,并预加载至无人机与后勤保障系统。威胁信息已知:假设敌方主要火力点、禁区等威胁区域信息已通过侦察手段获取,并录入系统。2. 用户假设士兵具备基本操作能力:假设前线士兵能够使用智能手表/手环或智能手机进行基本操作,包括需求上报、策略选择等。调度员具备系统操作能力:假设后勤调度员经过培训,能够熟练使用后勤保障系统进行任务管理与监控。用户遵循操作规程:假设用户按照系统设计的使用流程操作,不会进行超出系统设计范围的异常操作。3. 硬件前提无人机可用:假设执行任务的多旋翼无人机处于正常工作状态,具备足够的电量和载荷能力。终端设备可用:假设士兵携带的智能手表/手环或智能手机电量充足、网络连接正常。服务器可用:假设后勤保障系统的服务器或PC正常运行,数据库服务可用。4. 技术前提算法可行性:假设A*、RRT等路径规划算法及视线遮蔽计算算法在城市三维模型数据上能够有效运行。视觉算法可用性:假设基于OpenCV的墙体识别与障碍检测算法在典型城市环境图像上能够达到可接受的识别精度。无人机SDK支持:假设选用的无人机平台提供稳定的SDK接口,支持航线规划、状态监控及自主飞行控制。5. 验证前提仿真环境可用:假设Gazebo、AirSim等仿真环境可用于路径规划和投放点筛选算法的验证。测试数据就绪:假设能够采集或获取足够数量的城市环境图像数据集,用于视觉算法的离线测试。飞行测试场地:假设存在小范围空旷场地可用于无人机系统集成测试与通信链路验证。3. 软件功能需求描述3.1 软件功能概述1. 物资请求与任务规划功能功能描述:前线士兵通过单兵终端上报物资需求(类型、数量、紧急程度、位置),系统自动校验并生成任务方案。优先级:高使用场景:前线士兵急需补给时执行主体:人工决策 + 软件执行说明:系统支持异常请求过滤与毫秒级响应处理路径规划策略选择功能功能描述:提供“最快到达”、“最安全”、“最省能耗”三种路径策略,由士兵自主选择。优先级:高使用场景:不同战术需求(紧急补给/高威胁区域/长距离运输)执行主体:人工决策 + 软件执行说明:若30秒内未选择,默认“最安全”策略动态目标调整功能功能描述:支持任务执行过程中动态更新目标位置,并重新规划航线。优先级:较高使用场景:士兵移动或战场态势变化执行主体:软件执行 + 无人机执行说明:电量充足且在通信范围内才能调整,否则通知士兵前往原投放点。信息加密与安全传输功能功能描述:提供通信安全保障,包括加密、认证与重传机制。优先级:高执行主体:软件执行关键能力:AES加密、数据完整性校验、双向身份认证自主路径规划与动态避障功能功能描述:无人机基于视觉与IMU实现自主飞行与避障。优先级:高执行主体:无人机执行特点:墙体识别、障碍绕行、GPS拒止环境可运行战士标注辅助决策功能优先级:中等功能描述:士兵可标记危险/安全区域,影响算法决策。执行主体:人工决策 + 软件执行应急处理功能功能描述:应对通信中断、电量不足等异常情况。优先级:中等执行主体:软件执行3.2 软件需求的用例模型图2展示了“智途投送”系统的用例图。图 2“智途投送”软件系统用例图以下是对该软件系统的各个具体用例的详细描述。用例1:物资请求与任务规划用例名物资请求与任务规划用例描述前线士兵通过单兵终端上报物资需求,后勤保障系统接收需求并进行校验、分析和任务规划,后勤调度员确认后生成配送任务。参与者前线士兵、后勤调度员过程1.前线士兵在单兵终端中填写物资类型、数量、紧急程度和当前位置等信息。 单兵终端对输入内容进行完整性检查。2.需求信息通过加密通信链路上传至后勤保障系统。3.后勤保障系统对需求进行时间戳标记、去重校验和合法性校验。后勤调度员查看需求信息,并结合库存状态、无人机状态进行任务分配。4.系统生成运输任务,确定执行无人机、起点、目标区域和基础路径信息。系统将任务状态反馈给前线士兵,并进入后续配送流程。表 5 物资请求与任务规划用例描述表图 3 物资请求与任务规划顺序图用例2:信息加密与安全传输用例名信息加密与安全传输用例描述系统对单兵终端、后勤保障系统和无人机之间的数据通信进行加密、认证和完整性校验,保障任务数据和位置信息安全。参与者单兵终端、后勤保障系统、无人机过程1.通信双方建立连接并进行双向身份认证。2.系统协商并生成会话密钥。3.发送端对需求数据、任务数据、状态数据等进行加密处理,系统为每个数据帧附加完整性校验信息。4.接收端进行解密和校验,验证数据来源和内容完整性。5.当链路中断时,系统将关键数据缓存在本地。链路恢复后,系统优先重传关键任务数据。表 6 信息加密与安全传输用例描述表用例3:路径策略选择用例用例名路径规划策略选择用例描述根据战场态势和任务优先级,在系统提供的多种路径规划策略中进行选择,以提高运输任务的灵活性和适应性参与者后勤调度员,无人机过程1.任务创建后系统展示可选策略,包括“最快到达”“最安全”“最省能耗”。2.后期调度员根据当前物资紧急程度、敌方火力密度、无人机续航情况选择路径策略。3.系统记录所选策略并作为路径规划算法的优化目标。4.后勤保障系统依据所选策略计算全局路径。5.若在规定时间内未完成选择,系统自动采用默认策略“最安全”。6.路径规划结果下发至无人机执行。表 7 路径策略选择用例描述表图 4 路径策略选择顺序图用例4:自主路径规划与动态避障用例用例名自主路径规划与动态避障用例描述后勤保障系统在完成任务规划、路径生成和投放点确定后,将运输任务下发给指定无人机。无人机按照任务指令完成起飞、巡航飞行、动态避障、物资投放和任务返回等全过程,并实时向系统回传任务状态。参与者无人机、后勤保障系统、前线士兵、后勤调度员过程1.后勤保障系统根据任务规划结果,向指定无人机下发运输任务。无人机接收任务信息,包括物资类型、目标区域、推荐投放点、飞行路径和任务优先级。2.无人机对任务参数进行校验,并检查当前电量、载荷状态、通信状态和传感器状态是否满足执行条件。若满足起飞条件,无人机进入待执行状态并向后勤保障系统反馈“任务已接收”。3.无人机按照预设流程完成起飞,沿规划路径飞向目标区域。飞行过程中,无人机持续采集周边环境信息,并结合机载视觉与IMU数据进行姿态控制和局部路径修正。4.若前方存在障碍物、禁飞区域或突发风险,无人机启动动态避障或局部重规划机制。无人机持续向后勤保障系统回传当前位置、剩余电量、飞行速度、任务阶段和预计到达时间。5.前线士兵位置发生变化且满足目标调整条件时,系统向无人机下发更新后的目标点和航线信息。6.无人机到达目标区域后,对推荐投放点进行最终安全性确认;满足安全条件则执行物资投放,记录投放时间、坐标和任务结果。7.无人机将投放完成信息同步发送给后勤保障系统和前线士兵终端。8.投放完成后,无人机按照系统指令返航,或继续执行后续任务。无人机返回基地或到达指定位置后,系统将任务状态更新为“已完成”。9.后勤保障系统保存任务执行记录,供后续查询、统计与复盘分析使用表 8 自主路径规划与动态避障用例描述表图 5 自主路径规划与动态避障顺序图用例5:动态调整目标用例用例名动态目标调整用例描述在无人机执行任务过程中,系统支持根据士兵位置变化或士兵主动申请,对目标位置和投放点进行动态更新参与者前线士兵、无人机、后勤保障系统过程1.前线士兵主动上报新位置,或单兵终端检测到士兵位置偏移超过阈值。2.单兵终端将目标变更请求发送至后勤保障系统。3.后勤保障系统评估无人机当前状态,包括剩余电量、飞行距离、通信范围和任务进度。若满足调整条件,系统重新计算投放点和飞行航线。无人机更新执行路径并继续任务。若不满足调整条件,系统通知士兵前往原投放点取用物资。表 9 动态目标调整用例描述表图 6 动态调整目标顺序图3.3 软件需求的分析模型(1)系统总体结构模型系统采用三层结构,分别是单兵终端层、后勤调度层、无人机执行层(2)主要类模型核心类包括:User(士兵/调度员)、Task(任务)、Drone(无人机)、Path(路径)、DropPoint(投放点)、Annotation(标注信息)(3)关键交互模型(时序逻辑)任务执行流程:士兵上报需求→后勤系统生成任务→士兵选择策略→系统规划路径→无人机执行→投放并反馈4. 其它软件需求描述4.1 性能要求1.需求上报与任务生成响应时间要求在网络正常的情况下,前线士兵提交物资需求后,系统应在短时间内完成请求接收、校验与任务生成。普通请求的响应时间应不超过2秒,紧急任务请求应优先处理。2.路径规划与投放点计算性能要求在预加载城市地图和三维模型数据的前提下,系统应在可接受时间内完成全局路径规划和安全投放点筛选。常规任务的路径规划时间建议不超过5秒,安全投放点筛选建议不超过3秒。3.状态回传实时性要求无人机应周期性向后勤保障系统回传位置、电量、速度和任务状态信息,状态刷新周期建议不超过1秒,以保障监控的实时性。4.动态目标调整响应要求当士兵发起目标变更请求后,系统应在3秒内完成条件判断并给出是允许调整的结果;若允许调整,应在5秒内重新生成目标点和航线。5.可靠性要求系统应支持连续运行,后勤保障系统需具备较高稳定性;无人机在正常任务周期内应保持稳定通信与飞行控制能力。系统应支持关键任务日志记录与错误恢复机制。6.并发能力要求后勤保障系统应支持多个前线终端同时上报需求,并支持同时监控多架无人机任务执行状态,不得因多任务并发导致系统崩溃或关键任务信息丢失。4.2 设计约束1.硬件约束系统需部署在具备一定载荷能力和续航能力的多旋翼无人机平台上,并依赖摄像头、IMU、定位模块和通信模块等基础硬件。部分扩展功能如热成像识别需要额外传感器支持。2.环境约束系统主要面向城市作战环境,需考虑高楼遮挡、道路阻断、通信不稳定、GPS漂移或拒止等复杂条件。算法设计必须适应非理想环境。3.数据约束系统运行依赖预先采集的城市建筑轮廓、道路网络和三维模型数据。若地图数据缺失、精度不足或更新滞后,可能影响路径规划与安全投放点筛选效果。4.技术约束系统应优先采用可实现、可集成的成熟技术方案,如A*、RRT 等路径规划算法、OpenCV视觉处理技术、开源飞控或主流SDK接口,避免依赖难以落地的高成本专有设备。5.安全约束系统涉及敏感位置、任务和战术信息,通信过程必须采用加密机制,未经授权的终端不得接入系统。系统应尽量减少任务信息泄露风险。6.时间约束项目开发需在限定周期内完成,因此应采用模块化开发方式,优先完成需求上报、任务调度、路径规划、安全投放和应急处理等核心功能原型。4.3 界面要求1.单兵终端界面要求单兵终端界面应简洁直观,适合战场高压环境下快速操作。界面设计应突出大按钮、少层级、低操作复杂度,便于士兵快速完成关键操作。核心功能包括物资需求上报、路径策略选择、投放点查看与导航、任务状态查看、战场区域标注、位置变更上报。2.后勤保障系统界面要求后勤保障系统应提供可视化调度界面,支持调度员快速查看任务全局态势,并进行任务分配、任务取消和状态监控。能够展示:任务列表、无人机位置与状态、库存信息、投放点位置、地图与三维环境信息、风险区域与士兵标注信息。3.无人机端界面要求无人机机载软件以自主执行为主,对图形界面无强制要求;如配套调试界面,应能显示传感器状态、当前航线、避障结果和返航状态等调试信息。4.4 进度要求1)项目初期应完成需求分析、系统方案设计及原型规划。2)中期应完成单兵终端、后勤保障系统和无人机机载软件的核心模块开发。3)后期应完成系统联调、仿真测试、功能验证和文档整理。4)应优先保证以下核心功能按期完成:物资请求与任务规划,路径规划策略选择,自主路径规划与动态避障,动态目标调整,应急处理。4.5 交付要求整个软件系统项目完成以后,应当交付以下文档及程序:单兵终端软件安装包或可运行版本;后勤保障系统软件及数据库部署文件;无人机机载软件或仿真运行程序;软件需求规格说明书电子文档;软件设计说明书电子文档;系统使用说明书电子文档;必要的测试报告、演示材料和运行说明。4.6 验收要求1.系统应能够完成物资需求上报、任务调度、路径规划、任务执行监控和异常处理等核心功能。2.系统在仿真环境或测试环境中,应能够正确展示以下能力:士兵成功提交物资需求;调度员成功生成并下发任务;无人机根据所选策略完成路径执行;士兵位置变化后系统可进行动态目标调整;遇到通信中断、电量不足等情况时系统能触发应急处理机制。3.系统运行过程中不应出现严重错误或崩溃,对异常输入和异常状态应能够给出合理提示或安全处理结果。4.系统文档应齐全,内容与实际实现一致,能够支持用户使用、系统部署与后续维护。5. 软件原型5.1单兵终端APP界面设计1.首页(主界面)如图 7为单兵终端APP的主界面,是前线士兵进入系统后的第一个页面,提供核心功能的快速入口。在士兵需要快速了解当前物资状态并上报需求时使用。图 7 单兵终端APP主界面2.物资需求上报界面如图 8为前线士兵上报物资需求的核心界面,支持详细的物资信息和战场标注。士兵需要请求物资补给时,填写详细需求信息并提交。图 8 物资需求上报界面3.投放点选择界面如图 9为士兵查看系统推荐的安全投放点列表,并可选择或标注投放位置。系统推荐多个投放点后,士兵需要选择最合适的投放位置,或主动标注战场信息辅助决策。图 9 投放点选择界面4.位置更新界面如图 10为士兵位置发生偏移时,申请更新投放目标位置的界面。士兵因战术移动导致位置变化,需要通知系统更新投放目标时使用。图 10 位置更新界面5.无人机状态如图 11为士兵查看为其执行任务的无人机实时状态和飞行数据。士兵需要实时了解无人机状态,或在紧急情况下控制无人机时使用。图 11 无人机状态界面6.个人中心如图 12为士兵个人信息和任务统计的汇总界面,提供系统功能导航入口。士兵需要查看个人任务历史或进入其他功能模块时使用。图 12 个人中心界面7.任务监控界面如图 13为士兵查看当前物资运输任务执行状态的界面,实时掌握任务进度。士兵需要了解无人机运输进度、预计到达时间,或处理紧急情况时使用。图 13 任务监控界面8.系统设置如图 14为单兵终端APP的系统配置界面,提供个性化设置和安全选项。士兵需要调整应用设置或紧急求救时使用。图 14 系统设置界面5.2 后勤保障系统界面设计1.任务调度界面如图 15为后勤调度员的日常工作界面,查看和处理所有待分配的物资需求。后勤调度员需要查看所有待处理需求并分配无人机执行任务时使用。图 15 任务调度界面2.需求详情界面如图 16为查看单个物资需求的详细信息,并进行调度决策的界面。调度员需要详细了解某个需求并做出调度决策时使用。图 16 需求详情界面3.无人机状态界面如图 17为后勤调度员监控所有无人机运行状态的管理界面。调度员需要监控无人机运行状态、处理异常情况或远程控制无人机时使用。图 17 无人机状态界面(后勤保障端) - -=== 第四组软件构思 === -“智途投送”软件系统的需求构思及描述背景介绍近年来,多场局部战争的实战经验反复证明,后勤补给的“最后一公里”已成为制约战场持续作战能力的核心瓶颈。所谓战场后勤“最后一公里”,是指作战物资从后方集散中心输送至前线作战单元、偏远阵地士兵手中的最后一段末端配送路程,该环节直面复杂地形、敌方袭扰、火力封锁、通信中断等多重风险。以下真实战例深刻揭示了这一问题的严峻性:【案例一:以哈战争中的城市战补给难题】 2023年以哈战争中,以军在加沙城市巷战环境遭遇严重后勤困境。狭窄街巷、密集建筑、简易爆炸装置使得传统装甲运输车难以深入城区,补给车队频遭伏击。前线士兵在激烈交火中急需物资,但配送延误成为常态。以军随后成立专门的后勤创新部门,探索利用无人机等新技术手段解决前线补给问题。【案例二:俄乌冲突中的无人机末端投送困境】 2022年俄乌冲突中,前线部队长期面临弹药、食品、急救药品严重短缺。传统有人运输在最后几公里内频繁遭遇炮火覆盖,伤亡率极高。乌军被迫大规模采用无人机进行末端投送,但据CSIS报告指出,由于缺乏统一调度系统和智能路径规划能力,无人机投送效率低下、协调困难,大量物资仍无法及时送达前沿阵地。即便2025年引入大量无人地面车辆,因战场透明度过高和通信中断,末端配送挑战依然严峻。上述战例表明,无论是堑壕战还是城市巷战,后勤补给的“最后一公里”始终是制约作战效能的关键短板。前线士兵在关键物资上面临严重短缺,而传统有人运输伤亡率极高,即便引入无人机等无人平台,也因缺乏统一调度、智能路径规划和安全投放策略,末端配送效率低下、协调困难。面对这一现实挑战,亟需构建一套集需求实时上报、智能路径规划、安全点位投放于一体的智能化末端补给系统,从根本上为破解战场“最后一公里”困局提供帮助。本软件专为解决城市作战环境下“最后一公里”末端补给难题而设计,聚焦无人机物资投送场景。系统支持前线士兵通过终端实时上报需求,后方统一调度无人机执行运输任务;基于城市三维模型智能规划安全飞行路径,自动筛选视线遮蔽的安全投放点位,确保关键物资在复杂城市战场环境下能够隐蔽、安全、及时送达作战人员手中。欲解决问题基于现代战场城市作战场景与后勤保障痛点,小组期望通过该软件系统解决以下核心问题: 需求不通畅:前线作战人员物资需求无法实时上报,后方调度依赖人工无线电沟通,信息传递链路长、易中断,常出现物资错送、延误、短缺等情况。本系统支持前线士兵通过手持终端一键上报物资类型、数量和紧急程度,需求信息经加密通信链路实时回传至后方调度中心,调度指令精准下达至对应运输平台,实现需求-调度-配送全链路信息贯通;配送不安全:传统人力或车辆末端配送面临敌方伏击、空袭与火力封锁,运输人员伤亡率高;运输平台缺乏自主威胁规避能力,遇地形障碍阻挡时任务失败率极高。本系统通过无人机替代有人运输,搭载视觉传感器与IMU等低成本设备,结合动态避障算法,实时识别障碍物并自主调整航线,最大限度降低人员暴露与物资折损风险;策略不灵活:传统无人机运输系统路径策略固定,无法根据战场态势灵活调整。本系统提供多种路径规划策略供前线士兵自主选择,可根据物资紧急程度、敌方火力密度、无人机剩余电量等因素做出最优决策;目标不适应:战场瞬息万变,士兵位置可能发生转移,传统系统目标固定无法响应需求变化。本系统支持动态目标调整,实时同步士兵位置变化,确保物资准确送达最新位置。软件创意小组设计的“智途投送”系统软件,针对城市复杂立体空间特性及战场环境多变的特点,创新性地提出了三个创意点:自主路径规划、路径自主选择与目标实时调整。该软件系统聚焦于城市巷战末端补给最危险的投放与运输环节,确保关键物资在敌方火力封锁下实现隐蔽、精准、自主送达。具体的创意点说明阐述如下。3.1 基于视觉感知的墙体识别与自主路径规划算法为解决城市巷战中高楼遮挡、道路被倒塌建筑阻断导致运输任务失败的问题,本软件系统搭载基于视觉的自主导航算法。系统综合利用普通摄像头与惯性测量单元(IMU)等低成本设备,通过软件算法实现自主通行。针对道路阻断,软件系统调用图像处理算法,实时识别前方墙体、倒塌建筑等大型障碍物的边缘轮廓。当识别到通行路径被墙体阻挡时,系统自动触发路径规划程序,根据墙体轮廓计算可行通的侧向间隙或绕行路线,控制无人机自主转向避开障碍,无需人工干预。3.2 多策略路径规划与士兵自主选择机制由于战场环境多变、任务优先级实时变化,本系统创新性引入路径规划策略选择机制。系统提供“最快到达”、“最安全”、“最省能耗”三种策略选项,每种策略对应不同的优化目标与适用场景,由前线士兵根据实际战况自主选择。该创意突破了传统无人机运输系统路径策略固定、缺乏灵活性的局限,将决策权下放至一线作战人员,使其能够根据当前战场态势(如敌方火力密度、物资紧急程度等)做出最优选择,显著提升了系统对复杂战场环境的适应能力。3.3 动态目标调整与实时位置同步机制针对战场瞬息万变、士兵位置可能发生转移的现实问题,本系统创新性设计动态目标调整机制。在无人机执行任务过程中,系统可以实时接收士兵位置变更信息,动态更新投放位置。当检测到士兵位置偏移超过阈值或士兵主动申请变更时,系统自动判断无人机当前状态(电量、距离、通信范围),若满足条件则重新更新航线,前往新的投放点,否则通知士兵前往原投放点。该创意点解决了传统无人机运输系统目标固定、无法响应需求变化的痛点,确保物资能够准确送达士兵需要的最新位置。系统的组成和部署4.1 系统组成本系统由三大核心子系统构成:单兵终端系统、无人机软件系统、后勤保障系统,各子系统协同配合,共同完成城市巷战中物资运输的完整闭环任务。图 1 “智途投送”软件系统用例图参与者说明:前线士兵:上报物资需求,查看库存信息,接收投放点通知,选择路径策略,更新目标位置,选择投放点。后勤调度员:接收需求,分配无人机任务,监控任务状态,管理物资库存。无人机:执行运输任务,自主路径规划,动态避障,回传状态信息,动态调整航线。(1)单兵终端系统单兵终端系统是前线士兵与后勤保障系统的交互入口,负责需求上报与信息接收。单兵终端系统的硬件和软件组成分别如表1、2所示。表 1 单兵终端系统硬件组成组件说明功能要求智能手表/手环或智能手机士兵随身携带,用于上报需求和接收通知具备网络通信能力,可运行轻量级APP表 2 单兵终端系统软件组成组件功能描述单兵终端APP需求上报界面(物资类型、数量、紧急程度)、库存查询、投放点导航、消息通知接收(2)无人机软件系统无人机软件系统搭载于无人机平台,负责执行运输任务、自主路径规划、动态避障及安全投放点计算。无人机软件系统的硬件组成和软件组成分别如表3、4所示。表 3 无人机系统硬件组成组件功能要求说明多旋翼无人机具备一定载荷能力(建议≥2kg)和续航时间(建议≥20分钟),支持SDK二次开发或开源飞控执行物资运输任务视觉传感器普通摄像头(前置/下视)环境感知、障碍物识别IMU惯性测量单元提供姿态角速度信息视觉导航辅助定位模块GPS/北斗定位,可选RTK增强提供位置信息通信模块Wi-Fi或数传电台与后勤保障系统通信表 4 无人机系统软件组成组件功能描述路径规划算法模块基于城市地图与威胁区域计算安全飞行路径,支持动态重规划安全投放点选择支持模块让士兵选择最后安全的地点进行投发,支持多次调整飞行控制模块接收任务指令、执行航线、反馈状态、应急返航视觉导航模块在GPS拒止环境下提供辅助定位(3)后勤保障系统后勤保障系统部署于后方指挥所,负责需求接收、任务调度、资源管理与状态监控。后勤保障系统的硬件组成和软件组成分别如表5、6所示。表 5 后勤系统硬件组成组件功能要求说明服务器或高性能PC运行调度服务、数据库、算法运算后方指挥所部署网络通信设备局域网/移动网络接入连接各子系统表 6 无人机系统软件组成组件功能描述任务调度模块接收需求、分配无人机、监控任务状态数据库管理模块存储物资库存、无人机状态、任务记录、飞行日志通信服务模块处理与单兵终端、无人机的数据收发,支持加密传输可视化监控模块地图界面显示任务状态、无人机位置、投放点标注城市地图数据建筑轮廓、道路网络、三维模型数据(4) 子系统间数据流图 2 三大子系统间数据流图单兵终端 → 后勤保障系统:上报物资需求(类型、数量、紧急程度、位置)单兵终端 → 后勤保障系统:上报战士标注信息(危险区域、安全区域、战术情报)后勤保障系统 → 无人机:下发任务指令(起点、目标区域、物资信息、路径策略)后勤保障系统 → 无人机:下发标注约束条件(需避开/优先选择的区域)无人机 → 后勤保障系统:回传飞行状态、位置、电量、任务进度后勤保障系统 → 单兵终端:推送投放点位置、预计到达时间4.2 系统部署本系统主要分成三个部分展开部署,分别是后勤保障系统、无人机系统、单兵终端系统,三个系统的部署情况以及系统部署图如下所示。1. 后勤保障系统部署:部署于后方指挥所或移动指挥车内运行调度服务、数据库、通信服务预载城市地图与任务区域三维模型数据2. 无人机部署:存储于便携箱,任务前快速部署机载软件预加载城市三维模型与威胁区域数据与后勤保障系统通过无线网络保持通信3. 单兵终端部署:士兵随身携带智能手表/手环或智能手机安装轻量级终端APP通过移动网络或局域网与后勤保障系统通信4. 依赖条件:卫星定位信号(GPS/北斗)无线通信网络(Wi-Fi、4G/5G或专用数传网络)预先采集的任务区域城市建筑三维模型数据图 3 系统部署图部署说明:后方指挥所:部署后勤服务器与数据库服务器,运行后勤保障系统核心软件。前线作战区域:部署单兵终端设备与无人机平台。各节点通过无线网络(Wi-Fi/4G/数传)进行数据通信。GPS/北斗卫星为终端与无人机提供定位服务软件系统的功能描述为明确系统运行中的职责分工,本节在每个功能描述中标注执行主体:【人工决策】:需要前线士兵或后勤调度员做出判断和选择。【软件执行】:由后勤保障系统或机载软件自动完成。【无人机执行】:由无人机自主完成,无需人工干预。5.1 物资请求与任务规划功能该模块负责前端任务需求的收集与分析,是系统运行的起点。图 4 物资请求与任务规划功能顺序图当前线士兵想要申请物资时,首先在终端APP上选择对应的物资数量、类型以及紧急程度,终端APP根据实际情况向后勤保障系统发送士兵需求,同时查询库存和无人机状态,向后勤调度人员推送物资与无人机调度方案,后勤调度员进行方案的调整和确认,最后根据实际情况派出无人机运输对应的物资。5.2 路径规划策略选择功能针对战场环境多变、任务优先级不同的特点,系统提供多种路径规划策略供前线士兵选择,提高运输任务的灵活性。下面表7展示了三种路径策略选择的具体说明,图5展示了路径策略选择功能的顺序图。前线士兵可以根据战场危险等级、紧急状况等因素综合考虑路径策略选择问题。表 7 路径规划策略说明策略类型优化目标适用场景最快到达优先选择飞行时间最短的路径紧急物资(急救药品、弹药)最安全优先避开威胁区域,选择遮蔽性好的路径高风险区域、敌方火力密集最省能耗优先选择能耗最低的路径,延长续航远距离运输、电量有限图 5 路径规划策略选择功能顺序图默认策略: 若士兵在30秒内未选择,系统默认采用“最安全”策略。5.3 动态目标调整功能针对战场瞬息万变、士兵位置可能发生变化的情况,系统支持在无人机执行任务过程中动态调整目标位置。三种触发条件分别是:前线士兵主动上报位置变更单兵终端检测到位置偏移超过设定阈值(如50米)士兵主动申请变更投放点然而,动态目标实现调整需要一定的约束条件,只有当无人机剩余电量需满足飞往新目标的能耗需求以及新目标位置需在无人机通信范围内时,才能变更物资投放目的地,否则系统通知士兵前往原投放点。图 6 动态目标调整功能顺序图5.4 信息加密与安全传输功能该模块功能主要由软件系统本身执行,负责保障系统通信过程中的数据安全,主要内容有以下三个:数据加密:采用AES-128/256对称加密算法,结合动态密钥协商机制完整性校验:每个数据帧附带校验码,检测篡改或丢失身份认证:双向身份认证机制,防止非法节点接入5.5 自主路径规划与动态避障功能在该模块中,无人机具备自主避障飞行能力,在飞行过程种依托机载摄像头与 IMU 惯性测量单元,精准识别墙体、倒塌建筑等各类障碍物,机载端实时解算可安全通行间隙并动态规划最优绕行航线路径。全程无需人工操控干预,无人机可独立完成避障机动动作。此外,系统还支持通信链路中断冗余运行,在空地通信失联工况下,仍能稳定维持自主飞行与避障作业能力,保障复杂受限环境飞行任务安全连续执行。下面图7展示了系统自主路径规划与动态避障功能的顺序图。图 7 自主路径规划与动态避障功能顺序图5.6 应急处理功能针对执行任务过程种可能出现的通信中断、电量不足等异常情况,本系统提供了一些自动应急处理机制,具体情况以及应急措施说明如下表8所示。表 8 应急处理说明异常情况执行主体应急措施通信中断【无人机执行】自动悬停或按预设逻辑返航电量不足【无人机执行】自动中止任务,返航至出发点GPS信号丢失【无人机执行】切换至视觉导航模式,维持飞行目标区域不可达【软件执行】通知士兵,提供最近可行投放点任务取消【人工决策】士兵或调度员可随时中止任务可行性及潜在风险6.1 可行性分析(1)技术可行性路径规划算法:A*、RRT等经典算法开源实现丰富(如Python的pathfinding库、OMPL库),可直接集成或二次开发。视觉导航与避障:OpenCV提供完整的图像处理工具链,支持边缘检测、轮廓识别、特征提取等功能。无人机控制:主流无人机厂商提供SDK支持航线规划、状态监控;开源飞控(如PX4、ArduPilot)支持自主飞行开发。移动端开发:Android/Wear OS开发技术成熟,网络通信、地图集成、消息推送均有标准方案。(2)硬件可行性无人机:市面上有多款支持SDK二次开发或开源飞控的多旋翼无人机可供选择,功能满足自主飞行与载荷运输需求。终端设备:智能手机、智能手表等设备普及,可直接作为单兵终端使用。服务器:普通PC或笔记本即可运行后勤保障系统软件,无需特殊硬件设备。视觉传感器:普通USB摄像头或无人机搭载摄像头即可满足视觉感知需求,成本低廉。(3)数据可行性城市地图:OpenStreetMap免费开放,可导出建筑轮廓、道路网络等矢量数据。三维模型:可通过手动建模(如Blender)或从公开数据源获取。(4)开发能力可行性本小组具备Python、Java/Kotlin开发能力,熟悉算法实现与移动端开发;可采用模块化开发方式,先完成核心算法仿真验证,再进行硬件集成测试,在有限时间内完成核心功能原型。(5)实验条件可行性考虑到实际无人机飞行实验条件受限,可采用以下替代方案:算法验证:使用仿真环境(如Gazebo、AirSim)进行路径规划算法的验证。视觉算法测试:采集城市环境图像数据集,离线测试墙体识别与障碍检测算法。系统集成测试:小范围空旷场地进行无人机飞行测试,验证通信链路与任务执行流程。6.2 潜在风险分析(1)通信链路风险城市环境建筑遮挡导致无线信号不稳定,无人机可能失联。应对措施:预设通信中断后,无人机自动返航。(2)定位信号风险城市峡谷效应导致GPS信号漂移或丢失,影响航线精度。应对措施:结合视觉导航、IMU惯性导航进行辅助定位。(3)无人机硬件限制载荷与续航有限,单次运输物资量受限。应对措施:合理规划任务半径与物资重量。(4)三维数据精度风险建筑模型精度不足或数据更新滞后可能导致视线自主路径规划计算误差。应对措施:在关键区域进行现场数据校验。(5)视觉算法可靠性风险复杂光照条件、遮挡、纹理缺失等因素可能影响视觉识别准确性。应对措施:采用多传感器融合;设置置信度阈值,低置信度时触发人工介入。(6)实时性风险路径规划需要在有限时间内完成,计算复杂度可能影响响应速度。应对措施:采用分层规划策略,全局路径离线预计算,局部避障实时响应,优化算法效率。(7)动态调整风险动态目标调整过程中,频繁的位置变更可能导致无人机频繁调整航线,影响任务效率。应对措施:设置位置更新最小间隔阈值,或者限制单次任务最大调整次数,超出限制时通知士兵前往原投放点。(8)策略选择风险士兵可能因战场压力无法及时做出策略选择,或选择不当影响任务效果。应对措施:设置默认策略(最安全),超时自动采用该策略。 \ No newline at end of file diff --git a/temp_verify_doc.txt b/temp_verify_doc.txt deleted file mode 100644 index b450ec67..00000000 --- a/temp_verify_doc.txt +++ /dev/null @@ -1,133 +0,0 @@ -1: 智途投送 -2: 声源分析模块(Acoustic Analyzer) -3: 项目开发交接文档 -5: 国防科大计算机学院 23 级软件工程小班 -6: 2026 年 4 月 -8: 一、项目概述 -9: 声源分析模块是「智途投送」无人机软件系统的核心感知构件之一,负责通过麦克风阵列音频信号实现: -10: • 枪炮声识别分类(枪声 / 炮声 / 爆炸声 / 环境噪声) -11: • GCC-PHAT 声源定位(方位角、俯仰角) -12: • 基于能量衰减模型的距离估计 -13: • 多帧威胁跟踪与信息融合 -14: 模块采用 C++17 开发,核心算法零 ROS 依赖,通过 ONNX Runtime 进行神经网络推理,最终作为 ROS1 Noetic 节点部署于 P600 无人机机载电脑。 -15: 二、已完成工作总览 -16: 2.1 代码开发 -17: 已完成全部 34 个代码文件的编写,覆盖 Core 算法层、IO 抽象层、ROS 封装层及配套脚本: -19: 2.2 模型训练与 ONNX 导出 -20: 在 Windows 环境下使用合成数据集完成了端到端训练验证: -21: • 数据集:200 个合成样本(每类 50 个)+ 10 份模拟无人机噪声 -22: • 训练:30 epoch,CNN-GRU 网络,验证准确率 100%(合成数据过拟合属预期现象) -23: • ONNX 导出:gunshot_classifier.onnx(1.9MB,opset 13) -24: • ONNX 验证:枪声识别置信度 97.92% -25: 2.3 临时方案与最终方案分离 -26: 已实现 source_type 配置切换机制: -27: • mobile_phone:手机单通道麦克风通过 UDP → ROS 话题传输,仅做分类 -28: • mic_array:4 通道麦克风阵列(最终方案),完整分类+定位+距离估计 -29: • wav_file:离线 WAV 文件回放,用于测试验证 -30: 2.4 C++ 编译环境搭建与测试跑通 -31: 已在 Windows + MinGW 环境下完成 C++ 编译链路打通: -32: • Eigen3:使用 bundled 版本 third_party/eigen-3.4.0,无需安装 -33: • yaml-cpp:自动检测 conda 环境(C:/Users//miniconda3/Library),CMake 已适配 -34: • ONNX Runtime C++ v1.20.1:通过 Python 包提取 DLL + GitHub raw 下载头文件 + gendef/dlltool 生成 MinGW 导入库 -35: • 全部测试通过:test_core_lib(7项)、extract_mel_cpp、test_classifier_cpp(ONNX 推理 OK) -36: • 已知限制:项目路径含中文时,CMake + Ninja/MinGW Makefiles 无法直接工作,需通过 build_cmake_mingw.bat 自动复制到临时英文目录构建 -37: 2.5 代码 Bug 修复记录 -38: 搭建过程中发现并修复的问题: -39: • gcc_phat_localizer.cpp:缺少 #include ,导致 BDCSVD 不完整类型错误 -40: • threat_tracker.cpp:数据关联更新检测时丢失原有 threat_id,导致多帧跟踪失败 -41: • test_core_lib.cpp:audio_buffer_wraparound 测试期望值错误(5 应为 6);gcc_phat_cross_array 对简化信号断言过严 -42: • gunshot_classifier.cpp/h:升级至 ONNX Runtime C++ v1.20.1 RAII API,适配 wchar_t 路径(Windows) -43: • CMakeLists.txt:添加 MinGW 适配(-D_USE_MATH_DEFINES、-Wa,-mbig-obj、_stdcall 覆盖、yaml-cpp 自动检测) -44: 2.6 离线演示与多通道验证 -45: 已完成完整的离线演示程序(tests/demo_offline.cpp),支持单通道分类与多通道阵列(分类+方位角+距离)一体化测试: -46: • 单通道验证:dataset/val 共 40 个文件,分类准确率 100%(ambient/artillery/explosion/gunshot 各 10 个)。 -47: • 多通道模拟测试:scripts/generate_multichannel_test.py 可按指定方位角(0°–360°)和距离(1–1000m)生成 4 通道十字阵 WAV。 -48: • 多通道验证结果(5 组典型工况): -49: – 方位角:全部 0° 误差(GCC-PHAT 对模拟数据精度极高)。 -50: – 距离:最大误差 18.2m@300m(约 6%),其余 < 2m。 -51: – 分类:全部正确识别为 gunshot,置信度 0.77–0.98。 -52: • 一键演示脚本:run_demo.bat 自动执行核心单元测试 → ONNX 快速推理 → 完整离线流水线。 -53: 2.7 C++/Python 特征提取严格对齐 -54: 为保证 C++ 推理结果与 Python 训练一致,完成了特征提取全流程对齐: -55: • 导出 librosa 0.10.x 的 Mel 滤波器组到二进制文件 models/mel_filter_bank.bin(64×1025),C++ 加载后不再自行构造。 -56: • 统一参数:Hann 窗、preemphasis=0.97、n_fft=2048、hop=512、center=False、pad_to=63 frames(edge 填充)。 -57: • 验证脚本:scripts/verify_feature_consistency.py 对比 C++ 与 Python 输出,最大差异 < 0.008。 -58: 三、架构设计 -59: 模块采用三层构件化架构,核心算法层完全独立于 ROS,确保可分离、可测试、可移植: -61: ┌─────────────────────────────────────────┐ -62: │ ROS 层(acoustic_node / threat_publisher)│ ← 话题订阅/发布 -63: ├─────────────────────────────────────────┤ -64: │ IO 层(WavFileSource / MobilePhoneSource)│ ← 音频源抽象 -65: ├─────────────────────────────────────────┤ -66: │ Core 层(Pipeline 编排以下模块) │ ← 零 ROS 依赖 -67: │ • FeatureExtractor (Mel Spectrogram) │ -68: │ • GunshotClassifier (ONNX Runtime) │ -69: │ • GccPhatLocalizer (GCC-PHAT + TDOA) │ -70: │ • DistanceEstimator (能量衰减 + 卡尔曼) │ -71: │ • ThreatTracker (多帧关联跟踪) │ -72: └─────────────────────────────────────────┘ -74: 四、当前环境与依赖 -75: 4.1 Python 训练环境(Windows 已验证) -77: 4.2 C++ 编译环境(Windows 已配置) -78: • 编译器:g++ (MinGW-W64 15.2.0) 已安装 ✅ -79: • CMake:4.1.0 已安装 ✅ -80: • Eigen3:bundled third_party/eigen-3.4.0 ✅ -81: • ONNX Runtime C++:v1.20.1 已配置(头文件 + DLL + MinGW 导入库)✅ -82: • yaml-cpp:conda 0.8.0 已检测,CMake 自动链接 ✅ -83: • 构建方式: -84: – 快速命令行:build_core_test.bat(一键编译全部测试) -85: – 标准 CMake:build_cmake_mingw.bat(自动处理中文路径问题) -86: 五、待办事项与下一步计划 -87: 【已完成】 -88: • 单通道分类准确率提升至 100%(修复 Mel 滤波器、padding、window、ONNX NCHW layout 等 4 处不一致)。 -89: • GCC-PHAT 方位估计与 SPL 距离估计集成到离线 demo,使用模拟 4ch WAV 验证通过。 -90: • 生成 scripts/generate_multichannel_test.py 及 run_demo.bat 一键演示。 -91: 【待完成】 -92: • [P0] 实机部署:将编译通过的节点部署到 P600 机载电脑(Jetson / x86),验证 ROS 话题发布与订阅。 -93: • [P0] 真实麦克风阵列驱动:接入 4 通道 USB / I2S 麦克风阵列,录制真实环境枪声/炮声样本。 -94: • [P1] 数据集扩充:收集真实场景样本(含环境噪声、混响、多声源叠加),重新训练以降低合成数据过拟合。 -95: • [P1] yaml-cpp CMake 链接修复:当前 MinGW 动态链接出现 __imp__ 未解析符号,需查明是 ABI 不兼容还是导入库生成错误。 -96: • [P2] 距离估计 SPL 校准:当前合成数据使用固定 offset=60dB,真实场景需根据麦克风灵敏度数据 sheet 校准。 -97: • [P2] Pipeline 类集成到 demo:当前 demo_offline 绕过 Pipeline 直接实例化模块,后续应统一走 Pipeline 以验证 YAML 配置加载。 -98: • [P2] 俯仰角估计:当前 GCC-PHAT 仅输出水平面方位角,若阵列有高度差可解俯仰角。 -99: 六、关键配置参数速查 -100: config/acoustic_params.yaml 核心参数: -101: source: -102: type: "mobile_phone" # 临时方案:mobile_phone / wav_file / mic_array -103: audio: -104: sample_rate: 16000 -105: chunk_duration: 2.0 # 分析窗口 2 秒 -106: hop_duration: 0.5 # 步进 0.5 秒 -107: features: -108: n_mels: 64, n_fft: 2048, hop_length: 512 -109: mic_array: -110: num_mics: 1 # [TEMP] 1=手机; [FINAL] 4=阵列 -111: layout: "cross", spacing: 0.15 -112: classifier: -113: model_path: ".../gunshot_classifier.onnx" -114: threshold: 0.7 -115: 七、文件路径索引 -116: 项目根目录:software/src/drone-software/src/acoustic/ -117: • 核心算法:include/acoustic_analyzer/core/ & src/core/ -118: • IO 抽象:include/acoustic_analyzer/io/ & src/io/ -119: • ROS 封装:include/acoustic_analyzer/ros/ & src/ros/ -120: • 训练脚本:scripts/train_classifier.py, export_onnx.py, verify_onnx.py -121: • 手机桥接:scripts/mobile_audio_bridge.py, android_audio_sender.py -122: • 多通道生成:scripts/generate_multichannel_test.py -123: • 特征对齐验证:scripts/verify_feature_consistency.py, verify_val_accuracy.py -124: • 测试程序:tests/test_core_lib.cpp, extract_mel_cpp.cpp, test_classifier_cpp.cpp, demo_offline.cpp -125: • 配置文件:config/acoustic_params.yaml -126: • 模型权重:models/gunshot_classifier.onnx, models/mel_filter_bank.bin, train_output/best_model.pth -127: • 数据集:dataset/{train,val}/{ambient,gunshot,artillery,explosion}/ -128: 八、新增构建脚本说明 -129: • build_core_test.bat:一键命令行编译,适用于快速验证核心算法和 ONNX 推理 -130: 编译目标:test_core_lib.exe / extract_mel_cpp.exe / test_classifier_cpp.exe -131: • build_demo.bat:编译离线演示程序 demo_offline.exe -132: 不依赖 yaml-cpp 和 ROS,直接链接 ONNX Runtime + Eigen,用于快速验证完整流水线。 -133: • build_cmake_mingw.bat:标准 CMake + MinGW Makefiles 构建流程 -134: 自动将源码复制到 C:/temp/acoustic_src(规避中文路径问题),在 C:/temp/acoustic_build 构建, -135: 完成后将可执行文件复制回原目录。适用于需要标准 CMake 流程的场景。 -136: • run_demo.bat:一键运行完整演示 -137: Step 1: 核心单元测试(test_core_lib.exe) -138: Step 2: ONNX 快速推理(test_classifier_cpp.exe) -139: Step 3: 离线流水线验证(demo_offline.exe dataset/val) diff --git a/update_handover_doc.py b/update_handover_doc.py deleted file mode 100644 index 81115278..00000000 --- a/update_handover_doc.py +++ /dev/null @@ -1,245 +0,0 @@ -#!/usr/bin/env python3 -""" -更新声源分析模块_项目交接文档.docx -将本次(2026-05-06)完成的多通道离线演示等工作追加到文档中。 -""" - -from docx import Document -from docx.shared import Pt, RGBColor -from docx.enum.text import WD_PARAGRAPH_ALIGNMENT -import os - -def add_heading(doc, text, level=1): - """添加标题段落""" - p = doc.add_paragraph() - run = p.add_run(text) - run.bold = True - if level == 1: - run.font.size = Pt(16) - elif level == 2: - run.font.size = Pt(14) - else: - run.font.size = Pt(12) - p.alignment = WD_PARAGRAPH_ALIGNMENT.LEFT - return p - -def add_bullet(doc, text, indent=0): - """添加项目符号段落""" - p = doc.add_paragraph(style='List Bullet') - p.paragraph_format.left_indent = Pt(indent * 10) - p.add_run(text) - return p - -def add_normal(doc, text): - p = doc.add_paragraph() - p.add_run(text) - return p - -def main(): - doc_path = '声源分析模块_项目交接文档.docx' - doc = Document(doc_path) - - # ======================================================================== - # 1. 在 "2.5 代码 Bug 修复记录" 之后插入 2.6 小节 - # ======================================================================== - insert_idx = None - for i, para in enumerate(doc.paragraphs): - if para.text.strip().startswith('2.5'): - # 找到 2.5 的最后一项(CMakeLists.txt 那行)之后 - pass - if para.text.strip().startswith('三、架构设计'): - insert_idx = i - break - - if insert_idx is None: - print("ERROR: 未找到插入点(三、架构设计)") - return - - # 由于 python-docx 不支持在特定索引插入段落到 body, - # 我们采用另一种策略:将新内容作为独立段落追加到文档末尾, - # 然后手动调整顺序。但更简单的方法是:直接在 2.5 和 三 之间添加。 - # python-docx 的 add_paragraph 总是追加到末尾,所以我们需要操作 XML。 - # 为了避免 XML 操作复杂性,我们直接将整个文档重新组织: - # 读取所有段落文本 -> 在合适位置插入新文本 -> 重新写入。 - - # 实际上,对于 docx,最安全的方式是: - # 保存一份副本,然后在新段落要插入的位置,使用 paragraphs 列表的 _element 进行 insert。 - paragraphs = doc.paragraphs - - # 找到 2.5 最后一行(CMakeLists.txt)的索引 - idx_after_25 = None - for i, p in enumerate(paragraphs): - if 'CMakeLists.txt' in p.text and 'MinGW' in p.text: - idx_after_25 = i + 1 - break - - if idx_after_25 is None: - # 备用:找到 "三、架构设计" - for i, p in enumerate(paragraphs): - if p.text.strip().startswith('三、架构设计'): - idx_after_25 = i - break - - # 构建要插入的新段落列表 (text, style_name) - new_sections = [] - - # ---- 2.6 离线演示与多通道验证 ---- - new_sections.append(('2.6 离线演示与多通道验证', 'Heading 2')) - new_sections.append(('已完成完整的离线演示程序(tests/demo_offline.cpp),支持单通道分类与多通道阵列(分类+方位角+距离)一体化测试:', None)) - new_sections.append(('', 'List Bullet')) - # 修正:我们无法在 add_paragraph 之后修改之前的内容,所以换个策略 - # 直接在 XML 层级插入 - - # 为了简化,我们把所有段落文本收集起来,重建文档 - all_texts = [] - for p in doc.paragraphs: - style = p.style.name if p.style else None - all_texts.append((p.text, style)) - - # 找到插入位置 - insert_pos = None - for i, (text, style) in enumerate(all_texts): - if text.strip().startswith('三、架构设计'): - insert_pos = i - break - - if insert_pos is None: - print("ERROR: 未找到 '三、架构设计'") - return - - # 准备新内容 - new_content = [] - new_content.append(('2.6 离线演示与多通道验证', 'Heading 2')) - new_content.append(('已完成完整的离线演示程序(tests/demo_offline.cpp),支持单通道分类与多通道阵列(分类+方位角+距离)一体化测试:', None)) - new_content.append(('• 单通道验证:dataset/val 共 40 个文件,分类准确率 100%(ambient/artillery/explosion/gunshot 各 10 个)。', 'List Bullet')) - new_content.append(('• 多通道模拟测试:scripts/generate_multichannel_test.py 可按指定方位角(0°–360°)和距离(1–1000m)生成 4 通道十字阵 WAV。', 'List Bullet')) - new_content.append(('• 多通道验证结果(5 组典型工况):', 'List Bullet')) - new_content.append((' – 方位角:全部 0° 误差(GCC-PHAT 对模拟数据精度极高)。', 'List Bullet')) - new_content.append((' – 距离:最大误差 18.2m@300m(约 6%),其余 < 2m。', 'List Bullet')) - new_content.append((' – 分类:全部正确识别为 gunshot,置信度 0.77–0.98。', 'List Bullet')) - new_content.append(('• 一键演示脚本:run_demo.bat 自动执行核心单元测试 → ONNX 快速推理 → 完整离线流水线。', 'List Bullet')) - - new_content.append(('2.7 C++/Python 特征提取严格对齐', 'Heading 2')) - new_content.append(('为保证 C++ 推理结果与 Python 训练一致,完成了特征提取全流程对齐:', None)) - new_content.append(('• 导出 librosa 0.10.x 的 Mel 滤波器组到二进制文件 models/mel_filter_bank.bin(64×1025),C++ 加载后不再自行构造。', 'List Bullet')) - new_content.append(('• 统一参数:Hann 窗、preemphasis=0.97、n_fft=2048、hop=512、center=False、pad_to=63 frames(edge 填充)。', 'List Bullet')) - new_content.append(('• 验证脚本:scripts/verify_feature_consistency.py 对比 C++ 与 Python 输出,最大差异 < 0.008。', 'List Bullet')) - - # 插入 - all_texts = all_texts[:insert_pos] + new_content + all_texts[insert_pos:] - - # ======================================================================== - # 2. 更新 "五、待办事项与下一步计划" - # ======================================================================== - # 找到第五部分的起止范围 - section5_start = None - section5_end = None - for i, (text, style) in enumerate(all_texts): - if text.strip().startswith('五、待办事项与下一步计划'): - section5_start = i - elif section5_start is not None and text.strip().startswith('六、'): - section5_end = i - break - - if section5_start is not None and section5_end is not None: - # 替换第五部分的内容 - new_section5 = [] - new_section5.append(('五、待办事项与下一步计划', 'Heading 1')) - new_section5.append(('【已完成】', 'Heading 2')) - new_section5.append(('• 单通道分类准确率提升至 100%(修复 Mel 滤波器、padding、window、ONNX NCHW layout 等 4 处不一致)。', 'List Bullet')) - new_section5.append(('• GCC-PHAT 方位估计与 SPL 距离估计集成到离线 demo,使用模拟 4ch WAV 验证通过。', 'List Bullet')) - new_section5.append(('• 生成 scripts/generate_multichannel_test.py 及 run_demo.bat 一键演示。', 'List Bullet')) - new_section5.append(('【待完成】', 'Heading 2')) - new_section5.append(('• [P0] 实机部署:将编译通过的节点部署到 P600 机载电脑(Jetson / x86),验证 ROS 话题发布与订阅。', 'List Bullet')) - new_section5.append(('• [P0] 真实麦克风阵列驱动:接入 4 通道 USB / I2S 麦克风阵列,录制真实环境枪声/炮声样本。', 'List Bullet')) - new_section5.append(('• [P1] 数据集扩充:收集真实场景样本(含环境噪声、混响、多声源叠加),重新训练以降低合成数据过拟合。', 'List Bullet')) - new_section5.append(('• [P1] yaml-cpp CMake 链接修复:当前 MinGW 动态链接出现 __imp__ 未解析符号,需查明是 ABI 不兼容还是导入库生成错误。', 'List Bullet')) - new_section5.append(('• [P2] 距离估计 SPL 校准:当前合成数据使用固定 offset=60dB,真实场景需根据麦克风灵敏度数据 sheet 校准。', 'List Bullet')) - new_section5.append(('• [P2] Pipeline 类集成到 demo:当前 demo_offline 绕过 Pipeline 直接实例化模块,后续应统一走 Pipeline 以验证 YAML 配置加载。', 'List Bullet')) - new_section5.append(('• [P2] 俯仰角估计:当前 GCC-PHAT 仅输出水平面方位角,若阵列有高度差可解俯仰角。', 'List Bullet')) - all_texts = all_texts[:section5_start] + new_section5 + all_texts[section5_end:] - - # ======================================================================== - # 3. 更新 "七、文件路径索引" - # ======================================================================== - section7_start = None - section7_end = None - for i, (text, style) in enumerate(all_texts): - if text.strip().startswith('七、文件路径索引'): - section7_start = i - elif section7_start is not None and text.strip().startswith('八、'): - section7_end = i - break - - if section7_start is not None and section7_end is not None: - new_section7 = [] - new_section7.append(('七、文件路径索引', 'Heading 1')) - new_section7.append(('项目根目录:software/src/drone-software/src/acoustic/', None)) - new_section7.append(('• 核心算法:include/acoustic_analyzer/core/ & src/core/', 'List Bullet')) - new_section7.append(('• IO 抽象:include/acoustic_analyzer/io/ & src/io/', 'List Bullet')) - new_section7.append(('• ROS 封装:include/acoustic_analyzer/ros/ & src/ros/', 'List Bullet')) - new_section7.append(('• 训练脚本:scripts/train_classifier.py, export_onnx.py, verify_onnx.py', 'List Bullet')) - new_section7.append(('• 手机桥接:scripts/mobile_audio_bridge.py, android_audio_sender.py', 'List Bullet')) - new_section7.append(('• 多通道生成:scripts/generate_multichannel_test.py', 'List Bullet')) - new_section7.append(('• 特征对齐验证:scripts/verify_feature_consistency.py, verify_val_accuracy.py', 'List Bullet')) - new_section7.append(('• 测试程序:tests/test_core_lib.cpp, extract_mel_cpp.cpp, test_classifier_cpp.cpp, demo_offline.cpp', 'List Bullet')) - new_section7.append(('• 配置文件:config/acoustic_params.yaml', 'List Bullet')) - new_section7.append(('• 模型权重:models/gunshot_classifier.onnx, models/mel_filter_bank.bin, train_output/best_model.pth', 'List Bullet')) - new_section7.append(('• 数据集:dataset/{train,val}/{ambient,gunshot,artillery,explosion}/', 'List Bullet')) - all_texts = all_texts[:section7_start] + new_section7 + all_texts[section7_end:] - - # ======================================================================== - # 4. 更新 "八、新增构建脚本说明" - # ======================================================================== - section8_start = None - section8_end = None - for i, (text, style) in enumerate(all_texts): - if text.strip().startswith('八、新增构建脚本说明'): - section8_start = i - elif section8_start is not None and (text.strip().startswith('AI 助手') or text.strip().startswith('附录') or i == len(all_texts)-1): - section8_end = i if text.strip() else i - if i == len(all_texts)-1: - section8_end = len(all_texts) - break - if section8_start is not None and section8_end is None: - section8_end = len(all_texts) - - if section8_start is not None and section8_end is not None: - new_section8 = [] - new_section8.append(('八、新增构建脚本说明', 'Heading 1')) - new_section8.append(('• build_core_test.bat:一键命令行编译,适用于快速验证核心算法和 ONNX 推理', 'List Bullet')) - new_section8.append((' 编译目标:test_core_lib.exe / extract_mel_cpp.exe / test_classifier_cpp.exe', 'List Bullet')) - new_section8.append(('• build_demo.bat:编译离线演示程序 demo_offline.exe', 'List Bullet')) - new_section8.append((' 不依赖 yaml-cpp 和 ROS,直接链接 ONNX Runtime + Eigen,用于快速验证完整流水线。', 'List Bullet')) - new_section8.append(('• build_cmake_mingw.bat:标准 CMake + MinGW Makefiles 构建流程', 'List Bullet')) - new_section8.append((' 自动将源码复制到 C:/temp/acoustic_src(规避中文路径问题),在 C:/temp/acoustic_build 构建,', 'List Bullet')) - new_section8.append((' 完成后将可执行文件复制回原目录。适用于需要标准 CMake 流程的场景。', 'List Bullet')) - new_section8.append(('• run_demo.bat:一键运行完整演示', 'List Bullet')) - new_section8.append((' Step 1: 核心单元测试(test_core_lib.exe)', 'List Bullet')) - new_section8.append((' Step 2: ONNX 快速推理(test_classifier_cpp.exe)', 'List Bullet')) - new_section8.append((' Step 3: 离线流水线验证(demo_offline.exe dataset/val)', 'List Bullet')) - all_texts = all_texts[:section8_start] + new_section8 + all_texts[section8_end:] - - # ======================================================================== - # 重建文档 - # ======================================================================== - new_doc = Document() - for text, style_name in all_texts: - if not text and style_name == 'List Bullet': - # 空项目符号,跳过 - continue - if style_name: - try: - p = new_doc.add_paragraph(text, style=style_name) - except: - p = new_doc.add_paragraph(text) - else: - p = new_doc.add_paragraph(text) - - # 保留原始文档的页眉页脚等信息?简化处理:不保留 - output_path = '声源分析模块_项目交接文档.docx' - new_doc.save(output_path) - print(f"[OK] 文档已更新: {output_path}") - -if __name__ == '__main__': - main() diff --git a/前后端对接文档.md b/前后端对接文档.md deleted file mode 100644 index f7d78d2b..00000000 --- a/前后端对接文档.md +++ /dev/null @@ -1,727 +0,0 @@ -# 智途投送系统 — 前后端对接文档 - -> 版本:v1.0 -> 服务器:阿里云 ECS `121.41.216.243` -> 系统:Ubuntu 24.04 -> 数据库:SQLite(文件 `/opt/zhitu/zhitu.db`) - ---- - -## 一、服务器信息 - -| 项目 | 值 | -|------|-----| -| 公网 IP | `121.41.216.243` | -| 访问方式 | `http://121.41.216.243`(Nginx 80 端口) | -| 直连后端 | `http://121.41.216.243:5000`(Gunicorn) | -| 通信协议 | HTTP(明文,未配置 HTTPS) | - -**推荐**:所有接口统一走 `http://121.41.216.243/api/xxx`,无需加 `:5000`。 - ---- - -## 二、认证说明 - -### 2.1 Token 机制 - -- 登录成功后,后端返回 `token` 字符串 -- 后续所有需要认证的接口,需在请求头中携带: - -```http -X-Auth-Token: -``` - -或在 URL 参数中携带(调试用): - -```http -GET /api/task/current?soldier_id=xxx&token= -``` - -### 2.2 免认证接口(无需 Token) - -以下接口可直接访问,无需登录: - -| 接口 | 说明 | -|------|------| -| `GET /api/ping` | 存活检测 | -| `GET /api/auth/accounts` | 查看所有账号 | -| `GET /api/demands` | 查看所有需求 | - ---- - -## 三、API 接口总览 - -### 3.1 账号系统 - -#### ① 注册账号 - -```http -POST /api/auth/register -Content-Type: application/json -``` - -**请求体**: - -```json -{ - "soldier_id": "soldier_001", - "password": "123456", - "name": "张三", - "unit": "第3步兵师/1连", - "role": "狙击手" -} -``` - -**响应**: - -```json -// 成功 -{ "ok": true, "message": "注册成功" } - -// 失败 -{ "ok": false, "error": "该士兵编号已注册" } // 409 -{ "ok": false, "error": "士兵编号、密码、姓名不能为空" } // 400 -``` - ---- - -#### ② 登录 - -```http -POST /api/auth/login -Content-Type: application/json -``` - -**请求体**: - -```json -{ - "soldier_id": "soldier_001", - "password": "123456" -} -``` - -**响应**: - -```json -// 成功 -{ - "ok": true, - "token": "a1b2c3d4e5f6...", - "soldier_id": "soldier_001", - "name": "张三", - "unit": "第3步兵师/1连", - "role": "狙击手" -} - -// 失败 -{ "ok": false, "error": "士兵编号不存在" } // 404 -{ "ok": false, "error": "密码错误" } // 401 -``` - ---- - -#### ③ 查看当前登录用户 - -```http -GET /api/auth/me -X-Auth-Token: -``` - -**响应**: - -```json -{ - "ok": true, - "user": { - "soldier_id": "soldier_001", - "name": "张三", - "unit": "第3步兵师/1连", - "role": "狙击手" - } -} -``` - ---- - -#### ④ 查看所有账号(免认证) - -```http -GET /api/auth/accounts -``` - -**响应**: - -```json -{ - "accounts": [ - { "soldier_id": "soldier_001", "name": "张三", "unit": "...", "role": "..." }, - { "soldier_id": "soldier_002", "name": "李四", "unit": "...", "role": "..." } - ] -} -``` - ---- - -### 3.2 士兵位置 - -#### ① 上报位置(需认证) - -```http -POST /api/soldier/location -Content-Type: application/json -X-Auth-Token: -``` - -**请求体**: - -```json -{ - "id": "soldier_001", - "name": "张三", - "lat": 30.1234, - "lng": 120.5678 -} -``` - -**响应**: - -```json -{ "ok": true } -``` - ---- - -#### ② 获取所有士兵位置(免认证) - -```http -GET /api/soldiers -``` - -**响应**: - -```json -{ - "soldiers": [ - { - "soldier_id": "soldier_001", - "name": "张三", - "lat": 30.1234, - "lng": 120.5678, - "updated_at": "2026-05-23 12:00:00" - } - ] -} -``` - ---- - -### 3.3 物资需求 - -#### ① 上报需求(需认证) - -```http -POST /api/demand -Content-Type: application/json -X-Auth-Token: -``` - -**请求体**: - -```json -{ - "soldier_id": "soldier_001", - "soldier_name": "张三", - "type": "弹药", - "quantity": 20, - "unit": "发", - "urgency": "紧急", - "drop_point": { "lat": 30.1234, "lng": 120.5678 } -} -``` - -> `drop_point` 可为空或字符串,后端会自动从 `soldiers` 表补全当前位置。 - -**响应**: - -```json -{ "ok": true, "id": "REQ-001" } -``` - ---- - -#### ② 查看需求列表(免认证) - -```http -GET /api/demands?soldier_id=soldier_001 -``` - -**参数**: - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| `soldier_id` | string | 否 | 指定士兵 ID,不填则返回所有"待处理"需求 | - -**响应**: - -```json -{ - "demands": [ - { - "id": "REQ-001", - "soldier_id": "soldier_001", - "soldier_name": "张三", - "type": "弹药补给", - "items": "弹药 × 20发", - "quantity": 20, - "unit": "发", - "urgency": "紧急", - "status": "待处理", - "lat": 30.1234, - "lng": 120.5678, - "created_at": "2026-05-23 12:00:00" - } - ] -} -``` - ---- - -#### ③ 查看单个需求(需认证) - -```http -GET /api/demands/REQ-001 -X-Auth-Token: -``` - -**响应**: - -```json -{ "demand": { ... } } -``` - ---- - -### 3.4 任务调度 - -#### ① 派发任务(需认证) - -```http -POST /api/task/dispatch -Content-Type: application/json -X-Auth-Token: -``` - -**请求体**: - -```json -{ - "soldier_id": "soldier_001", - "soldier_name": "张三", - "type": "弹药投送", - "demand_id": "REQ-001", - "start_name": "后方阵地", - "target_name": "A区街角12号", - "start_lat": 30.0, - "start_lng": 120.0, - "end_lat": 30.1234, - "end_lng": 120.5678, - "safety_score": 90 -} -``` - -**响应**: - -```json -{ - "ok": true, - "task": { - "id": "#001", - "soldier_id": "soldier_001", - "type": "弹药投送", - "status": "执行中", - "progress": 0, - "eta": "计算中...", - "remain_time": "计算中...", - "start_name": "后方阵地", - "target_name": "A区街角12号", - "start_lat": 30.0, - "start_lng": 120.0, - "end_lat": 30.1234, - "end_lng": 120.5678, - "safety_score": 90, - "created_at": "2026-05-23 12:00:00" - } -} -``` - -> 派发任务后,对应需求 `REQ-001` 的 `status` 会自动更新为 `"已调度"`。 - ---- - -#### ② 获取当前任务(需认证) - -```http -GET /api/task/current?soldier_id=soldier_001 -X-Auth-Token: -``` - -**响应**: - -```json -{ - "task": { - "id": "#001", - "status": "执行中", - "progress": 50, - "eta": "2分钟", - ... - } -} - -// 无任务时 -{ - "task": { - "id": "#--", "status": "无任务", "progress": 0, - "eta": "--", "remain_time": "--", - "start_name": "--", "target_name": "--", "safety_score": 0 - } -} -``` - ---- - -#### ③ 更新任务进度(需认证) - -```http -POST /api/task/update -Content-Type: application/json -X-Auth-Token: -``` - -**请求体**: - -```json -{ - "soldier_id": "soldier_001", - "progress": 75, - "status": "执行中", - "eta": "1分钟", - "remain_time": "60秒" -} -``` - -**响应**: - -```json -{ "ok": true, "task": { ... } } -``` - ---- - -### 3.5 投放点 - -#### ① 获取投放点列表(免认证) - -```http -GET /api/drop-points -``` - -**响应**: - -```json -{ - "drop_points": [ - { "id": 1, "name": "A区街角12号", "lat": 30.1234, "lng": 120.5678 } - ] -} -``` - ---- - -#### ② 添加投放点(需认证) - -```http -POST /api/drop-point -Content-Type: application/json -X-Auth-Token: -``` - -**请求体**: - -```json -{ - "name": "B区道路", - "lat": 30.2345, - "lng": 120.6789 -} -``` - -**响应**: - -```json -{ "ok": true } -``` - ---- - -### 3.6 危险区域 - -#### ① 查看危险区域(免认证) - -```http -GET /api/danger-zones -``` - -**响应**: - -```json -{ - "danger_zones": [ - { - "id": 1, - "lat": 30.1234, - "lng": 120.5678, - "radius": 100, - "description": "士兵求救: 张三", - "created_at": "2026-05-23 12:00:00" - } - ] -} -``` - ---- - -#### ② 添加危险区域(需认证) - -```http -POST /api/danger-zones -Content-Type: application/json -X-Auth-Token: -``` - -**请求体**: - -```json -{ - "lat": 30.1234, - "lng": 120.5678, - "radius": 100, - "description": "B区道路(危险区域)" -} -``` - -**响应**: - -```json -{ "ok": true, "id": 1 } -``` - ---- - -### 3.7 SOS 求救 - -#### ① 发送求救(需认证) - -```http -POST /api/sos -Content-Type: application/json -X-Auth-Token: -``` - -**请求体**: - -```json -{ - "soldier_id": "soldier_001", - "soldier_name": "张三", - "lat": 30.1234, - "lng": 120.5678 -} -``` - -**响应**: - -```json -{ "ok": true } -``` - -> 发送求救后,系统会自动在危险区域表中添加一个以士兵位置为中心、半径 100 米的危险区域。 - ---- - -### 3.8 无人机状态(演示数据) - -#### ① 获取无人机状态(免认证) - -```http -GET /api/drone/status -``` - -**响应**: - -```json -{ - "status": { - "battery": 85, - "altitude": 120, - "speed": 15, - "position": { "lat": 30.1234, "lng": 120.5678 } - } -} -``` - ---- - -#### ② 获取无人机日志(免认证) - -```http -GET /api/drone/logs -``` - -**响应**: - -```json -{ - "logs": [ - { "time": "12:25:30", "message": "到达投放点" }, - { "time": "12:20:45", "message": "接收任务指令" }, - { "time": "12:10:00", "message": "任务分配" } - ] -} -``` - ---- - -### 3.9 系统状态 - -#### ① 存活检测(免认证) - -```http -GET /api/ping -``` - -**响应**: - -```json -{ "ok": true, "message": "智途投送后端运行正常" } -``` - ---- - -## 四、数据库表结构 - -### 4.1 accounts(账号表) - -| 字段 | 类型 | 说明 | -|------|------|------| -| `soldier_id` | TEXT PK | 士兵编号 | -| `password_hash` | TEXT | Werkzeug 哈希密码 | -| `name` | TEXT | 姓名 | -| `unit` | TEXT | 单位 | -| `role` | TEXT | 角色 | -| `created_at` | TEXT | 注册时间 | - -### 4.2 tokens(登录令牌表) - -| 字段 | 类型 | 说明 | -|------|------|------| -| `token` | TEXT PK | 随机 Token | -| `soldier_id` | TEXT | 士兵编号 | -| `name` | TEXT | 姓名 | -| `unit` | TEXT | 单位 | -| `role` | TEXT | 角色 | -| `created_at` | TEXT | 生成时间 | - -### 4.3 demands(物资需求表) - -| 字段 | 类型 | 说明 | -|------|------|------| -| `id` | TEXT PK | 需求编号(如 REQ-001) | -| `soldier_id` | TEXT | 上报士兵 | -| `soldier_name` | TEXT | 士兵姓名 | -| `type` | TEXT | 物资类型(如"弹药补给") | -| `items` | TEXT | 物资描述(如"弹药 × 20发") | -| `quantity` | INTEGER | 数量 | -| `unit` | TEXT | 单位 | -| `urgency` | TEXT | 紧急程度 | -| `status` | TEXT | 状态:待处理/已调度/已完成 | -| `lat` | REAL | 纬度 | -| `lng` | REAL | 经度 | -| `created_at` | TEXT | 创建时间 | - -### 4.4 tasks(任务表) - -| 字段 | 类型 | 说明 | -|------|------|------| -| `id` | TEXT PK | 任务编号(如 #001) | -| `soldier_id` | TEXT | 目标士兵 | -| `soldier_name` | TEXT | 士兵姓名 | -| `type` | TEXT | 任务类型 | -| `status` | TEXT | 状态 | -| `progress` | INTEGER | 进度 0-100 | -| `eta` | TEXT | 预计到达时间 | -| `remain_time` | TEXT | 剩余时间 | -| `start_name/target_name` | TEXT | 起止点名称 | -| `start_lat/lng` | REAL | 起点坐标 | -| `end_lat/lng` | REAL | 终点坐标 | -| `safety_score` | INTEGER | 安全评分 | -| `created_at` | TEXT | 创建时间 | - -### 4.5 soldiers(士兵位置表) - -| 字段 | 类型 | 说明 | -|------|------|------| -| `soldier_id` | TEXT PK | 士兵编号 | -| `name` | TEXT | 姓名 | -| `lat` | REAL | 纬度 | -| `lng` | REAL | 经度 | -| `updated_at` | TEXT | 更新时间 | - -### 4.6 danger_zones(危险区域表) - -| 字段 | 类型 | 说明 | -|------|------|------| -| `id` | INTEGER PK AI | 自增 ID | -| `lat` | REAL | 纬度 | -| `lng` | REAL | 经度 | -| `radius` | REAL | 半径(米) | -| `description` | TEXT | 描述 | -| `created_at` | TEXT | 创建时间 | - -### 4.7 sos_alerts(求救记录表) - -| 字段 | 类型 | 说明 | -|------|------|------| -| `id` | INTEGER PK AI | 自增 ID | -| `soldier_id` | TEXT | 士兵编号 | -| `soldier_name` | TEXT | 姓名 | -| `lat` | REAL | 纬度 | -| `lng` | REAL | 经度 | -| `alert_time` | TEXT | 求救时间 | -| `handled` | INTEGER | 是否已处理(0/1) | - ---- - -## 五、错误码速查 - -| HTTP 状态码 | 含义 | 典型场景 | -|-------------|------|----------| -| 200 | 成功 | 正常响应 | -| 400 | 请求参数错误 | 缺少必填字段 | -| 401 | 未认证 | Token 无效或缺失 | -| 404 | 资源不存在 | 士兵编号不存在、需求不存在 | -| 409 | 冲突 | 账号已注册 | -| 500 | 服务器内部错误 | 代码异常 | - ---- - -## 六、联系 - -- 后端维护:赵昌 -- 服务器 IP:`121.41.216.243` -- 操作手册:`software/后端操作手册.md` - ---- - -*文档生成时间:2026-05-23* diff --git a/单兵终端+声源分析_问题清单.md b/单兵终端+声源分析_问题清单.md deleted file mode 100644 index 8f075b72..00000000 --- a/单兵终端+声源分析_问题清单.md +++ /dev/null @@ -1,142 +0,0 @@ -# 单兵终端APP + 声源分析模块 问题清单 - -> 评估范围:仅评估你们组负责的两个模块 -> 评估时间:2026-05-23 - ---- - -## 一、单兵终端APP 问题清单 - -### 🔴 严重问题(演示前必须修复) - -| # | 问题 | 位置 | 影响 | 修复方式 | -|---|------|------|------|----------| -| 1 | **HTML 语法错误** — `1` 多余字符 | `index.html:471` | DOM 解析异常,底部导航栏下方出现无意义文本 | 删除 `` 后的 `1` | -| 2 | **调用不存在函数** — `toggleTheme`、`showChangePasswordModal`、`selectDropPointFromMap` | `index.html:237,426,436` | 用户点击直接抛出 `TypeError`,APP 崩溃 | 方案A:在 `app.js` 中补齐这 3 个函数
方案B:从 `index.html` 中移除这 3 处 `onclick` 绑定 | -| 3 | **数量验证逻辑漏洞** — `"abc" < 1` 为 `false` | `js/app.js:287` | 输入非数字(如"abc")绕过验证,`parseInt` 生成 `NaN` 发送到后端导致 500 | ```javascript -const num = parseInt(qty, 10); -if (isNaN(num) || num < 1) { showToast('请输入有效数量'); return; } -``` | -| 4 | **高德地图 API Key 硬编码泄露** | `js/location.js:22,66` | Key 被盗用产生额外费用 | 从代码中删除硬编码 Key,改为从配置文件读取 | -| 5 | **DOM 操作空值保护缺失** — `loadDroneStatus` | `js/app.js:547-557` | 元素不存在时抛出 `TypeError` | 统一添加 `if (el) el.textContent = ...` | -| 6 | **敏感凭证明文存储** — `auth_token` 存 `localStorage` | `js/app.js:196`, `js/api.js:8` | XSS 攻击可直接窃取 Token | 改为 `sessionStorage`,或实现 Token 自动刷新 | -| 7 | **路由栈无限增长** — `pageStack` 只有 push | `js/app.js:75-123` | 内存泄漏,长时间使用后卡顿 | 登录成功用 `replace` 而非 `push`;限制栈深度 | -| 8 | **后台轮询未暂停** | `js/app.js:715`, `js/location.js:509` | 耗电、流量浪费 | 监听 `visibilitychange`,隐藏时 `clearInterval` | -| 9 | **请求超时过短** — 统一 5 秒 | `js/api.js:17` | 弱网环境下频繁超时 | 关键接口改为 10 秒,非关键保持 5 秒 | - -### 🟡 一般问题(建议修复) - -| # | 问题 | 位置 | 影响 | -|---|------|------|------| -| 10 | **重复嵌套目录** — `js/js/`、`www/js/js/` | 全项目 | 构建脚本路径配置错误,APK 体积增大 | -| 11 | **登录后未清空密码** | `js/app.js:181-213` | 密码在内存中持续存在 | -| 12 | **Mock 数据字段缺失** — `getMockDropPoints` 无 `lat`/`lng` | `js/api.js:177-183` | 地图定位到 `(0, 0)` | -| 13 | **`setInterval` async 未防并发** | `js/location.js:514` | 网络阻塞时请求堆积 | -| 14 | **位置上报失败静默吞掉** | `js/location.js:520-528` | 用户不知位置是否同步成功 | -| 15 | **网络/电量为静态假数据** | `index.html:99-100` | UI 永远显示 `--` | -| 16 | **偏移距离使用随机数** | `js/app.js:636-637` | `Math.random() * 100` 误导用户 | - -### 🟢 建议(优化项) - -| # | 建议 | 说明 | -|---|------|------| -| 17 | 删除 `rememberMe` 复选框 | 代码完全未实现,纯摆设 | -| 18 | 统一错误码体系 | 区分网络超时/500/认证失效/业务错误 | -| 19 | 地图实例缓存 | 避免每次进入页面销毁重建地图 | - ---- - -## 二、声源分析模块(acoustic)问题清单 - -### 🔴 严重问题(演示前必须修复) - -| # | 问题 | 位置 | 影响 | 修复方式 | -|---|------|------|------|----------| -| 1 | **`AudioBuffer` 除零崩溃** — `capacity_frames_ = 0` 时 `% 0` | `src/core/audio_buffer.cpp:24` | 构造传入 0 时程序崩溃 | 构造函数加 `assert(capacity_samples > 0)` | -| 2 | **`AudioBuffer` 假线程安全** — 头文件声明线程安全但实现无同步 | `include/acoustic_analyzer/core/audio_buffer.h:14` | 多线程调用时数据竞争、内存损坏 | 将 `head_`/`tail_`/`size_` 改为 `std::atomic` 或加 `std::mutex` | -| 3 | **GCC-PHAT 整数溢出** — `int nfft` 左移可能溢出为负数 | `src/core/gcc_phat_localizer.cpp:88-133` | 大输入时死循环或分配负尺寸数组 | 循环索引统一用 `std::size_t`;对 `nfft` 加上限检查 | -| 4 | **YAML 路径不展开** — `$(find pkg)` 语法原样传入 | `config/acoustic_params.yaml:49-50`
`src/ros/acoustic_node.cpp:77-78` | 模型加载失败,检测流水线静默失效,永远输出 "unknown" | ```cpp -std::string pkg_path = ros::package::getPath("acoustic_analyzer"); -params_.model_path = pkg_path + "/models/gunshot_classifier.onnx"; -``` | -| 5 | **UDP 接收队列无界** — `buffer_` 无限增长 | `src/io/mobile_phone_source.cpp:69-95` | 消费慢时内存耗尽 | 设置队列上限,超限时丢弃最旧数据 | -| 6 | **C++ 多模态融合未订阅声学话题** ❗ | `src/多模态融合/cpp/src/main.cpp` | 声学节点发布的 `/acoustic/threats` 无人消费,声源数据无法参与融合避障 | 在融合节点的 `setup_ros()` 中增加:
```cpp -ros::Subscriber acoustic_sub_ = nh.subscribe("/acoustic/threats", 5, - &ThreatFusionNode::acoustic_threats_cb, this); -``` | - -### 🟡 一般问题(建议修复) - -| # | 问题 | 位置 | 影响 | -|---|------|------|------| -| 7 | **ONNX 节点名硬编码** — `"input"`/`"output"` | `src/core/gunshot_classifier.cpp:170-172` | 模型节点名不同时 `session->Run` 失败 | -| 8 | **Mel 滤波器组路径硬编码** — 相对路径 `"models/..."` | `src/core/feature_extractor.cpp:33` | 工作目录不同时找不到文件 | -| 9 | **魔法数字 `63`** — 目标帧数与模型强耦合 | `src/core/feature_extractor.cpp:124` | 更换模型需重新编译 | -| 10 | **分类器与定位器输入来源不一致** | `src/core/pipeline.cpp:130-149` | 分类器看 0.5s,定位器看 2s,精度下降 | -| 11 | **`Predict` 对空矩阵无校验** | `src/core/gunshot_classifier.cpp:155` | 传入空矩阵时行为未定义 | -| 12 | **demo 参数解析无异常保护** | `tests/demo_offline.cpp:200` | 输入非数字时崩溃 | -| 13 | **WAV 头解析依赖未打包结构体** | `src/io/wav_file_source.cpp:48-50` | 编译器插入填充时解析失败 | -| 14 | **缺少启动自检** — 模型加载失败不退出 | `src/ros/acoustic_node.cpp:63-85` | 节点启动后永远输出假数据 | -| 15 | **`CMakeLists.txt` 缺少 onnxruntime 目录** | `CMakeLists.txt:75` | 首次克隆构建失败 | -| 16 | **`package.xml` 未声明 yaml-cpp 依赖** | `package.xml` | `rosdep` 安装时遗漏 | - -### 🟢 建议(优化项) - -| # | 建议 | 说明 | -|---|------|------| -| 17 | 统一 ROS 话题命名空间 | 声学节点应支持 UAV 命名空间前缀,如 `/uav1/acoustic/threats` | -| 18 | 增加诊断心跳 | 发布 `DiagnosticArray`,报告模型加载状态、推理耗时 | -| 19 | 将 VAD 门限等参数移入配置 | `-60.0f dB`、`zcr_rate` 等不应写死在代码中 | -| 20 | 声速 `343.0f` 作为配置参数 | 不同温度/海拔下声速变化 | - ---- - -## 三、两个模块之间的关联问题 - -### 问题 1:后端与声源模块零集成 ❌ - -- **现状**:后端 `app.py` 没有任何与声源分析模块的接口 -- **影响**:单兵APP无法接收声源威胁告警 -- **建议**:如需 APP 接收声源告警,后端应订阅 ROS `/acoustic/threats` 话题,通过 WebSocket 推送或轮询接口发送到 APP - -### 问题 2:后端无人机状态是演示数据 ⚠️ - -- **现状**:`_drone_status` 和 `_drone_logs` 是内存变量,非真实无人机数据 -- **影响**:单兵APP看到的无人机状态是静态假数据 -- **说明**:这是整体架构设计(电脑端前端直连 rosbridge),不属你们模块的责任范围,但需在演示时明确说明 - ---- - -## 四、优先修复清单(演示前) - -### 单兵终端(Top 5) -1. 删除 `index.html:471` 的 `1` -2. 补齐/移除不存在的函数调用 -3. 修复数量验证逻辑 -4. 移除硬编码高德 Key -5. 为 DOM 操作加空值保护 - -### 声源分析(Top 5) -1. 修复 `AudioBuffer` 除零和线程安全 -2. 修复 YAML 路径 `$(find)` 不展开问题 -3. **在 C++ 多模态融合节点中订阅 `/acoustic/threats`** -4. 修复 GCC-PHAT 整数溢出 -5. 为 UDP 接收队列加容量上限 - ---- - -## 五、演示注意事项 - -| 场景 | 预期表现 | 风险点 | -|------|----------|--------| -| 士兵登录APP | 正常 | Token 过期需重新登录 | -| 上报物资需求 | 正常 | 数量输入非数字可能崩溃 | -| 查看无人机状态 | 显示静态演示数据 | 需提前说明这是演示数据 | -| 声源检测 → 融合避障 | **可能无法工作** | 融合节点未订阅声学话题 | -| SOS求救 | 正常 | 会自动标记危险区域 | - -**特别提醒**:声源分析模块虽然在离线 demo 中能正常运行,但在完整系统链路中**无法将声源数据送入多模态融合**,这是你们组需要与其他组协调修复的关键集成点。 - ---- - -*报告生成时间:2026-05-23* diff --git a/单兵终端APP_架构与功能实现说明.docx b/单兵终端APP_架构与功能实现说明.docx deleted file mode 100644 index 6702ec90..00000000 Binary files a/单兵终端APP_架构与功能实现说明.docx and /dev/null differ diff --git a/后端操作手册.md b/后端操作手册.md deleted file mode 100644 index 1d933568..00000000 --- a/后端操作手册.md +++ /dev/null @@ -1,146 +0,0 @@ -# 智途投送后端操作手册 - -> 服务器:阿里云 ECS `121.41.216.243`(Ubuntu 24.04) -> 部署路径:`/opt/zhitu/` -> 服务名:`zhitu.service` -> 数据库:SQLite `/opt/zhitu/zhitu.db` - ---- - -## 1. 连接服务器 - -```bash -ssh root@121.41.216.243 -# 输入密码 -``` - ---- - -## 2. 服务启停(最常用) - -| 操作 | 命令 | -|------|------| -| 查看状态 | `systemctl status zhitu` | -| 启动服务 | `systemctl start zhitu` | -| 停止服务 | `systemctl stop zhitu` | -| 重启服务 | `systemctl restart zhitu` | -| 重载配置 | `systemctl daemon-reload` | -| 开机自启 | `systemctl enable zhitu`(已配置)| - ---- - -## 3. 查看日志(排错必备) - -```bash -# 查看最新 50 行日志 -journalctl -u zhitu -n 50 - -# 实时跟踪日志(调试时用,按 Ctrl+C 退出) -journalctl -u zhitu -f -``` - ---- - -## 4. 改 Worker 数量为 1(避免 SQLite 并发锁) - -当前配置为 2 个 worker,SQLite 并发写入时可能锁竞争导致请求卡住,建议改为 1 个: - -```bash -sed -i 's/-w 2/-w 1/' /etc/systemd/system/zhitu.service -systemctl daemon-reload -systemctl restart zhitu -systemctl status zhitu -``` - ---- - -## 5. 备份数据库 - -数据库文件在 `/opt/zhitu/zhitu.db`,课程结束前务必备份: - -```bash -# 方式一:在服务器上备份到 root 目录 -cp /opt/zhitu/zhitu.db ~/zhitu_backup_$(date +%Y%m%d_%H%M%S).db - -# 方式二:下载到本地电脑(在本地终端执行) -scp root@121.41.216.243:/opt/zhitu/zhitu.db D:\zhitu_backup.db -``` - ---- - -## 6. 修改后端代码后热更新 - -改完 `app.py` 后需要重启生效: - -```bash -# 先检查语法 -python3 -m py_compile /opt/zhitu/app.py - -# 语法通过后重启 -systemctl restart zhitu -``` - ---- - -## 7. 常用验证命令 - -```bash -# 测试后端是否存活 -curl http://121.41.216.243/api/ping - -# 查看所有需求(无需登录) -curl http://121.41.216.243/api/demands - -# 查看账号列表(无需登录) -curl http://121.41.216.243/api/auth/accounts - -# 直接查看数据库中的 token(调试用) -sqlite3 /opt/zhitu/zhitu.db "SELECT * FROM tokens;" - -# 查看所有需求记录 -sqlite3 /opt/zhitu/zhitu.db "SELECT * FROM demands;" -``` - ---- - -## 8. 网络/端口检查 - -```bash -# 查看 5000 端口是否在监听 -ss -tlnp | grep 5000 - -# 查看 Nginx 状态 -systemctl status nginx - -# 查看防火墙状态 -ufw status -``` - ---- - -## 9. 常见问题速查 - -| 现象 | 可能原因 | 解决 | -|------|----------|------| -| APP 上报 500 | `_demand_id_counter` 内存计数器归零导致主键冲突 | 已修复:改为数据库查询生成 ID | -| APP 上报超时/卡住 | Gunicorn 多 worker + SQLite 并发锁竞争 | 改 `-w 1` | -| APP 登录 401 | Token 跨 worker 不共享 / localStorage 缓存旧地址 | 已修复:Token 存数据库;检查 APP 服务器地址设置 | -| 电脑端首页 404 | 前端静态文件未上传到 `/opt/zhitu/` | 确保 `index.html`、`css/`、`js/` 都在部署目录 | -| 服务启动失败 | 语法错误 / 端口被占 | `python3 -m py_compile /opt/zhitu/app.py` 检查语法 | - ---- - -## 10. 关键文件路径 - -| 文件/目录 | 路径 | -|-----------|------| -| 后端主程序 | `/opt/zhitu/app.py` | -| 数据库 | `/opt/zhitu/zhitu.db` | -| 服务配置 | `/etc/systemd/system/zhitu.service` | -| Nginx 配置 | `/etc/nginx/sites-enabled/zhitu` | -| Python 虚拟环境 | `/opt/zhitu/venv/` | -| 日志输出 | `journalctl -u zhitu` | - ---- - -*手册生成时间:2026-05-23* diff --git a/基于C++的无人机声源分析模块设计与实现_技术博客.docx b/基于C++的无人机声源分析模块设计与实现_技术博客.docx deleted file mode 100644 index bf6b4fac..00000000 Binary files a/基于C++的无人机声源分析模块设计与实现_技术博客.docx and /dev/null differ diff --git a/声源分析模块_项目交接文档.docx b/声源分析模块_项目交接文档.docx deleted file mode 100644 index 03b61f75..00000000 Binary files a/声源分析模块_项目交接文档.docx and /dev/null differ diff --git a/多模态融合_声学订阅补丁.md b/多模态融合_声学订阅补丁.md deleted file mode 100644 index 612c03bc..00000000 --- a/多模态融合_声学订阅补丁.md +++ /dev/null @@ -1,64 +0,0 @@ -# 多模态融合节点 — 声学威胁订阅补丁 - -> 问题:C++ 多模态融合节点未订阅 `/acoustic/threats`,导致声源数据无法参与融合避障。 -> 适用文件:`src/多模态融合/cpp/src/main.cpp` - ---- - -## 修改 1:添加成员变量 - -在 `ros::Subscriber flash_det_sub_;` 之后添加: - -```cpp - ros::Subscriber acoustic_sub_; // /acoustic/threats -``` - -## 修改 2:在 setup_ros() 中订阅声学话题 - -在 `flash_enabled` 订阅块之后、`// ── 定时器 ──` 之前添加: - -```cpp - // ── 声学威胁订阅者 ── - if (cfg_.acoustic_enabled) { - acoustic_sub_ = nh.subscribe("/acoustic/threats", 5, - &ThreatFusionNode::acoustic_threats_cb, this); - ROS_INFO("[ThreatFusion] 已订阅 /acoustic/threats"); - } -``` - -## 修改 3:添加回调函数 - -在 `flash_detection_cb` 之后、`fusion_timer_cb` 之前添加: - -```cpp - void acoustic_threats_cb(const acoustic_analyzer::AcousticThreatArray::ConstPtr& msg) { - for (const auto& t : msg->threats) { - if (t.confidence < cfg_.acoustic_confidence_threshold) continue; - AcousticThreatData a; - a.threat_id = t.threat_id; - a.sound_type = t.sound_type; - a.confidence = t.confidence; - a.azimuth = t.azimuth; - a.elevation = t.elevation; - a.distance = t.distance; - a.distance_confidence = t.distance_confidence; - a.timestamp = get_time(); - cache_.add_acoustic(a); - } - modality_status_["acoustic"] = "OK"; - } -``` - -## 修改 4:添加消息头文件 include - -在文件顶部的 include 区域添加: - -```cpp -#include -``` - -> 注:若构建时提示找不到该头文件,需确保 `acoustic_analyzer` 包已编译(`catkin_make`),并在 CMakeLists.txt 的 `find_package` 中声明依赖。 - ---- - -*补丁生成时间:2026-05-23* diff --git a/文档模板:软件设计规格说明书.doc b/文档模板:软件设计规格说明书.doc deleted file mode 100644 index 6c03816c..00000000 Binary files a/文档模板:软件设计规格说明书.doc and /dev/null differ diff --git a/智途投送_软件开发方案.md b/智途投送_软件开发方案.md deleted file mode 100644 index dd12dd8c..00000000 --- a/智途投送_软件开发方案.md +++ /dev/null @@ -1,749 +0,0 @@ -# "智途投送"软件开发方案 - -> 本文档基于《最后一公里软件构想》编写,为"智途投送"软件系统的开发实施方案。 - ---- - -## 一、项目概述 - -### 1.1 项目背景 - -"智途投送"软件系统是针对城市作战环境下"最后一公里"末端补给难题而设计的智能化物资投送系统。系统通过无人机替代有人运输,结合智能路径规划、动态避障和实时目标调整等功能,实现战场物资的安全、精准投送。 - -### 1.2 系统组成 - -本系统由三大核心子系统构成: - -| 子系统 | 主要功能 | 部署位置 | -|--------|----------|----------| -| 单兵终端系统 | 需求上报、策略选择、位置同步 | 前线士兵随身携带 | -| 无人机软件系统 | 自主飞行、路径规划、动态避障 | 无人机机载 | -| 后勤保障系统 | 任务调度、资源管理、状态监控 | 后方指挥所 | - -### 1.3 开发目标 - -- 实现前线士兵物资需求的实时上报与处理 -- 实现无人机自主路径规划与动态避障 -- 支持多种路径策略选择(最快、最安全、最省能耗) -- 支持动态目标调整与实时位置同步 -- 构建完整的后勤调度与监控平台 - ---- - -## 二、技术选型 - -### 2.1 技术栈总览 - -| 层次 | 技术选型 | 说明 | -|------|----------|------| -| 后勤保障系统 | Python + Flask/FastAPI | 快速开发,便于算法集成 | -| 数据库 | SQLite / PostgreSQL | 轻量级或企业级可选 | -| 单兵终端APP | Flutter 或 Android (Kotlin) | 跨平台或原生开发 | -| 无人机控制 | Python + MAVSDK / PX4 | 开源飞控生态完善 | -| 静态路径规划 | Python (NetworkX, OMPL) | 图算法库,用于全局路径计算 | -| 视觉导航与图像分析 | Python + OpenCV | 成熟的图像处理工具链,支持枪口火光检测、障碍物识别 | -| 热成像分析 | Python + OpenCV + PyTorch | 红外图像处理,热异常检测,温度阈值判定 | -| 声源分析与定位 | Python + librosa + NumPy | 声学特征提取,枪炮声分类,麦克风阵列声源定位(GCC-PHAT) | -| 多模态融合 | Python + NumPy | 多源威胁信息融合,实时威胁地图生成 | -| 仿真环境 | Gazebo / AirSim | 无人机仿真验证,支持传感器模拟 | -| 地图服务 | Leaflet / Mapbox | Web地图可视化 | - -### 2.2 技术选型理由 - -#### 2.2.1 后勤保障系统 - -**选择 Python + Flask/FastAPI 的理由:** -- Python 拥有丰富的科学计算和算法库(NumPy、SciPy、NetworkX) -- Flask/FastAPI 轻量级框架,便于快速构建 RESTful API -- 与路径规划算法、视觉算法无缝集成 -- 团队熟悉 Python 开发 - -#### 2.2.2 单兵终端APP - -**选择 Flutter 或 Android (Kotlin) 的理由:** -- Flutter:一套代码支持 Android/iOS,开发效率高 -- Android (Kotlin):原生性能好,硬件调用方便 -- 均支持地图SDK集成、网络通信、消息推送 - -#### 2.2.3 无人机软件 - -**选择 MAVSDK/PX4 的理由:** -- PX4 是成熟的开源飞控系统 -- MAVSDK 提供Python API,便于二次开发 -- 支持航线规划、状态监控、自主飞行 -- 社区活跃,文档完善 - -#### 2.2.4 仿真环境 - -**选择 Gazebo/AirSim 的理由:** -- Gazebo:开源机器人仿真,支持PX4集成 -- AirSim:微软开源,提供逼真的城市环境 -- 均支持传感器模拟(摄像头、IMU、GPS) - ---- - -## 三、开发阶段规划 - -采用分阶段迭代开发策略,总周期约 **12-16周**。 - -### 3.1 阶段一:核心算法验证(3-4周) - -#### 目标 -验证路径规划算法、多模态感知算法和避障算法的可行性,为后续系统集成奠定基础。 - -#### 任务分解 - -| 任务 | 描述 | 产出物 | -|------|------|--------| -| 搭建仿真环境 | 安装配置 AirSim 或 Gazebo,创建简化城市模型 | 可运行的仿真环境 | -| 静态路径规划 | 实现 A* 算法,基于城市地图、燃料约束、安全点标注等因素计算初始路径 | 静态路径规划模块 | -| 局部避障算法 | 实现 RRT 或 RRT* 算法,动态避开障碍物 | 避障算法模块 | -| 策略切换机制 | 实现三种策略(最快、最安全、最省能耗)的切换逻辑 | 策略选择模块 | -| 视觉识别原型 | 使用 OpenCV 实现墙体/障碍物边缘检测 | 视觉识别原型 | -| 热成像分析原型 | 实现红外图像热异常检测算法,包括枪管过热检测和枪口火焰热残留检测 | 热成像分析模块 | -| 相机图像分析原型 | 实现枪口火光检测算法(帧间差分+运动目标检测)和战场态势评估 | 相机图像分析模块 | -| 声源分析原型 | 实现枪炮声识别分类模型和麦克风阵列声源定位算法(GCC-PHAT) | 声源分析模块 | -| 多模态融合原型 | 实现三种感知结果融合逻辑,生成实时威胁地图 | 多模态融合模块 | - -#### 技术要点 - -```python -# 静态路径规划算法示例架构 -class StaticPathPlanner: - def __init__(self, city_map, threat_zones): - self.city_map = city_map - self.threat_zones = threat_zones - - def plan(self, start, goal, strategy='safest', fuel_constraint=None, - safe_points=None, urgency='normal'): - """ - strategy: 'fastest' / 'safest' / 'energy_efficient' - fuel_constraint: 剩余电量约束 - safe_points: 士兵标注的安全区域 - urgency: 物资紧急程度 - """ - pass - -# 动态威胁检测示例架构 -class DynamicThreatDetector: - def __init__(self): - self.thermal_analyzer = ThermalAnalyzer() # 热成像分析 - self.camera_analyzer = CameraAnalyzer() # 相机图像分析 - self.acoustic_analyzer = AcousticAnalyzer() # 声源分析 - - def detect_and_fuse(self, thermal_frame, camera_frame, audio_data): - """融合三种感知结果,生成威胁地图""" - thermal_threats = self.thermal_analyzer.detect(thermal_frame) - visual_threats = self.camera_analyzer.detect(camera_frame) - acoustic_threats = self.acoustic_analyzer.detect(audio_data) - return self._fuse(thermal_threats, visual_threats, acoustic_threats) -``` - -#### 验收标准 -- [ ] 仿真环境中无人机能够按规划路径飞行 -- [ ] 能够成功避开预设的障碍物 -- [ ] 三种策略能够正确切换并产生不同路径 -- [ ] 热成像模块能检测到模拟的热异常点 -- [ ] 相机模块能识别模拟的枪口火光闪烁 -- [ ] 声源模块能区分枪炮声与环境噪声并估计声源方向 - ---- - -### 3.2 阶段二:后勤保障系统开发(3-4周) - -#### 目标 -构建后端服务、数据库和可视化监控界面,实现任务调度和资源管理。 - -#### 任务分解 - -| 任务 | 描述 | 产出物 | -|------|------|--------| -| 数据库设计 | 设计物资、无人机、任务、用户等数据表 | 数据库Schema | -| 后端API开发 | 实现需求上报、任务调度、状态查询等接口 | RESTful API | -| 任务调度模块 | 实现无人机分配、任务状态管理逻辑 | 调度服务 | -| 可视化监控界面 | 开发Web界面,显示地图、无人机位置、任务状态 | Web前端 | -| 通信服务模块 | 实现与终端APP、无人机的数据收发 | 通信服务 | - -#### 数据库设计 - -##### E-R 图概念模型 - -``` -┌─────────────┐ ┌─────────────┐ ┌─────────────┐ -│ Soldier │ │ Task │ │ Drone │ -│ (前线士兵) │ │ (任务) │ │ (无人机) │ -├─────────────┤ ├─────────────┤ ├─────────────┤ -│ soldier_id │──┐ │ task_id │ ┌──│ drone_id │ -│ name │ │ │ type │ │ │ name │ -│ position │ │ │ priority │ │ │ status │ -│ unit │ │ │ strategy │ │ │ battery │ -└─────────────┘ │ │ status │ │ │ position │ - │ │ create_time │ │ └─────────────┘ - │ └─────────────┘ │ - │ │ │ - │ ▼ │ - │ ┌─────────────┐ │ - │ │ Delivery │───┘ - │ │ (配送记录) │ - │ ├─────────────┤ - └───▶│ delivery_id │ - │ task_id │ - │ drone_id │ - │ soldier_id │ - │ pickup_loc │ - │ dropoff_loc │ - │ start_time │ - │ end_time │ - └─────────────┘ - │ - ▼ - ┌─────────────┐ - │ Material │ - │ (物资) │ - ├─────────────┤ - │ material_id │ - │ name │ - │ quantity │ - │ location │ - └─────────────┘ -``` - -##### 数据表定义 - -**士兵表 (soldiers)** -| 字段名 | 类型 | 说明 | -|--------|------|------| -| soldier_id | VARCHAR(32) | 主键,士兵ID | -| name | VARCHAR(64) | 姓名 | -| unit | VARCHAR(64) | 所属单位 | -| position_lat | FLOAT | 纬度 | -| position_lng | FLOAT | 经度 | -| status | VARCHAR(16) | 状态(active/inactive) | -| create_time | DATETIME | 创建时间 | - -**无人机表 (drones)** -| 字段名 | 类型 | 说明 | -|--------|------|------| -| drone_id | VARCHAR(32) | 主键,无人机ID | -| name | VARCHAR(64) | 名称 | -| status | VARCHAR(16) | 状态(idle/flying/returning/maintenance) | -| battery | INT | 电量百分比 | -| position_lat | FLOAT | 当前纬度 | -| position_lng | FLOAT | 当前经度 | -| max_payload | FLOAT | 最大载重(kg) | - -**任务表 (tasks)** -| 字段名 | 类型 | 说明 | -|--------|------|------| -| task_id | VARCHAR(32) | 主键,任务ID | -| soldier_id | VARCHAR(32) | 外键,请求士兵 | -| strategy | VARCHAR(16) | 路径策略(fastest/safest/energy_efficient) | -| priority | VARCHAR(16) | 优先级(low/medium/high/urgent) | -| status | VARCHAR(16) | 状态(pending/assigned/in_flight/completed/cancelled) | -| create_time | DATETIME | 创建时间 | -| assign_time | DATETIME | 分配时间 | -| complete_time | DATETIME | 完成时间 | - -**配送记录表 (deliveries)** -| 字段名 | 类型 | 说明 | -|--------|------|------| -| delivery_id | VARCHAR(32) | 主键 | -| task_id | VARCHAR(32) | 外键,关联任务 | -| drone_id | VARCHAR(32) | 外键,执行无人机 | -| pickup_lat | FLOAT | 取货点纬度 | -| pickup_lng | FLOAT | 取货点经度 | -| dropoff_lat | FLOAT | 投放点纬度 | -| dropoff_lng | FLOAT | 投放点经点 | -| start_time | DATETIME | 开始时间 | -| end_time | DATETIME | 结束时间 | - -**物资表 (materials)** -| 字段名 | 类型 | 说明 | -|--------|------|------| -| material_id | VARCHAR(32) | 主键 | -| name | VARCHAR(64) | 物资名称 | -| category | VARCHAR(32) | 类别(ammo/food/medicine/equipment) | -| quantity | INT | 库存数量 | -| weight | FLOAT | 单件重量(kg) | -| location | VARCHAR(64) | 存放位置 | - -#### API 接口设计 - -**基础URL**: `http://:/api/v1` - -| 接口 | 方法 | 描述 | -|------|------|------| -| `/soldiers/{id}/position` | PUT | 更新士兵位置 | -| `/materials` | GET | 查询物资库存 | -| `/tasks` | POST | 创建物资需求任务 | -| `/tasks/{id}` | GET | 查询任务状态 | -| `/tasks/{id}/strategy` | PUT | 更新路径策略 | -| `/tasks/{id}/dropoff` | PUT | 更新投放点 | -| `/drones` | GET | 查询无人机列表 | -| `/drones/{id}/status` | POST | 无人机状态上报 | -| `/deliveries` | GET | 查询配送记录 | - -#### 验收标准 -- [ ] 数据库表创建完成,可正常读写 -- [ ] 所有API接口可通过Postman测试 -- [ ] Web界面可显示地图和无人机位置 -- [ ] 任务创建到完成的完整流程可跑通 - ---- - -### 3.3 阶段三:单兵终端APP开发(2-3周) - -#### 目标 -开发前线士兵使用的移动应用,实现需求上报、策略选择、消息接收等功能。 - -#### 任务分解 - -| 任务 | 描述 | 产出物 | -|------|------|--------| -| 项目框架搭建 | 创建Flutter/Android项目,配置依赖 | 项目骨架 | -| 登录认证模块 | 实现士兵身份认证 | 登录界面 | -| 需求上报界面 | 物资类型、数量、紧急程度选择与提交 | 上报界面 | -| 策略选择界面 | 三种路径策略的选择交互 | 策略界面 | -| 地图显示模块 | 集成地图SDK,显示投放点位置 | 地图模块 | -| 消息推送模块 | 接收后勤系统的通知消息 | 推送模块 | -| 位置上报服务 | 后台定时上报士兵位置 | 位置服务 | - -#### 界面设计 - -``` -┌─────────────────────────────────────┐ -│ 智途投送 - 单兵终端 │ -├─────────────────────────────────────┤ -│ ┌─────────────────────────────────┐│ -│ │ ││ -│ │ [ 地图显示区域 ] ││ -│ │ 显示当前位置 ││ -│ │ 显示投放点位置 ││ -│ │ ││ -│ └─────────────────────────────────┘│ -├─────────────────────────────────────┤ -│ 快捷操作 │ -│ ┌─────────┐ ┌─────────┐ │ -│ │ 申请物资 │ │ 查看任务 │ │ -│ └─────────┘ └─────────┘ │ -│ ┌─────────┐ ┌─────────┐ │ -│ │ 库存查询 │ │ 消息中心 │ │ -│ └─────────┘ └─────────┘ │ -├─────────────────────────────────────┤ -│ 当前任务:等待中 │ -│ 任务ID: T-2024001 │ -│ 物资: 急救药品 x5 │ -│ 状态: 无人机已起飞 │ -│ 预计到达: 14:35 │ -└─────────────────────────────────────┘ -``` - -#### 验收标准 -- [ ] APP可正常安装运行 -- [ ] 可成功提交物资需求 -- [ ] 可选择路径策略 -- [ ] 可接收投放点通知 -- [ ] 位置可实时上报 - ---- - -### 3.4 阶段四:无人机系统集成(3-4周) - -#### 目标 -实现无人机自主飞行、路径规划、动态避障等核心能力。 - -#### 任务分解 - -| 任务 | 描述 | 产出物 | -|------|------|--------| -| 飞控平台选型 | 选择无人机平台,配置开发环境 | 开发环境 | -| 航点飞行控制 | 实现按航点序列飞行的能力 | 飞控模块 | -| 状态回传模块 | 定时上报位置、电量、任务状态 | 状态模块 | -| 静态路径规划集成 | 集成阶段一开发的静态路径规划算法,综合考虑燃料、安全点、紧急程度等约束 | 静态规划模块 | -| 视觉避障模块 | 集成视觉识别,实现动态避障 | 避障模块 | -| 热成像感知模块 | 集成红外热成像传感器驱动与分析算法,实现枪管过热和火焰热残留检测 | 热成像模块 | -| 相机图像分析模块 | 集成可见光相机驱动与火光检测算法,实现枪口火光识别和战场态势评估 | 图像分析模块 | -| 声源感知模块 | 集成麦克风阵列驱动与声学分析算法,实现枪炮声识别和声源定位 | 声源分析模块 | -| 多模态融合模块 | 融合热成像、相机、声源三种感知结果,生成威胁地图并驱动动态航线调整 | 融合规划模块 | -| 通信模块 | 与后勤系统的数据收发 | 通信模块 | -| 应急处理模块 | 通信中断、电量不足等异常处理 | 应急模块 | - -#### 软件架构 - -``` -┌──────────────────────────────────────────────────────────────────┐ -│ 无人机软件系统 │ -├──────────────────────────────────────────────────────────────────┤ -│ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌─────────────┐ │ -│ │ 通信模块 │ │ 飞控模块 │ │静态路径规划│ │多模态融合 │ │ -│ │ │ │ │ │ │ │与动态规划 │ │ -│ │- 指令接收 │ │- 航点飞行 │ │- 地图规划 │ │ │ │ -│ │- 状态回传 │ │- 悬停控制 │ │- 燃料约束 │ │- 威胁融合 │ │ -│ │- 加密传输 │ │- 返航逻辑 │ │- 安全标注 │ │- 威胁地图 │ │ -│ └─────┬─────┘ └─────┬─────┘ │- 策略切换 │ │- 动态绕行 │ │ -│ │ │ └─────┬─────┘ └──────┬──────┘ │ -│ │ │ │ │ │ -│ └──────────────┴──────────────┴───────────────┘ │ -│ │ │ -│ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐ │ -│ │热成像分析 │ │相机图像分析│ │ 声源分析 │ │ 任务管理器 │ │ -│ │ │ │ │ │ │ │ │ │ -│ │- 枪管过热 │ │- 枪口火光 │ │- 枪炮识别 │ │- 任务执行 │ │ -│ │- 热残留 │ │- 态势感知 │ │- 声源定位 │ │- 策略切换 │ │ -│ │- 温度检测 │ │- 危险评估 │ │- 火力评估 │ │- 应急处理 │ │ -│ └───────────┘ └───────────┘ └───────────┘ └───────────┘ │ -├──────────────────────────────────────────────────────────────────┤ -│ 硬件接口层 │ -│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │ -│ │ 飞控 ││摄像头│ │热成像│ │麦克风│ │ IMU │ │ GPS │ │ -│ └──────┘ └──────┘ └──────┘ └──────┘ └──────┘ └──────┘ │ -└──────────────────────────────────────────────────────────────────┘ -``` - -#### 状态机设计 - -``` - ┌─────────────┐ - │ IDLE │ - │ (待机) │ - └──────┬──────┘ - │ 收到任务 - ▼ - ┌─────────────┐ - │ PLANNING │ - │ (路径规划) │ - └──────┬──────┘ - │ 规划完成 - ▼ - ┌─────────────┐ - ┌─────│ FLYING │─────┐ - │ │ (飞行中) │ │ - │ └─────────────┘ │ - │ │ │ - 避障触发│ │到达目标 │电量不足 - │ │ │ - ▼ ▼ ▼ - ┌───────────┐ ┌───────────┐ ┌───────────┐ - │ AVOIDING │ │ HOVERING │ │ RETURNING │ - │ (避障中) │ │ (悬停) │ │ (返航) │ - └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ - │ │ │ - └─────────────┴─────────────┘ - │ - ▼ - ┌─────────────┐ - │ COMPLETED │ - │ (完成) │ - └─────────────┘ -``` - -#### 验收标准 -- [ ] 无人机可接收后勤系统下发的任务 -- [ ] 可按规划路径自主飞行 -- [ ] 可识别障碍物并自主避让 -- [ ] 状态可实时回传后勤系统 -- [ ] 通信中断时可自动返航 - ---- - -### 3.5 阶段五:系统集成测试(2周) - -#### 目标 -完成各子系统的联调测试,验证端到端功能。 - -#### 任务分解 - -| 任务 | 描述 | 产出物 | -|------|------|--------| -| 接口联调测试 | 验证各子系统间的通信接口 | 测试报告 | -| 端到端流程测试 | 完整任务流程测试 | 测试报告 | -| 异常场景测试 | 通信中断、电量不足等异常测试 | 测试报告 | -| 性能测试 | 并发任务、响应时间测试 | 测试报告 | -| 用户验收测试 | 模拟真实使用场景测试 | 验收报告 | - -#### 测试用例 - -| 编号 | 测试场景 | 预期结果 | -|------|----------|----------| -| TC001 | 士兵提交物资需求 | 后勤系统收到请求,分配无人机 | -| TC002 | 选择"最快"策略 | 路径优先考虑时间最短 | -| TC003 | 选择"最安全"策略 | 路径避开威胁区域 | -| TC004 | 动态调整投放点 | 无人机更新航线 | -| TC005 | 通信中断 | 无人机自动返航 | -| TC006 | 电量不足 | 无人机中止任务返航 | -| TC007 | 多任务并发调度 | 系统正确分配资源 | -| TC008 | 视觉避障测试 | 无人机成功绕过障碍物 | -| TC009 | 热成像枪管过热检测 | 检测到模拟热源,标记为威胁区域 | -| TC010 | 相机枪口火光检测 | 识别到模拟火光闪烁,区分环境光源 | -| TC011 | 声源枪炮声识别 | 正确区分枪声、炮声与环境噪声 | -| TC012 | 声源定位准确性 | 声源方向估计误差在可接受范围内 | -| TC013 | 多模态融合威胁检测 | 三种感知结果融合后生成一致的威胁地图 | -| TC014 | 动态威胁规避 | 检测到交火威胁后无人机自动绕行 | - -#### 验收标准 -- [ ] 所有测试用例通过 -- [ ] 端到端流程完整可运行 -- [ ] 异常场景处理正确 -- [ ] 系统响应时间满足要求 - ---- - -## 四、项目结构 - -### 4.1 目录结构 - -``` -ZhiTuTouSong/ -│ -├── docs/ # 项目文档 -│ ├── 需求规格说明书.md -│ ├── 系统设计文档.md -│ ├── 接口设计文档.md -│ ├── 测试报告.md -│ └── 用户手册.md -│ -├── backend/ # 后勤保障系统 -│ ├── README.md -│ ├── requirements.txt # Python依赖 -│ ├── config/ # 配置文件 -│ │ ├── __init__.py -│ │ ├── settings.py -│ │ └── logging.conf -│ ├── api/ # API接口 -│ │ ├── __init__.py -│ │ ├── routes/ -│ │ │ ├── __init__.py -│ │ │ ├── soldiers.py -│ │ │ ├── tasks.py -│ │ │ ├── drones.py -│ │ │ └── materials.py -│ │ └── schemas/ -│ │ ├── __init__.py -│ │ ├── task.py -│ │ └── drone.py -│ ├── models/ # 数据模型 -│ │ ├── __init__.py -│ │ ├── soldier.py -│ │ ├── task.py -│ │ ├── drone.py -│ │ └── material.py -│ ├── services/ # 业务逻辑 -│ │ ├── __init__.py -│ │ ├── task_service.py -│ │ ├── drone_service.py -│ │ └── notification_service.py -│ ├── algorithms/ # 算法模块 -│ │ ├── __init__.py -│ │ ├── path_planner.py -│ │ ├── obstacle_detector.py -│ │ └── strategy_selector.py -│ ├── database/ # 数据库 -│ │ ├── __init__.py -│ │ ├── connection.py -│ │ └── migrations/ -│ └── main.py # 入口文件 -│ -├── mobile-app/ # 单兵终端APP -│ ├── README.md -│ ├── lib/ -│ │ ├── main.dart -│ │ ├── models/ -│ │ ├── views/ -│ │ │ ├── home_view.dart -│ │ │ ├── task_view.dart -│ │ │ └── map_view.dart -│ │ ├── viewmodels/ -│ │ ├── services/ -│ │ │ ├── api_service.dart -│ │ │ ├── location_service.dart -│ │ │ └── notification_service.dart -│ │ └── utils/ -│ ├── assets/ -│ ├── pubspec.yaml -│ └── android/ -│ -├── drone-software/ # 无人机软件 -│ ├── README.md -│ ├── requirements.txt -│ ├── src/ -│ │ ├── __init__.py -│ │ ├── main.py -│ │ ├── flight_control/ -│ │ │ ├── __init__.py -│ │ │ ├── drone_controller.py -│ │ │ └── waypoint_manager.py -│ │ ├── vision/ -│ │ │ ├── __init__.py -│ │ │ ├── camera.py -│ │ │ ├── obstacle_detector.py -│ │ │ ├── muzzle_flash_detector.py -│ │ │ └── visual_odometry.py -│ │ ├── thermal/ -│ │ │ ├── __init__.py -│ │ │ ├── thermal_sensor.py # 红外热成像传感器驱动 -│ │ │ ├── heat_anomaly_detector.py # 热异常检测(枪管过热/火焰热残留) -│ │ │ └── temperature_processor.py # 温度数据处理与阈值判定 -│ │ ├── acoustic/ -│ │ │ ├── __init__.py -│ │ │ ├── microphone_array.py # 麦克风阵列驱动 -│ │ │ ├── gunshot_classifier.py # 枪炮声分类识别 -│ │ │ ├── sound_localizer.py # 声源定位(GCC-PHAT) -│ │ │ └── noise_filter.py # 风噪滤波预处理 -│ │ ├── communication/ -│ │ │ ├── __init__.py -│ │ │ ├── radio_link.py -│ │ │ └── message_protocol.py -│ │ ├── planning/ -│ │ │ ├── __init__.py -│ │ │ ├── global_planner.py # 静态路径规划(A*等) -│ │ │ ├── local_planner.py # 局部避障规划 -│ │ │ └── dynamic_planner.py # 多模态融合动态路径规划 -│ │ └── mission/ -│ │ ├── __init__.py -│ │ ├── mission_manager.py -│ │ └── emergency_handler.py -│ └── config/ -│ └── drone_config.yaml -│ -├── simulation/ # 仿真环境 -│ ├── README.md -│ ├── city_model/ # 城市模型 -│ │ ├── buildings.json -│ │ └── terrain.json -│ ├── scenarios/ # 测试场景 -│ │ ├── scenario_1.json -│ │ └── scenario_2.json -│ └── scripts/ -│ ├── setup_simulation.py -│ └── run_test.py -│ -├── tests/ # 集成测试 -│ ├── integration/ -│ ├── e2e/ -│ └── performance/ -│ -├── scripts/ # 工具脚本 -│ ├── setup.sh -│ ├── run_backend.sh -│ └── deploy.sh -│ -├── .gitignore -├── LICENSE -└── README.md -``` - -### 4.2 模块职责说明 - -| 模块 | 职责 | 所属子系统 | -|------|------|------------| -| api/ | RESTful API接口定义 | 后勤保障系统 | -| models/ | 数据模型定义 | 后勤保障系统 | -| services/ | 业务逻辑处理 | 后勤保障系统 | -| algorithms/ | 路径规划与避障算法 | 后勤保障系统 | -| flight_control/ | 飞行控制逻辑 | 无人机软件 | -| vision/ | 视觉识别、枪口火光检测与导航 | 无人机软件 | -| thermal/ | 红外热成像分析、枪管过热检测 | 无人机软件 | -| acoustic/ | 声源分析、枪炮声识别与声源定位 | 无人机软件 | -| planning/ | 静态路径规划与多模态融合动态规划 | 无人机软件 | -| communication/ | 通信协议与数据传输 | 无人机软件 | -| views/ | 移动端界面 | 单兵终端APP | -| services/ | 移动端服务(API调用、位置上报) | 单兵终端APP | - ---- - -## 五、开发规范 - -### 5.1 代码规范 - -- **Python**: 遵循 PEP 8 规范,使用 Black 格式化 -- **Dart/Flutter**: 遵循 Dart 官方风格指南 -- **文档**: 使用中文注释,函数需添加文档字符串 - -### 5.2 Git 分支管理 - -``` -main # 主分支,稳定版本 -├── develop # 开发分支 -│ ├── feature/backend-task-service # 功能分支 -│ ├── feature/mobile-home-view # 功能分支 -│ └── feature/drone-flight-control # 功能分支 -└── release/v1.0 # 发布分支 -``` - -### 5.3 提交信息规范 - -``` -(): - -# 示例 -feat(backend): 添加任务调度API接口 -fix(drone): 修复通信中断后无法返航的问题 -docs(readme): 更新项目说明文档 -test(backend): 添加路径规划算法单元测试 -``` - -**Type 类型**: -- `feat`: 新功能 -- `fix`: 修复bug -- `docs`: 文档更新 -- `test`: 测试相关 -- `refactor`: 代码重构 -- `style`: 代码格式调整 - ---- - -## 六、风险管理 - -### 6.1 技术风险 - -| 风险 | 概率 | 影响 | 应对措施 | -|------|------|------|----------| -| 路径规划算法性能不足 | 中 | 高 | 采用分层规划,全局离线+局部实时 | -| 视觉避障可靠性低 | 高 | 高 | 多传感器融合,设置置信度阈值 | -| 通信链路不稳定 | 高 | 中 | 设计通信中断应急机制 | -| GPS信号丢失 | 中 | 中 | 视觉导航辅助定位 | - -### 6.2 项目风险 - -| 风险 | 概率 | 影响 | 应对措施 | -|------|------|------|----------| -| 开发周期延期 | 中 | 高 | 分阶段交付,优先核心功能 | -| 无人机硬件获取困难 | 中 | 高 | 使用仿真环境替代实物测试 | -| 团队成员变动 | 低 | 中 | 代码规范,文档完善 | - ---- - -## 七、里程碑计划 - -| 里程碑 | 时间节点 | 交付物 | -|--------|----------|--------| -| M1: 算法验证完成 | 第3周 | 路径规划仿真演示 | -| M2: 后勤系统可用 | 第7周 | 可运行的后端服务+Web界面 | -| M3: 终端APP可用 | 第10周 | 可安装的移动应用 | -| M4: 无人机集成完成 | 第14周 | 无人机自主飞行演示 | -| M5: 系统验收 | 第16周 | 完整系统演示+文档 | - ---- - -## 八、附录 - -### 8.1 参考资料 - -- PX4 开发指南: https://docs.px4.io/ -- MAVSDK Python: https://mavsdk.mavlink.io/ -- AirSim 文档: https://microsoft.github.io/AirSim/ -- OpenCV 官方文档: https://docs.opencv.org/ -- Flutter 开发文档: https://flutter.dev/docs - -### 8.2 开发工具 - -- IDE: VS Code / PyCharm / Android Studio -- 版本控制: Git -- 项目管理: GitHub Projects / 禅道 -- API测试: Postman -- 数据库工具: DBeaver - ---- - -*文档版本: v1.0* -*创建日期: 2026年4月* diff --git a/智途投送软件系统_软件设计规格说明书.docx b/智途投送软件系统_软件设计规格说明书.docx deleted file mode 100644 index ef847b89..00000000 Binary files a/智途投送软件系统_软件设计规格说明书.docx and /dev/null differ diff --git a/设计文档示例-空巢老人看护系统.doc b/设计文档示例-空巢老人看护系统.doc deleted file mode 100644 index 92aca09c..00000000 Binary files a/设计文档示例-空巢老人看护系统.doc and /dev/null differ diff --git a/课程实践服务器资源_2026-05-12.xlsx b/课程实践服务器资源_2026-05-12.xlsx deleted file mode 100644 index a1de9403..00000000 Binary files a/课程实践服务器资源_2026-05-12.xlsx and /dev/null differ