You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
software/generate_handover_doc.js

292 lines
19 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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 epochCNN-GRU 网络,验证准确率 100%(合成数据过拟合属预期现象)"),
body("• ONNX 导出gunshot_classifier.onnx1.9MBopset 13"),
body("• ONNX 验证:枪声识别置信度 97.92%"),
h2("2.3 临时方案与最终方案分离"),
body("已实现 source_type 配置切换机制:"),
body("• mobile_phone手机单通道麦克风通过 UDP → ROS 话题传输,仅做分类"),
body("• mic_array4 通道麦克风阵列(最终方案),完整分类+定位+距离估计"),
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/<user>/miniconda3/LibraryCMake 已适配"),
body("• ONNX Runtime C++ v1.20.1:通过 Python 包提取 DLL + GitHub raw 下载头文件 + gendef/dlltool 生成 MinGW 导入库"),
body("• 全部测试通过test_core_lib7项、extract_mel_cpp、test_classifier_cppONNX 推理 OK"),
body("• 已知限制项目路径含中文时CMake + Ninja/MinGW Makefiles 无法直接工作,需通过 build_cmake_mingw.bat 自动复制到临时英文目录构建"),
h2("2.5 代码 Bug 修复记录"),
body("搭建过程中发现并修复的问题:"),
body("• gcc_phat_localizer.cpp缺少 #include <Eigen/SVD>,导致 BDCSVD 不完整类型错误"),
body("• threat_tracker.cpp数据关联更新检测时丢失原有 threat_id导致多帧跟踪失败"),
body("• test_core_lib.cppaudio_buffer_wraparound 测试期望值错误5 应为 6gcc_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("• CMake4.1.0 已安装 ✅"),
body("• Eigen3bundled third_party/eigen-3.4.0 ✅"),
body("• ONNX Runtime C++v1.20.1 已配置(头文件 + DLL + MinGW 导入库)✅"),
body("• yaml-cppconda 0.8.0 已检测CMake 自动链接 ✅"),
body("• 构建方式:"),
body(" 快速命令行build_core_test.bat一键编译全部测试"),
body(" 标准 CMakebuild_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("实现 MicArraySourceALSA 麦克风阵列驱动)", 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");
});