Files
radar_data_process/README.md
T

1298 lines
142 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 雷达数据处理 DLL(data_process_class_dll)
> X256 雷达数据处理动态链接库:将雷达输出的原始点迹(TWS/TAS)处理为稳定可靠的目标航迹,并给出 TAS 跟踪波束控制指令。
> 仓库 simianzhen256-v1.5.5-ms-vscode(目录名沿用旧版本,当前代码版本为 **V1.5.9**;已由 Qt/qmake 工程迁移为 VS Code + CMake 工程,编译器为 MSVC 2022 / v143,C++17,x64 目标)。
>
> 版本号由 `parameters.h` 的 `MAJOR_VERSION` / `MINOR_VERSION` / `PATCH_VERSION`(当前 1.5.9)与 `VERSION_INFO`(`"GENERIC"`——机扫/相扫版本已合并为同一份 DLL,无体制后缀)拼装为 `VERSION_STRING`(`V1.5.9.GENERIC`),实例创建后可从 `Data_Process_Factory::GetB()` 返回对象的公开成员 `version_info`(`const char*`)读取。
>
> **工作参数来源(参数配置方式改造后)**:全部雷达工作参数由宿主调用 `parameters_reload(配置文件路径)` 从 **TOML 配置文件**加载到内部 `RDP_parameter`,不再由宿主下发 `struct RadarPara`、也不再由 `parameters.h` 编译期宏配置(见 10)。
---
## 目录
1. [项目简介](#1-项目简介)
2. [功能特性](#2-功能特性)
3. [目录结构](#3-目录结构)
4. [构建与环境](#4-构建与环境)
5. [总体架构](#5-总体架构)
6. [关键数据结构](#6-关键数据结构)
7. [外部接口与调用流程](#7-外部接口与调用流程)
8. [处理流程总览](#8-处理流程总览)
9. [算法实现详解](#9-算法实现详解)
10. [参数说明](#10-参数说明)
11. [已知问题与限制](#11-已知问题与限制)
12. [版本历史](#12-版本历史)
13. [参考文档](#13-参考文档)
---
## 1. 项目简介
本仓库是一个 **Windows 动态链接库**,实现某型雷达(内部代号 X256;机扫、相扫两个版本已合并为同一份 DLL,扫描模式由运行期配置项 `[radar_params] scan_mode` 选择,构建不再区分体制)的 **航迹数据处理** 功能,包括:
- 输入点迹预处理与点迹凝聚(滑窗凝聚)
- 边扫描边跟踪(TWS)与边跟踪边扫描(TAS)双通道处理
- 逻辑法航迹起始(3~9 点起批,含屏蔽区、角度/波门约束)
- IMM + 扩展卡尔曼滤波(EKF,含多普勒速度)航迹维持
- 最近邻(NN)点航关联
- 航迹外推、消亡与航迹号管理
- TAS 手动转跟踪与跟踪波束调度输出
**技术栈**:C++(MSVC 2022 / v143 工具集,C++17)、Eigen 3(随仓库内置,仅用 Eigen/Dense)、CMake ≥ 3.21。
**处理约定**:
| 项目 | 约定 |
|---|---|
| 时间戳 | CPI 时间 / GNSS 时间均为 long long 毫秒(64 位);航迹时间 T_track 同样为毫秒,参与运算时除以 1000 转秒 |
| 角度 | 外部接口用度(°),内部统一弧度;输出航向角/方位/俯仰为度 |
| 坐标 | 直角坐标系 x/y 为水平面投影,z = 目标高度 + 雷达平台高度 |
| 点迹类型 | point_type = 0 为 TWS,point_type = 1 为 TAS |
| 跟踪模式 | Track_Mode = 0 为 TWS,Track_Mode = 1 为 TAS |
| 参数来源 | TOML 配置文件(`config/config_tmp.toml` 为样例)→ 内部 `struct RDP_parameter`,宿主通过 `parameters_reload()` 加载;参数对照见 10 |
| 判圈模式 | 由配置项 `[radar_params] scan_mode` 运行时选择:0 相扫(波位号 ≤ 上一帧判满圈)/ 1 机扫(波位号 == 0 判满圈);机扫/相扫已合并为同一份构建,不再有编译期体制(见 4.2、7.2) |
---
## 2. 功能特性
- **双模式处理管线**:data_preprocess 按输入类型与扫描圈完成标志返回 0/1/2/3,track_process 据此调度 TWS 凝聚/关联/起始或 TAS 凝聚/关联。判圈条件由配置项 `[radar_params] scan_mode` **运行时**选择(0 相扫 / 1 机扫):**相扫**比较前后两帧方位波位号(当前波位号 ≤ 上一帧波位号即判满圈),**机扫**以「方位波位号 == 0」判满圈(规避转台反转导致的误判),详见 7.2。
- **两帧滑窗点迹凝聚**:TWS 点迹先与上一帧缓存合并凝聚,再进入关联,兼顾跨波位(CPI)相邻点迹的分裂问题;近程模式增加速度维约束。
- **逻辑法航迹起始**:每圈按固定顺序推进——① 未关联点迹先与 ≥2 点临时航迹做 EKF 波门 + 折角约束关联(延长临时航迹),② 再与 1 点航迹头做速度法关联(两点卡尔曼初始化出 2 点临时航迹),③ 两步都做完后删除被消费的点迹、剩余点迹转成新航迹头,④ 长度达标的临时航迹经三点卡尔曼初始化转可靠航迹;带起批屏蔽区与重复航迹去重。
- **3 模型 IMM 滤波**:三个 Singer 模型(低/中/高过程噪声),量测为「距离-方位-径向速度」三维的 EKF,多普勒残差按盲速折叠,似然用 3×3 新息协方差。
- **最近邻数据关联**:三模型统计距离波门 `associate_threshold = 4`(配置项 `[track_associate] associate_threshold`,等效 d < 4,TWS 另按航迹距离分段收紧模型 3 波门),再叠加高度门限(≤1000 m 150 m / 2000 m 200 m / 3000 m 250 m / 5000 m 300 m,更远不约束)与 TWS 弦距-位移距离门限。ΔT ≤ 0(点迹时间戳不晚于航迹时间)的候选不更新航迹状态、仅消费该点迹(标记已使用),避免其继续起批而生成虚假 TWS 航迹。关联输出的航迹同时给出**靠近/远离方向标志**:按航迹 IMM 融合速度矢量与「雷达→目标」位置矢量的夹角判定——`acos((-x·cos(Direction_Angle) − y·sin(Direction_Angle)) / r) < π/2` 置 1(靠近),否则 0(远离),等价于「滤波速度的径向分量指向雷达」,不再使用受多普勒模糊影响的实测径向速度 `vr_point`;TWS、TAS 两通道一致(见 9.6)。
- **重点目标与外推上限**:`primary_target_add` / `primary_target_cancel` 可按批号手动标记/取消重点目标,重点航迹的消亡轮数放宽到 `track_die_round_pramary`(默认 10);未关联航迹的外推圈数受限(TWS ≤ `extrapolate_max`=3,TAS 由 `extrapolate_max_tas` 控制,样例配置为相扫 5 / 机扫需配 48),超限后停止外推。**输出航迹只包含本圈有更新的航迹**(`Track_Update_Flag` 门控),宿主不能再用输出行数推断航迹总数(见 9.9)。
- **航迹质量(V1.5.8)**:归一化航迹质量(0~1,内部)贯穿起始→关联→外推三阶段——临时航迹每延长一点按「统计距离 + SNR」重算,关联实点后按「统计距离 + SNR + 有效点占比」加权并指数平滑,未关联期间按未更新时长二次衰减;起批需达到**按长度分级**的最低质量,输出航迹给 0~100 的 `Quality` 字段;**普通 TWS 航迹的消亡改由质量决定**(`Quality < 0.3`),重点航迹与 TAS 航迹仍按外推圈数(见 9.11)。
- **点迹附加信息字段扩展(需同步重编译宿主)**:`DataRev` 新增 `amp_asv` / `prn_fftn`,`Track` 新增 `amp_asv_point` / `prn_fftn_point`,结构体布局随之变化,宿主必须使用同一版本头文件重新编译对接;输入侧已打通(TWS 输出有效,TAS 输出仍未写回),详见 11.2。
- **高度维独立平滑**:按距离分段选择滑动平均窗长,TWS 为 `height_smooth_win + {2,3,4,6}`、TAS 为 `height_smooth_win + {6,8,10,12}`(样例配置 `height_smooth_win`=6 对应相扫;机扫需配 3),抑制俯仰测量跳变(见 9.7)。
- **参数配置外置(参数配置方式改造)**:全部工作参数(原 `parameters.h` 宏 + `RadarPara` 字段)改由 TOML 配置文件提供,宿主在 `GetB()` 后调用一次 `parameters_reload(路径)` 加载(重连/换配置可再次调用);加载器严格校验 11 个配置段、键名/类型/取值范围与屏蔽区数组长度,失败返回 -1 且不改变当前参数(见 10.1)。样例配置 `config/config_tmp.toml` 为**相扫**取值(`scan_mode = 0`);机扫部署需改用 `scan_mode = 1` 并把 `extrapolate_max_tas`、`height_smooth_win`、`track_die_round_tas`、`tas_track_num_max` 配为 48 / 3 / 96 / 1(这 4 项在改造前按扫描体制取不同宏值,现在同一份配置对所有体制生效)。**判圈逻辑由配置项 `scan_mode` 决定**(不再是编译期体制),详见 4.2、7.2。
- **TAS 波束控制**:手动转 TAS 目标入队(队列容量为编译期常量 `RDP_TAS_QUEUE_CAPACITY`、运行期上限为配置项 `tas_track_num_max`),按最新时间戳外推输出跟踪波束(距离/方位/俯仰/批号)。
- **航迹生命周期管理**:外推轮数计数、超时消亡与质量消亡(普通 TWS 航迹)、手动删除、全清空(含各模块 reset,防重连后幽灵航迹)。
- **防御性加固**:见 archived_docs/BUG_FIX_REPORT.md——越界防护、时间戳正序校验、方位角 ±π 环绕、asin 定义域钳位、IMM 概率奇异保护等已修复项。
- **日志文件输出**:`RDP_LOG_ENABLE` 定义时,首次 `Data_Process_Factory::GetB()` 自动用 `rdbuf()` 将 `std::cout` 重定向到 `RDP_LOG_DIR`(`.\rdp_logs\`)下按日期+时间命名的日志文件,`Destroy()` 时恢复控制台并关闭文件;`RDP_LOG` 日志宏在每条日志前附加 `[时间戳][文件:行号]`。该宏在 `parameters.h` 中**当前为注释状态(默认不启用)**,即默认不做重定向、日志输出到控制台(见 10.4)。
- **版本号输出**:`parameters.h` 的 `MAJOR_VERSION`/`MINOR_VERSION`/`PATCH_VERSION`(当前 1.5.9)经两级 `STRINGIFY` 宏拼成 `VERSION_STRING`(`V1.5.9.GENERIC`,机扫/相扫共用同一版本、无 PS/MS 后缀);`Data_process_class_dll` 基类公开成员 `const char* version_info` 由 `Data_Process_Factory::GetB()` 在创建实例时赋值,宿主可直接读取以核对/上报 DLL 版本(b227ae1)。
- **数据记录调试功能(可选编译、异步批量写入)**:`rdp_record` 模块把结构体按「一个记录实体一张表」写入 SQLite(一次运行一个 db 文件、多张表),结构体到表的映射由内置的 ormpp(`third_party/ormpp`,含 iguana、frozen 与 SQLite 3.49.1 amalgamation)完成;由 CMake 选项 `RDP_DATA_RECORD`(`AUTO`/`ON`/`OFF`)控制,**AUTO 时 Debug 构建启用、Release(交付)构建完全不编译**——记录模块源码不参与编译、记录宏(6 个异步入队宏与遗留 `RDP_RECORD`/`RDP_RECORD_BATCH`)展开为 `((void)0)`(实参不求值),DLL 不新增依赖与导出符号、无性能损失。**V1.5.8 优化后的运行模型**:`GetB()` 建目录、开库(`.\rdp_records\rdp_record_YYYYMMDD_HHMMSS.db`)并启动独立**写线程**;12 个记录点只做「帧/圈内收集源结构体 → 一次入队」(收集代码均在 `#ifdef RDP_RECORD_ENABLE` 内),实体构造(数组转文本)与 SQLite **批量事务**全部在写线程完成;入队队列**有界**(默认 64 MB / 4096 批,满则整批丢弃并计入 `stats().dropped_rows`,不阻塞处理线程),写线程按 4096 行或等待 50 ms 凑批提交,SQLite 使用 WAL + `synchronous=OFF` + 8 MB 缓存,建表后去掉 `AUTOINCREMENT`;`Destroy()` 时停止入队、排空、`wal_checkpoint(TRUNCATE)`、关库并打印统计,支持 `Destroy()`→`GetB()` 重连重新建库(同秒文件名冲突追加 `_1`/`_2` 后缀)。当前内置 **6 个记录实体定义、6 张在用表**(输入点迹、TWS/TAS 凝聚后点迹、临时航迹、可靠航迹、点航关联信息),**可靠航迹与关联信息两通道均覆盖 TWS 与 TAS**(TAS 侧由 5cb67cc 补齐,关联信息以 `tas_flag` 区分来源),临时航迹与可靠航迹表还记录**航迹质量**(1ffb287:`RdpRecTempTrack.quality`、`RdpRecTrustTrack.Quality` 及 `Unupdated_time`/`Point_sum`/`Valid_point_sum`),并新增 `point_id`/`frame_id`/`circle_id`/`temp_track_id`/`track_id` 等关联标识,可把一次处理的点迹→凝聚→临时航迹→可靠航迹→关联信息串成完整链路;新增记录数据按「加记录实体 + 注册 + 加异步入队接口/宏 + 写线程分支 + 业务侧收集调用」四步进行,详见 docs/data_record_debug.md(见 4.3、10.4、11.3)。
---
## 3. 目录结构
```text
.
├── CMakeLists.txt # CMake 构建脚本(构建类型/记录模式、导出宏、输出目录)
├── CHANGELOG.md # 变更日志(Keep a Changelog 格式,按 git 提交记录维护)
├── README.md # 本文件:项目说明(架构、接口、流程、算法、参数)
├── requirements.md # 需求说明:雷达参数配置方式改造(TOML 配置文件 → RDP_parameter、parameters_reload 接口)
├── config/ # 参数配置文件目录
│ └── config_tmp.toml # 参数配置样例(TOML,11 个配置段,键名与 struct RDP_parameter 成员一致;样例为相扫取值)
├── archived_docs/ # 过期文档留档(仅作历史参考;接口与流程以本 README 与 docs/ 专项说明为准)
│ ├── BUG_REPORT.md # 全量逻辑 BUG 分析报告(P0~P3,37 项)
│ └── BUG_FIX_REPORT.md # BUG 修复报告(修复明细 + 编译验证结果)
├── docs/ # 专项说明文档(按当前源码整理,与 README 互补)
│ ├── data_process_flow_report.md # 数据处理流程与关键逻辑说明(前处理/判圈、凝聚、关联与滤波、起始、外推消亡、TAS 波束、参数脉络)
│ ├── track_init_readme.md # 航迹起始(Track Init)详细逻辑说明(阶段流程、条件汇总、输出字段映射、风险点、代码索引)
│ └── data_record_debug.md # 数据记录调试功能说明(开关与构建、异步运行期行为与队列/批事务参数、表结构约定、新增记录点四步配方、6 张在用记录表清单与字段、查询示例、已知限制与验证参考)
├── design_docs/ # 设计与讨论资料留档(被 .gitignore 忽略、不入库;含设计讨论、产品介绍与 README/流程报告的导出、渲染版本)
├── .vscode/ # VS Code 工程配置
│ ├── settings.json # cmake.generator=NMake、MSVC2022 x64 环境变量、构建目录=build/<构建类型>/<记录模式>、compile_commands
│ ├── cmake-variants.yaml # Release / Debug × REC_AUTO / REC_OFF / REC_ON 变体(机扫/相扫已合并,无体制维度)
│ ├── tasks.json # 仅 5 个任务:清理全部 + 4 种组合的「配置并构建」(原有任务已删除)
│ └── scripts/ # 构建脚本(纯 ASCII,避免 cmd 代码页问题)
│ ├── msvc_env.bat # 共享环境设置:定位 VS2022/cl.exe 并调用 vcvarsall.bat(x64)
│ ├── config_paths.bat # 按「构建类型/记录模式」推导构建目录并校验参数
│ ├── configure.bat # 单配置 CMake 配置(含旧工具集构建树自动清理)
│ ├── build.bat # 单配置 CMake 构建
│ ├── clean.bat # 单配置清理(删除该配置的构建目录)
│ ├── build_config.bat # 单配置「配置 + 构建」(4 个构建任务调用)
│ └── clean_all.bat # 清理全部配置的构建输出(含旧版 X256_PS/X256_MS 目录)
├── backup/
│ └── data_process_class_dll/
│ ├── data_process_class_dll.pro # 迁移前的 Qt/qmake 工程文件(备份)
│ └── data_process_class_dll.pro.user
├── third_party/ # 内置第三方源码(按上游原样保存,来源/版本/升级方式见其 UPSTREAM.md)
│ ├── ormpp/ # ormpp 0.2.0 + iguana 1.0.5 + frozen + SQLite 3.49.1 amalgamation(Apache-2.0 / 公有领域)
│ └── toml/
│ └── toml.hpp # toml++ v3.4.0 单头文件(MIT,仅参数加载器 rdp_parameter_loader.cpp 使用)
├── data_process_class_dll/ # 源码目录
│ ├── data_process_class_dll.h # 对外接口:DataRev/Track/TrackingBeam/Target_direct_tracking 结构体、抽象基类(公开成员 version_info、虚接口 parameters_reload)、工厂类
│ ├── data_process_class_dll_global.h # DLL 导入导出宏
│ ├── data_process_class_dll.cpp # 工厂实现(GetB/Destroy 单例)
│ ├── rdp_log.h / .cpp # 日志输出模块:rdbuf() 重定向 std::cout、RDP_LOG 宏(开关宏在 parameters.h)
│ ├── rdp_record.h / .cpp # 数据记录调试模块:结构体→SQLite 表(内置 ormpp)、异步入队接口与宏(RDP_RECORD_POINTS 等 6 个)+ 遗留 RDP_RECORD/RDP_RECORD_BATCH、有界队列、异步写线程、批量事务、Stats 统计、失败降级/熔断(开关由 CMake 选项 RDP_DATA_RECORD 控制;实现以 C++20 独立编译)
│ ├── rdp_record_entity.h # 记录实体(=数据表)定义区:6 张在用表(输入点迹、TWS/TAS 凝聚后点迹、临时航迹、可靠航迹、关联信息)+ RDP_RECORD_DECLARE 声明宏;新增需要记录的数据在此加结构体
│ ├── rdp_parameter_loader.h / .cpp # TOML 参数加载器(内部模块,不属于宿主接口):rdp_parameter_load() 严格校验 11 个配置段并写入 RDP_parameter,失败返回 -1 且不改变入参
│ ├── data_process.h / .cpp # Data_Process 实现:接口分发、TWS/TAS 主流程、参数加载(parameters_reload)、清空/删除/转跟踪;含 point_id/frame_id/circle_id 自增计数(记录用)
│ ├── struct.h # 内部结构体:PointRecv / Trust_Track / Temp_track / Asso_Info / Tracking_Target / RDP_parameter(工作参数,与 TOML 配置一一对应)
│ ├── parameters.h # 编译期常量:PI、版本宏、RDP_LOG_*、RDP_RECORD_*、MAX_TRACK_NUM、RDP_TAS_QUEUE_CAPACITY、Round(不再含雷达工作参数宏;机扫/相扫合并后构建不再定义体制宏,版本串为 V1.5.9.GENERIC)
│ ├── dot_coh.h / .cpp # TWS 点迹凝聚(含两帧滑窗缓冲)
│ ├── dot_coh_tas.h / .cpp # TAS 点迹凝聚
│ ├── coor_trans.h / .cpp # 极坐标 ↔ 直角坐标转换
│ ├── kalman.h / .cpp # 卡尔曼滤波:两点/三点初始化、线性 KF、EKF(含多普勒)、统计距离、盲速计算
│ ├── track_asso.h / .cpp # TWS 航迹关联:IMM 交互 → 滤波 → 输出、统计距离/高度/距离门限、高度平滑
│ ├── track_asso_tas.h / .cpp # TAS 航迹关联(独立实现,量测门限与数据率不同)
│ ├── track_init.h / .cpp # 逻辑法航迹起始:点-临时航迹关联、点-航迹头关联、转可靠航迹、屏蔽区
│ ├── track_init_direct_tracking.h/.cpp# 引导跟踪航迹起始(当前入口为空实现,未启用)
│ ├── track_asso_direct_tracking.h/.cpp# 引导跟踪航迹关联(未加入 CMake 构建)
│ ├── track_die.h / .cpp # TWS 航迹消亡
│ ├── track_die_tas.h / .cpp # TAS 航迹消亡
│ ├── tas_ctrl.h / .cpp # TAS 波束控制:目标队列增删、波束输出、禁止区判断
│ ├── track_index_mangement.h / .cpp # 航迹号 1~500 分配/复用
│ └── Eigen/ # 内置 Eigen 3 头文件库(仅用 Eigen/Dense)
├── build/ # 构建产物(被 .gitignore 忽略)
│ ├── Debug/ # Debug 构建根目录:REC_AUTO / REC_OFF / REC_ON
│ ├── Release/ # Release 构建根目录:REC_AUTO / REC_OFF / REC_ON
│ └── output/ # 早期打包导出(其中 data_process_class_dll.h 为旧版 32 位时间戳接口,勿作为当前 API 依据)
├── rdp_logs/ # 日志输出目录(运行时自动创建于宿主进程当前工作目录下,被 .gitignore 忽略)
├── rdp_records/ # 数据记录库输出目录(运行时自动创建于宿主进程当前工作目录下,被 .gitignore 忽略;仅记录功能启用时产生)
└── .gitignore
```
---
## 4. 构建与环境
### 4.1 环境要求
| 组件 | 要求 |
|---|---|
| 操作系统 | Windows(构建脚本默认按 D:\APP\VisualStudio2022 与 Windows SDK 10.0.26100.0 配置,可用环境变量覆盖) |
| 编译器 | Microsoft Visual C++ 2022(v143 工具集,`_MSC_VER` 19.44)**x64**(`D:\APP\VisualStudio2022\VC\Tools\MSVC\14.44.35207\bin\Hostx64\x64\cl.exe`) |
| C++ 标准 | C++17(`/std:c++17`;由 `CMAKE_CXX_STANDARD 17` + `CMAKE_CXX_STANDARD_REQUIRED ON` 强制) |
| CMake | ≥ 3.21(VS2022 生成器自 3.21 起支持;本工程实际在 CMake 4.x 上验证) |
| 生成器 | NMake Makefiles(VS Code 配置与脚本均使用该生成器) |
| 线性代数 | 无需安装——Eigen 头文件已内置在源码目录 |
| 参数配置 | 无需安装——配置文件为 TOML 格式,解析器 toml++ v3.4.0 已内置在 `third_party/toml/toml.hpp`(仅头文件);样例见 `config/config_tmp.toml`(见 10) |
| 数据记录(可选调试功能) | 无需安装——ormpp / iguana / frozen / SQLite amalgamation 已内置在 `third_party/ormpp`(版本与升级方式见该目录 UPSTREAM.md);启用时记录模块以 C++20 独立编译,所需的 C 编译器由同一 VS 2022 工具集提供 |
### 4.2 扫描模式(运行期配置)
机扫与相扫版本已合并为**同一份 DLL**:构建不再有扫描体制维度(`CMakeLists.txt` 不再有 `RADAR_SCAN_MODE` 缓存变量,也不再定义 `PHASE_SCANNING` / `MECHANICAL_SCANNING` 编译宏;`parameters.h` 的 `VERSION_INFO` 固定为 `"GENERIC"`,版本串为 `V1.5.9.GENERIC`)。扫描模式改由运行期配置项 `[radar_params] scan_mode` 决定(0 相扫 / 1 机扫),随全部工作参数由 TOML 配置文件经 `parameters_reload()` 载入(见 10);同一份 DLL 加载不同配置即可分别用于相扫 / 机扫部署,TWS 判圈行为随之切换(见 7.2)。
> **部署一致性提示**:DLL 不校验配置项 `scan_mode` 与实际雷达体制 / 波位号序列是否一致(不报错)。机扫部署须把 `scan_mode` 配为 1,并把 4 项体制相关参数按机扫取值:`extrapolate_max_tas=48`、`height_smooth_win=3`、`track_die_round_tas=96`、`tas_track_num_max=1`(样例 `config/config_tmp.toml` 为相扫取值,见 10.1)。判圈要求:相扫每圈波位号先增后回到起点、机扫每圈均出现 0。
构建只按「构建类型 × 记录模式」划分目录(见 4.3):
| 维度 | 取值 | 构建目录 |
|---|---|---|
| 构建类型 | Debug / Release | build/<Debug\|Release>/… |
| 记录模式 | REC_AUTO / REC_OFF / REC_ON | …/<REC_AUTO\|REC_OFF\|REC_ON> |
### 4.3 命令行构建
构建目录由「构建类型 + 记录模式」唯一确定(机扫/相扫已合并为同一版本,无扫描体制维度),构建脚本、VS Code 任务与 CMake Tools 变体使用同一布局:
```text
build/<Debug|Release>/<REC_AUTO|REC_OFF|REC_ON>
```
```bat
:: 单配置操作(参数:<Debug|Release> [AUTO|ON|OFF],记录模式缺省 AUTO)
:: 构建目录自动推导,例如 build/Release/REC_OFF
.vscode\scripts\configure.bat Release OFF
.vscode\scripts\build.bat Release OFF
.vscode\scripts\clean.bat Release OFF
```
```bat
:: 配置并构建单个配置(VS Code 任务「配置并构建(...)」的内部实现)
.vscode\scripts\build_config.bat Release OFF
.vscode\scripts\build_config.bat Release ON
.vscode\scripts\build_config.bat Debug OFF
.vscode\scripts\build_config.bat Debug ON
:: 清理全部配置的构建输出(VS Code 任务「清理全部」的内部实现)
.vscode\scripts\clean_all.bat
```
脚本内部通过 msvc_env.bat 调用 vcvarsall.bat x64 并校验 cl.exe,无需手工进入 MSVC 环境。configure.bat 会在每个构建目录写入 `.msvc_toolset` 标记;若该目录是用其它工具集(例如旧的 MSVC 2013 缓存)配置的,脚本会先整体删除该目录再重新配置,避免新旧目标文件混链。用 `set VS2022_DIR=...`、`set MSVC_TOOLSET_VERSION=...`、`set MSVC_TARGET_ARCH=x86` 可覆盖默认的 VS 安装路径、工具集版本与目标架构。
数据记录调试功能由缓存变量 `RDP_DATA_RECORD` 控制(取值 `AUTO`/`ON`/`OFF`,缺省 `AUTO`:Debug 启用、Release 关闭)。显式取值时构建目录名随之不同(`REC_OFF`/`REC_ON`),因此关闭与开启记录模块的产物可以并存。启用时配置阶段打印 `数据记录调试功能:启用(C++20 静态库 rdp_record + 内置 SQLite)`,并额外构建静态库 `rdp_record`(记录模块 + SQLite,链接进 DLL);关闭时打印 `...:关闭(不编译记录模块,RDP_RECORD 为空操作)`,记录模块源码完全不参与编译。开关语义、表结构约定与新增记录点配方见 docs/data_record_debug.md。
记录功能的性能参数集中在 `parameters.h` 的「数据记录性能参数」段(均以 `#ifndef` 保护,便于用 `/DRDP_RECORD_...` 编译选项临时覆盖做压测):入队队列上限 `RDP_RECORD_QUEUE_CAP_BYTES`(默认 64 MB)与 `RDP_RECORD_QUEUE_MAX_BATCHES`(默认 4096 批)、写线程批提交 `RDP_RECORD_WRITE_BATCH_ROWS`(默认 4096 行)/ `RDP_RECORD_WRITE_MAX_WAIT_MS`(默认 50 ms)、关联信息分块 `RDP_RECORD_ASSO_CHUNK_ROWS`(默认 131072 行)、SQLite 缓存/忙等待/WAL 开关(`RDP_RECORD_SQLITE_CACHE_KB`=8192、`RDP_RECORD_SQLITE_BUSY_TIMEOUT_MS`=2000、`RDP_RECORD_SQLITE_WAL`=1)、连续错误熔断阈值 `RDP_RECORD_MAX_CONSECUTIVE_ERRORS`(默认 10)与丢弃日志限频 `RDP_RECORD_DROP_LOG_INTERVAL`(默认 1024 行);默认值、语义与运行统计(`rdp_record::Stats`/`stats()`)见 10.4 与 docs/data_record_debug.md 第 3 节。
VS Code 任务(`.vscode/tasks.json`)只保留以下 5 个(原有任务已全部删除),可在「终端 → 运行任务」中选择,或按 `Ctrl+Shift+B` 运行默认构建任务「配置并构建(Release/REC_OFF)」:
| 任务 | 配置 |
|---|---|
| 清理全部 | 删除 `build/Debug`、`build/Release` 下所有配置的构建输出,并删除旧版 `build/X256_PS`、`build/X256_MS` 目录(`build/output` 留档不动) |
| 配置并构建(Release/REC_OFF) | Release + `RDP_DATA_RECORD=OFF`,单次配置并构建 |
| 配置并构建(Release/REC_ON) | Release + `RDP_DATA_RECORD=ON`,单次配置并构建 |
| 配置并构建(Debug/REC_OFF) | Debug + `RDP_DATA_RECORD=OFF`,单次配置并构建 |
| 配置并构建(Debug/REC_ON) | Debug + `RDP_DATA_RECORD=ON`,单次配置并构建 |
> 注意:`clean_all.bat` / `clean.bat` 会**整体删除**对应的配置目录(不再只做 `cmake --build --target clean`),因此自行放置到 `build/<Debug|Release>/<REC_*>/bin/` 的 rdp_playback.exe、Qt5Core.dll、sqlite3.dll 与回放数据也会被删除,清理后需重新放置——这类手工工具与样例数据建议放在 `build/output/` 或仓库之外。`settings.json`、`c_cpp_properties.json` 的默认 `compileCommands` 指向 `build/Debug/REC_ON/compile_commands.json`(便于 IntelliSense 覆盖记录模块代码);未构建该配置时 C/C++ 插件回退到内置 `includePath`/`defines`。
>
> 若此前用 CMake Tools 选择过变体(旧版本曾含 `scanMode` 变体、键名为 `ps`/`ms`/`X256_PS`/`X256_MS`),升级后请重新执行一次「CMake: Select Variant」——旧的变体选择会持久化在 workspaceStorage 中,移除扫描体制变体后需要重新选择,构建目录才会落到 `build/<Debug|Release>/<REC_*>`。
### 4.4 产物
| 产物 | 位置 |
|---|---|
| data_process_class_dll.dll(+ .pdb) | build/<Debug\|Release>/<REC_*>/bin/ |
| 导入库 data_process_class_dll.lib | build/<Debug\|Release>/<REC_*>/lib/ |
| 安装(cmake --install) | DLL/导入库 → bin、lib,公开头文件 → include |
| compile_commands.json | 各配置的构建目录根(供 VS Code IntelliSense 使用) |
| rdp_record.lib(仅记录功能启用时) | build/<Debug\|Release>/<REC_*>/lib/(仅 `REC_ON`,或 Debug 下的 `REC_AUTO` 才生成)—— 记录模块静态库(含 SQLite),已链接进 DLL,**无需随 DLL 分发** |
产物为 **x64(AMD64)** 目标。宿主程序必须是 64 位、且使用与本 DLL 同一版本头文件重新编译——MSVC 2013 → MSVC 2022 同时伴随 x86 → x64 的 ABI 变化,旧的 32 位宿主无法加载该 DLL。
> **本次参数配置改造后的体积/导出变化**:Release REC_OFF 的 `data_process_class_dll.dll` 为 331,776 字节(约 324 KB),较改造前约 178 KB 增大——原因是纯头文件的 toml++ 解析器随 `rdp_parameter_loader.cpp` 编入 DLL。机扫/相扫合并后的四种构建(0 warning、0 error):Release REC_OFF 331,776 字节、Release REC_ON 1,653,248 字节、Debug REC_OFF 1,718,272 字节、Debug REC_ON 4,694,528 字节。导出表(Release REC_OFF 共 31 个导出)新增 `parameters_reload`(`?parameters_reload@Data_process_class_dll@@UEAAHPEBD@Z`),`track_process_parameters_initial`/`track_process_parameters_modify` 与 `RadarPara` 相关符号已不存在,`Data_Process_Factory::GetB`/`Destroy` 等其余接口不变。
仓库 `build/<Debug|Release>/<REC_*>/bin/` 内原附带 **rdp_playback.exe**(回放测试工具,依赖 Qt5Core.dll、sqlite3.dll,配置样例 RadarConfigParam.ini,可回放 .db 记录的点迹数据验证 DLL 输出),该工具不在本仓库源码范围内、当前构建目录中亦不存在,需自行放置;由于 DLL 已改为 x64,配套的 rdp_playback.exe 必须是 **x64 版本**(同时其自带 Qt5Core.dll / sqlite3.dll 也需为 x64),32 位版本无法加载新版 DLL。
### 4.5 编译警告处理
- 源码文件统一使用 **带 BOM 的 UTF-8** 编码保存;`CMakeLists.txt` 对 MSVC 统一追加 `/utf-8`,中文字符串与注释不再受系统代码页影响(消除 C4819),BOM 仅作为编辑器/旧工具的兼容保留。
- `CMakeLists.txt` 显式指定 `/W3`:CMake 3.15(策略 CMP0092)起不再把 `/W3` 放进 `CMAKE_CXX_FLAGS`,本工程此前一直以 `/W3` 构建,故显式恢复以保持警告级别不变。
- 修复了 `/W3` 下全部 C4819(源文件字符集)、C4018(signed/unsigned 不匹配)、C4244(类型转换可能丢失数据)警告:循环变量按需改为 `size_t`,窄化转换改为 `static_cast` 显式转换,不改变原有计算逻辑。
- MSVC 2022 在 `/W3` 下新增报出的 C4267(`size_t` → `int` 窄化)共 17 处已按同一约定修复(`track_asso.cpp`、`track_asso_tas.cpp`、`track_init.cpp`、`track_init_direct_tracking.cpp`、`tas_ctrl.cpp` 中改为 `static_cast<int>(...)`),同样不改变计算逻辑。
- 当前 4 种显式配置(Release / Debug × REC_OFF / REC_ON)均以 **0 warning、0 error** 通过编译(机扫/相扫已合并为同一份构建,不再有 PS/MS 维度;REC_AUTO 与「Debug=ON / Release=OFF」等价,未重复单独验证)。
- cl.exe 的诊断信息为中文(跟随 VS 安装语言,`VSLANG=1033` 对 VS2022 的 cl.exe 无效),构建日志中偶见 `注意: 包含文件:` 行泄漏,属 CMake 依赖扫描的显示噪声,头文件依赖(`CMakeFiles/*.dir/**/*.obj.d`)记录完整,不影响增量编译。
- **第三方库告警例外(仅记录功能启用时)**:数据记录模块的第三方依赖按上游原样内置在 `third_party/ormpp`(保留上游字节,含换行符,不转 BOM/编码),其中 `third_party/ormpp/thirdparty/sqlite3/sqlite3.c` 以源文件级 `/w` 单独编译,`data_process_class_dll/rdp_record.cpp` 用 `#pragma warning(push, 0)` / `(pop)` 包裹第三方头;参数加载器使用的 toml++ 单头文件(`third_party/toml/toml.hpp`)同样在 `rdp_parameter_loader.cpp` 中以 `#pragma warning(push, 0)` / `(pop)` 包裹。除此之外本工程源码仍按上一条的 `/W3` 零告警标准编译(Release/Debug × REC_OFF/REC_ON 四种配置实测 0 warning、0 error)。
### 4.6 编译器升级说明(MSVC 2013 → MSVC 2022)
| 项目 | 升级前 | 升级后 |
|---|---|---|
| 编译器 | Microsoft Visual C++ 2013(VS 12.0,`_MSC_VER` 1800) | Microsoft Visual C++ 2022(v143,`_MSC_VER` 1944,cl 19.44.35228) |
| 目标架构 | x86(32 位) | x64(AMD64) |
| C++ 标准 | C++11(编译器默认) | C++17(`/std:c++17`) |
| CMake 最低版本 | 3.10 | 3.21 |
| 新增/调整编译选项 | — | `/utf-8`(改为无条件)、`/Zc:__cplusplus`、`/W3`(显式恢复) |
- **`/Zc:__cplusplus`**:MSVC 默认把 `__cplusplus` 报为 `199711L`,加该选项后正确报 `201703L`,使依赖 `__cplusplus` 判断的第三方库(内置 Eigen 3.3.7)走标准分支。已验证 Eigen 3.3.7 在此组合下编译通过。
- **`/Zc:strictStrings` 仍仅在 Release 启用**:原限制(MSVC 2013 Debug 运行库与该选项冲突)已不存在,此处保持与原 qmake 工程一致的行为。
- **旧构建目录需清理**:MSVC 2013 的 CMake 缓存与目标文件不能跨编译器复用(nmake 会因目标文件时间戳较新而跳过重编译,导致新旧目标文件混链)。`configure.bat` 已内置自动清理:构建目录中无 `.msvc_toolset` 标记或标记与当前工具集不一致时,先删除整个构建目录再配置。
- **源码改动**:仅补齐 17 处 `static_cast<int>(...)` 显式窄化转换以消除 MSVC 2022 新增的 C4267 告警,未改动任何计算逻辑、接口与结构体布局;DLL 导出符号与升级前一致(差异仅为 x86 → x64 的名称修饰,如 `QAE` → `QEAA`、`PAV` → `PEAV`)。
- **兼容性风险点已核查**:C++17 移除的 `std::auto_ptr`、`std::random_shuffle`、`std::unary_function`/`binary_function`、`std::binder1st/2nd` 等在本工程源码与内置 Eigen 3.3.7 中均未被使用(Eigen 的相应特化本身带有 `__cplusplus`/`EIGEN_COMP_MSVC` 版本保护)。
---
## 5. 总体架构
### 5.1 设计模式
- **接口 + 工厂(单例)**:Data_process_class_dll(抽象基类,声明全部虚接口)→ Data_Process(具体实现)。宿主仅通过 Data_Process_Factory::GetB() / Destroy() 获取与销毁唯一实例。
- **模块化流水线**:Data_Process 按职责组合 Dot_Coh、Dot_Coh_TAS、Track_Asso、Track_Asso_Tas、Track_Init、Track_Die、Track_Die_Tas、TAS_Ctrl、Track_Ind_Mangement 等模块,各模块持有自身处理缓存并支持 reset()。
```mermaid
classDiagram
class Data_process_class_dll {
<<abstract, exported API>>
+const char* version_info
+data_preprocess(DataRev[150]) int
+track_process(Track[][10], int*, int[], int*, int) int
+Beam_Ctrl(TrackingBeam*, Track[][10], int*)
+direct_tracking_process(...) int
+track_clear_all() int
+track_delete(int, int[]) int
+tracking_start(int) int
+tracking_stop(int) int
+tracking_point(float) int
+parameters_reload(const char*) int
}
class Data_Process {
-Data_buffer / Data_buffer_tas : vector PointRecv
-point_recv / point_recv_tas : vector PointRecv
-trust_track : vector Trust_Track
-temp_track : vector Temp_track
-rdp_parameter : RDP_parameter
-dot_coh / dot_coh_tas / track_asso / track_asso_tas
-track_init / track_die / track_die_tas / tas_ctrl
}
class Data_Process_Factory {
-static p : Data_process_class_dll*
+static GetB() Data_process_class_dll*
+static Destroy()
}
class Dot_Coh
class Dot_Coh_TAS
class Track_Asso
class Track_Asso_Tas
class Track_Init
class Track_Die
class Track_Die_Tas
class TAS_Ctrl
class Track_Ind_Mangement
class kalman
class coor_trans
Data_process_class_dll <|-- Data_Process
Data_Process_Factory ..> Data_Process : creates
Data_Process *-- Dot_Coh
Data_Process *-- Dot_Coh_TAS
Data_Process *-- Track_Asso
Data_Process *-- Track_Asso_Tas
Data_Process *-- Track_Init
Data_Process *-- Track_Die
Data_Process *-- Track_Die_Tas
Data_Process *-- TAS_Ctrl
Track_Init *-- Track_Ind_Mangement
Track_Asso ..> kalman
Track_Asso_Tas ..> kalman
Track_Init ..> kalman
kalman ..> coor_trans
```
### 5.2 模块职责
| 类 / 文件 | 职责 |
|---|---|
| Data_Process(data_process.cpp) | 对外接口实现与流程编排:输入缓存、按 model 分发 TWS/TAS 流水线、参数加载(`parameters_reload`:TOML → `rdp_parameter`)、航迹清空/删除、手动转/停 TAS、手动标记/取消重点目标(primary_target_add/cancel)、波束控制转发 |
| rdp_parameter_loader(rdp_parameter_loader.h/.cpp) | 参数加载器(内部模块):解析 TOML 并严格校验 11 个配置段/键集合/类型/取值范围/屏蔽区数组长度,全部通过后一次性写入 `RDP_parameter`;失败返回 -1 并给出首条原因、不改变入参(见 10.1) |
| Dot_Coh | TWS 点迹凝聚:两帧滑窗合并凝聚(dot_coh_process_buff) |
| Dot_Coh_TAS | TAS 点迹凝聚(单帧,距离/方位/速度三维门限) |
| Track_Asso | TWS 点航关联 + IMM 滤波:模型交互 → 门限筛选(NN)→ 各模型 EKF → 概率更新 → 模型输出(只输出 `Track_Update_Flag==1` 的航迹);未关联航迹按上限外推;高度平滑;按滤波速度矢量写 `Flag_Direction`;ΔT≤0(乱序/重复时间戳)的候选取出后不更新滤波、不刷新航迹,仅消费该点迹 |
| Track_Asso_Tas | TAS 航迹关联(只处理指定批号 tas_track_idx,门限与 TWS 略有差异;输出同样受 `Track_Update_Flag` 门控,外推上限 `extrapolate_max_tas` 的判定方向与 TWS 相反) |
| Track_Init | 逻辑法航迹起始,每圈顺序固定:点-临时航迹关联(延长 ≥2 点临时航迹)→ 点-航迹头关联(两点起始)→ 剩余点转新航迹头 → 长度达标者起批(三点卡尔曼初始化);另含起批屏蔽区判断与临时航迹消亡 |
| Track_Die / Track_Die_Tas | 可靠航迹消亡:**TWS 普通航迹按航迹质量**(V1.5.8:`Quality < 0.3`)、TWS 重点航迹按未关联轮数(10)、TAS 按未关联轮数(相扫 20、机扫 96),或手动删除标志置位时输出消亡批号并删除 |
| TAS_Ctrl | TAS 波束控制:手动目标入队(tas_target_add)、失效目标出队(tas_target_del)、跟踪波束预测输出(tas_beam_output:数据率门控 + 队内选择最早 CPI 目标)、调度时刻记录(last_track_time) |
| Track_Ind_Mangement | 航迹号 1~`track_index_max`(默认 500)的顺序分配与回绕复用 |
| kalman | 两点/三点滤波初始化、线性卡尔曼预测/滤波、EKF(3 维量测含多普勒)、马氏统计距离 d、盲速 Bind_speed |
| coor_trans | 极坐标 ↔ 直角坐标转换 |
| rdp_log(rdp_log.h/.cpp) | 日志输出:按 parameters.h 的 `RDP_LOG_ENABLE` 开关,在 `Init()` 中用 `rdbuf()` 将 `std::cout` 重定向到日期+时间命名的日志文件、`Shutdown()` 恢复控制台并关闭;提供 `RDP_LOG` 宏自动附加 `[时间戳][文件:行号]` 前缀 |
| rdp_record(rdp_record.h/.cpp、rdp_record_entity.h) | 数据记录调试(可选编译):由 CMake 选项 `RDP_DATA_RECORD` 决定是否参与编译。开启时 `GetB()` 建库并启动**独立写线程**,12 个记录点只做「帧/圈内收集源结构体 → 一次入队」;写线程从**有界队列**(默认 64 MB / 4096 批,满则整批丢弃并计入 `stats().dropped_rows`,不阻塞处理线程)取批,构造记录实体(数组转文本)并按表以**批量事务**写入 SQLite(达到 4096 行或等待 50 ms 提交;SQLite 使用 WAL + `synchronous=OFF` + 8 MB 缓存,建表后去掉 `AUTOINCREMENT`);写失败每表只提示一次并永久跳过该表、连续 10 次错误熔断;`Shutdown()` 依次停止入队、排空、`wal_checkpoint(TRUNCATE)`、关库并打印统计(`rdp_record::Stats`/`stats()` 可随时读取,`Destroy()`→`GetB()` 可重连重新建库)。**当前 6 个实体定义、6 张在用表**:`RdpRecPoint`(输入点迹,TWS/TAS 共用)、`RdpRecPointCohesionTWS`、`RdpRecPointCohesionTAS`、`RdpRecTempTrack`(含 `quality`)、`RdpRecTrustTrack`(含 `Quality`/`Unupdated_time`/`Point_sum`/`Valid_point_sum`,质量字段由 1ffb287 加入)、`RdpRecAssoInfo`(后两者 **TWS 与 TAS 两通道均写入**,关联信息以 `tas_flag` 区分来源),并有数组转字符串辅助 `arrayToString()`(用于把 `X`/`P` 等状态数组存为文本列);关闭(AUTO 的 Release 结果)时记录模块不参与编译、所有记录宏为空操作,旧 `RDP_RECORD`/`RDP_RECORD_BATCH` 仅作为遗留同步接口保留(会阻塞调用线程) |
| Track_Init_Direct_Tracking / Track_Asso_Direct_Tracking | 引导跟踪(direct tracking)专用起批/关联。**当前入口为空实现、未启用**;track_asso_direct_tracking.cpp 未加入 CMake 源列表 |
---
## 6. 关键数据结构
### 6.1 对外结构体(data_process_class_dll.h)
| 结构体 | 用途 | 要点 |
|---|---|---|
| DataRev | 输入点迹 | 距离(m)、方位/俯仰(°)、速度(m/s)、幅度/门限/SNR/RCS、码盘值、CPI/GNSS 时间(ms, long long)、方位波位(0-24)/俯仰波位(0-13)、PRI(µs,**不允许为 0**)、频点号、点数、点迹号、使用标记、TAS 批号、点迹类型、归一化幅度 `amp_asv`(dB)、速度维 FFT 点数 `prn_fftn`、十字星数据 speed_dim[129]/range_dim[8] |
| Track | 输出航迹 | 位置/速度、极坐标量、**航迹质量 `Quality`(0~100,V1.5.8 新增;插在 `Amplitude` 之后,宿主需同步重编译)**、航迹号、更新点数、方向标志 Flag_Direction(仅关联/外推输出路径赋值:按滤波速度矢量判定,1 靠近 / 0 远离,见 9.6;起批输出不写该字段)、实虚点标志 Flag_Point、一步预测、跟踪模式、航向角 Direction_Angle、目标类型、关联点信息、归一化幅度 `amp_asv_point` / 速度维 FFT 点数 `prn_fftn_point`、航迹时间(s)/GNSS、SNR/RCS、十字星数据透传 |
| TrackingBeam | TAS 跟踪波束指令 | open_flag、type、Range、Azi、Elev、TAS_track_index |
| Target_direct_tracking | 引导跟踪信息 | 批号、距离/方位/俯仰、开关(接口未启用) |
> 工作参数结构体 `RDP_parameter` 定义在内部头 `struct.h`,**不在公开头中导出**:宿主不再构造/下发参数结构体,改为通过 `parameters_reload(配置文件路径)` 把 TOML 配置加载进 DLL(参数含义见 10)。
### 6.2 内部结构体(struct.h)
| 结构体 | 用途 | 关键字段 |
|---|---|---|
| RDP_parameter | 工作参数(唯一来源) | 按注释分组:雷达工作参数(`radar_work_mode`/`freq_0_GHz`/`radar_height`/`radar_system_delay`/`data_rate_tws`/`data_rate_tas`/`data_rate_track_only`)、点迹凝聚参数、航迹关联参数(`sigma_*`/`associate_threshold`/`extrapolate_max(_tas)`/`height_smooth_win`)、航迹起始参数(`track_init_*`)、航迹消亡参数(`track_die_*`)、航迹质量参数(`track_quality_*`)、航迹批号(`track_index_max`)、波束调度(`default_track_beam_type`/`tas_track_num_max`)、singer 模型参数(`model_*_Q_*`)、两个屏蔽区(各 30 组距离/方位区间);与 TOML 配置段/键一一对应(见 10.2) |
| PointRecv | 内部点迹 | 距离/方位(弧度)/速度/幅度/高度/SNR/RCS/CPI/GNSS 时间、点迹号 `point_id` / 帧号 `frame_id` / 圈号 `circle_id`(记录链路用,c3c7e66 新增)、使用标志、波位/PRF/频点、跟踪模式、点迹区号、归一化幅度 `amp_asv_point` / 速度维 FFT 点数 `prn_fftn_point`、十字星数据 |
| Trust_Track | 可靠航迹(IMM 全状态) | 航迹号、标识字段 `track_id` / `point_id` / `circle_id`(b227ae1 新增,起批时取临时航迹末点的 `temp_track_id`/`point_id`/`circle_id`,关联成功时刷新为被关联点迹的 ID)、高度、极坐标量快照 `Range` / `Azimuth` / `Elevation` / `Velocity`(b227ae1 新增,仅在本圈有输出时回填)、**航迹质量相关状态(V1.5.8 新增)`Quality`(0~1)/ `Point_sum`(累计点数,含外推)/ `Valid_point_sum`(累计实点关联次数)/ `Unupdated_time`(连续未关联实点的累计毫秒)**、航迹时间 `T_track`(CPI 时间)/ `GNSS_time`、更新标志 Track_Update_Flag(**输出门控**:仅置 1 的航迹当圈被输出,输出后清零)、外推轮数 Extrapolate_round、实虚点标志、手动删除/手动 TAS/重点目标(primary_target_flag,决定消亡走质量还是 10 圈轮数)标志、关联点数、高度平滑缓冲 Hight_smooth、关联点信息、归一化幅度 `amp_asv_point` / 速度维 FFT 点数 `prn_fftn_point`、融合状态 X[6]/P[6][6]、三个子模型 X1/X2/X3、P1/P2/P3、模型概率 u[3] |
| Temp_track | 临时航迹(航迹起始阶段) | 4 维状态 X[4]/P[4][4]、极坐标点信息(`r`/`azi`/`vr`/`height`/`SNR`/`RCS`/`amplitude`)、**航迹质量 `quality`(0~1,V1.5.8 新增,起批时带给 Trust_Track)**、时间戳 `CPI_time` / `GNSS_time`、`buff_round`(已缓存圈数)、标识字段 `temp_track_id` / `point_id` / `circle_id`、区号 `temp_track_section_idx`、俯仰波位号 `pitch_num`、关联标志(c3c7e66 起字段统一更名,如原 `snr`/`Amp`/`T`) |
| Asso_Info | 点航关联候选(track_asso.cpp / track_asso_tas.cpp 共用) | `point_id` / `track_id` / `circle_id`、三模型统计距离 `d1`/`d2`/`d3` 与最小值 `d_min`、点迹/航迹下标、`delta_T`/`delta_h`/`R`/`VT`、来源标志 `tas_flag`(1 TAS / 0 TWS,5cb67cc 新增)、门限判定结果 `thd_d`/`thd_h`/`thd_r`、是否被最近邻取中 `min_d_flag`(b227ae1 提升到 struct.h;TAS 侧 5cb67cc 起改用同一结构) |
| Tracking_Target | TAS 队列元素 | 批号 Index、空标志 empty_flag、最近波束输出时间 last_track_time |
| Direct_Tracking_Target | 引导跟踪目标 | ID、方位/俯仰/距离、空标志 |
> 说明:Trust_Track 的状态布局为 [x, vx, ax, y, vy, ay],x/y 两轴解耦,每轴为「位置-速度-加速度」。
>
> ⚠ **结构体布局变更**:`DataRev` 新增 `amp_asv` / `prn_fftn`,`Track` 新增 `amp_asv_point` / `prn_fftn_point`;**V1.5.8 起 `Track` 又在 `Amplitude` 之后插入 `Quality`(之后字段整体后移)**,内部 `Trust_Track` / `Temp_track` 新增质量相关字段。宿主与 DLL 必须使用同一版本头文件并**同步重新编译**,否则字段错位。对外结构体中 `DataRev` 布局自 1.5.5 起未变化;原对外 `RadarPara` 已删除,`RDP_parameter` 仅在内部使用(宿主无需包含其定义)。
---
## 7. 外部接口与调用流程
### 7.1 接口一览
| 接口 | 返回值 | 说明 |
|---|---|---|
| Data_Process_Factory::GetB() | 实例指针 | 获取单例(首次调用时创建,并写入 `version_info`) |
| Data_Process_Factory::Destroy() | — | 销毁实例并将指针置空 |
| version_info(基类公开成员) | `const char*` | DLL 版本字符串,由 `GetB()` 赋值为 `VERSION_STRING`(`V1.5.9.GENERIC`——机扫/相扫已合并,无体制后缀);只读使用,不要释放(b227ae1) |
| parameters_reload(const char* path) | 0 成功 / -1 失败 | **加载全部工作参数**:解析 TOML 配置文件并校验,成功后整体替换内部 `RDP_parameter`;失败时当前参数保持不变并打印原因。建议 `GetB()` 后立即调用一次,重连/换配置时再次调用即可热重载(见 10.1) |
| data_preprocess(DataRev[150]) | 0/1/2/3 | 输入一帧点迹并缓存,返回处理模式(见下表) |
| track_process(Track[][10], &num, dieIdx[], &dieNum, model) | 1 | 按 data_preprocess 的返回值执行 TWS/TAS 处理 |
| Beam_Ctrl(TrackingBeam*, Track[][10], &num) | — | TAS 波束控制(内部清零并重填航迹输出计数) |
| track_clear_all() | 0 | 清空全部航迹/缓存并复位各模块状态 |
| track_delete(n, idx[]) | 0 | 按批号标记手动删除(下一轮消亡输出) |
| tracking_start(track_index) | 0 | 手动转 TAS 跟踪(置 manual_tracking_flag,由 Beam_Ctrl 入队) |
| tracking_stop(track_index) | 0 | 手动取消 TAS(清标志并 Track_Mode=0;队列项延至下一次 Beam_Ctrl 移除) |
| primary_target_add(track_index) | 0 | 手动将指定批号标为**重点目标**(置 `primary_target_flag=1`,消亡轮数放宽到 10 圈;批号不存在时不报错、无副作用) |
| primary_target_cancel(track_index) | 0 | 取消指定批号的重点目标标记(置 `primary_target_flag=0`,恢复普通航迹的消亡判据——V1.5.8 起为 `Quality < 0.3`) |
| tracking_point(azimuth) | 0 | 手动打跟踪波束——**未实现(保留空实现)** |
| direct_tracking_process(...) | 0 | 引导跟踪——**未实现(保留空实现)** |
> **输出语义(50e0b5c 起)**:`track_process(model=1/3)` 只把本圈**有更新**的航迹写入 `Trust_Track_Output`(关联到实点、外推成功,或 TAS 指定批号被更新),行数由 `Trust_track_num_Output` 给出;未更新(含外推超限)的航迹当圈不出现在输出中,宿主不能据输出行数推断航迹总数。输出数组内容由 DLL 覆盖写入指定行,其余行保持宿主原值(DLL 不清零整块数组)。
> 日志输出为 DLL 内部功能(不对外导出,接口见 10.4 的宏开关):首次 `GetB()` 创建实例时自动初始化(`RDP_LOG_ENABLE` 定义则将 `std::cout` 重定向到 `.\rdp_logs\` 下按日期+时间命名的日志文件,该宏当前为注释状态,见 10.4),`Destroy()` 销毁实例时恢复 `std::cout` 并关闭日志文件。
> 数据记录同样为 DLL 内部功能(不对外导出):记录功能启用时,`data_preprocess` 在帧内收集输入点迹(判圈 return 之前入队)、`dot_coh`/`dot_coh_tas` 收集凝聚后点迹、`track_init` 收集临时航迹、`track_asso`/`track_asso_tas` 收集可靠航迹与关联信息(关联信息按 `RDP_RECORD_ASSO_CHUNK_ROWS` 分块、函数返回前 flush),收集完成后各调用一次**异步入队**宏;实体构造与写库由记录写线程异步完成,落盘为 `.\rdp_records\rdp_record_YYYYMMDD_HHMMSS.db` 的 6 张在用表(表清单与字段见 docs/data_record_debug.md 第 7 节)。处理线程不会被记录 I/O 阻塞,但队列满时记录会整批丢弃(`stats().dropped_rows` 可查),进程异常退出时队列尾部与 WAL 尾部可能丢失。
### 7.2 data_preprocess 返回值的含义
| 返回值 | 含义 | 触发条件 |
|---|---|---|
| 0 | 无效数据 | point_type 既非 0 也非 1 |
| 1 | **TWS 满一圈,执行航迹处理** | point_type==0 且判圈条件成立:`scan_mode==0`(相扫)时当前帧方位波位号 ≤ 上一帧波位号 `last_beam_num`;`scan_mode==1`(机扫)时当前帧方位波位号 == 0 |
| 2 | **TWS 未满一圈,继续蓄数据** | point_type==0 且上述判圈条件不成立;调用 track_process(model=2) 做滑窗凝聚 |
| 3 | **TAS 处理** | point_type==1;同时记录 TAS_track_idx 与最新时间戳 |
> **判圈由配置项 `scan_mode` 运行时选择**:`data_process.cpp` 不再使用 `#ifdef PHASE_SCANNING` 编译期分支,而是按 `rdp_parameter.scan_mode` 选择两条判据——`scan_mode==0`(相扫)走「波位号不变大(当前 ≤ 上一帧)即为新一圈」(`last_beam_num` 参与判断,`track_clear_all()` 复位为 INT_MAX,故**相扫首帧即返回 1**);`scan_mode==1`(机扫)走 7d5a56f 的「方位波位号 == 0」判据(机扫转台反转时波位号会变小但并未扫完一圈,用波位号比较会误判;此时 `last_beam_num` 仍被更新但不参与判断)。两种模式下 `last_beam_num` 每帧都会更新,仅判满圈时 `circle_id++` 并返回 1。因此同一份 DLL 的判圈行为只取决于加载的配置(构建已不区分扫描体制),调用方需保证 `scan_mode` 与实际波位号序列/部署体制一致:相扫要求每圈波位号先增后回到起点、机扫要求每圈均出现 0。
### 7.3 典型调用序列
```mermaid
flowchart TD
A["Data_Process_Factory::GetB()"] --> B["parameters_reload(参数配置文件路径)"]
B --> C{"接收一帧点迹"}
C --> D["model = data_preprocess(DataRev[150])"]
D --> E{"model ?"}
E -- "2 (TWS 蓄数据)" --> F["track_process(model=2) 滑窗凝聚"]
E -- "1 (TWS 一圈)" --> G["track_process(model=1) 关联/起批/消亡"]
E -- "3 (TAS)" --> H["track_process(model=3) TAS 关联/消亡"]
E -- "0" --> C
F --> C
G --> I["Beam_Ctrl() 输出跟踪波束"]
H --> I
I --> J{"手动操作?"}
J -- 是 --> K["tracking_start / tracking_stop / track_delete"]
K --> C
J -- 否 --> C
C -. "结束/重连" .-> L["track_clear_all() / Factory::Destroy()"]
```
---
## 8. 处理流程总览
### 8.1 TWS 流程(model=1)
```mermaid
flowchart TD
A["data_preprocess: 点迹入 Data_buffer(度→弧度、高度=Range·sin(Elev)、时间戳缓存)"] --> B["判圈成立(由配置 scan_mode 选择:0 相扫: 波位号 ≤ 上一帧 / 1 机扫: 波位号 == 0)→ model=1"]
B --> C["track_process(1)"]
C --> D["dot_coh 两帧滑窗凝聚 → point_recv"]
D --> E["track_asso: IMM 交互 → 点航波门筛选(NN)→ EKF 滤波 → 模型输出"]
E --> F["track_die: 连续未关联超限 / 手动删除 → 输出消亡批号"]
F --> G["track_init: 点-临时航迹关联 → 点-航迹头关联 → 剩余点转新航迹头 → 起批转可靠航迹"]
G --> H["输出 Trust_Track_Output(含起批历史点)"]
H --> I["Beam_Ctrl: 手动 TAS 目标入队 / 波束输出"]
```
其中 model=2(未满一圈)只执行滑窗凝聚 dot_coh_process_buff,把上一帧凝聚完成的点输出到 point_recv 供下一圈的关联/起批使用,当前帧未凝聚点作为下一次的缓存——即「凝聚在前、关联在后、缓存一帧」的两帧滑窗结构。
输出环节(`track_asso_process()` 末尾)只写 `Track_Update_Flag==1` 的航迹:关联到实点、或外推成功(`Extrapolate_round <= extrapolate_max`,样例 3)时置 1;外推超限的航迹不再推进位置与航迹时间,当圈也不输出,直到重新关联上实点才恢复(详见 9.9)。
### 8.2 TAS 流程(model=3)
```mermaid
flowchart TD
A["data_preprocess: 点迹入 Data_buffer_tas,记录 TAS_track_idx/latest_timestamp → model=3"] --> B["track_process(3)"]
B --> C["dot_coh_tas 单帧凝聚 → point_recv_tas"]
C --> D["track_asso_tas: 仅对 tas_track_idx 批号做 IMM+EKF 关联(含高度门限)"]
D --> E["未关联 → 按 latest_timestamp 外推(ΔT≤0 跳过)"]
E --> F["track_die_tas: TAS 连续未关联超上限 / 手动删除 → 消亡输出"]
F --> G["输出该批号航迹(point_type=1)"]
G --> H["Beam_Ctrl: 数据率门控 + 队内最早 CPI 目标 + 预测波束输出"]
```
TAS 输出同样受 `Track_Update_Flag` 门控:只有 `Track_Index == tas_track_idx` 且本圈有更新(关联到实点、或外推成功)时才向 `Trust_Track_Output` 写一行(`point_type=1`)。TAS 外推上限为配置项 `extrapolate_max_tas`(样例配置为相扫 5,机扫需配 48),判定方向与 TWS 相反(`Extrapolate_round >= 上限` 时才外推并输出),详见 9.9 与 11.2。
### 8.3 航迹起始流程(逻辑法)
```mermaid
flowchart TD
A["本圈未关联点迹(point_recv → point_process)"] --> A1["临时航迹所有点的 buff_round +1"]
A1 --> B["① 点-临时航迹关联(≥2 点临时航迹、末点 buff_round≥2):EKF 统计距离波门 d²≤64、折角<60°、径向速度同号、|Δr|≥5m → 复制原航迹并追加新点"]
B --> C["② 点-航迹头关联(1 点航迹头、buff_round≥2):track_init_velocity_min·ΔT ≤ dis ≤ track_init_velocity_max·ΔT、径向速度同号、dis ≥ |vr_point|·ΔT 且 dis ≥ |v_track_head|·ΔT → 两点卡尔曼初始化(航迹头 + 新点 → 2 点临时航迹)"]
C --> D["③ 删除 Use_Flag==1 的点迹,剩余点全部转为新航迹头 Temp_track(1 点、buff_round=1)"]
D --> E{"④ 长度 ≥ track_init_point_num_min(3~9) 且 ≤10 且不在起批屏蔽区 ?"}
E -- 是 --> F["重复航迹去重(保留末点 d 更小者)→ 三点卡尔曼初始化"]
F --> G["转可靠航迹:分配航迹号 1~track_index_max(默认 500),IMM 三模型同状态初始化 u=1/3"]
G --> H["输出前 track_init_point_num_min 个历史点 Trust_Track_Output[i][0..L-1]"]
E -- 否 --> I["留在临时航迹表,下一圈继续关联"]
H --> J["⑤ 临时航迹消亡:末点 buff_round>2 或 长度≥10"]
I --> J
```
> 顺序说明:`track_init_process_logic()` 中四步的先后顺序固定、不可颠倒——先延长已有临时航迹,再与航迹头配对,两步都走完才生成新航迹头,最后才把长度达标的临时航迹转为可靠航迹(因此当圈新建的 2 点临时航迹不可能当圈起批,长度刚达标的临时航迹则可以当圈起批);临时航迹消亡在第 ⑤ 步、即全部起始动作之后执行。
>
> 第 ① ② 步**互不排斥**:两者都只把命中的点迹标记 `Use_Flag=1`,航迹头关联并不检查临时航迹关联留下的标记,因此同一点迹可能既延长一条临时航迹、又开启一条新的两点临时航迹;两类关联也都不做一对一分配(同一条临时航迹可被本圈多个点延长,同一个航迹头也可与本圈多个点配对)。只有走完两步后才统一删除 `Use_Flag==1` 的点迹,其余点迹成为新航迹头。
---
## 9. 算法实现详解
### 9.1 坐标与量测转换
极坐标(距离 r、方位 θ,弧度)与直角坐标互转(coor_trans.cpp):
$$
x=r\cos\theta,\qquad y=r\sin\theta
\qquad\qquad
r=\sqrt{x^2+y^2},\qquad \theta=\operatorname{atan2}(y,x)\ \bmod 2\pi
$$
输入点高度由量测俯仰直接折算:h = R·sin(ε)(data_preprocess 中完成)。输出时航迹高度加雷达平台高度:z = h + H_radar。
**转换量测协方差**(用于以直角坐标为量测的线性滤波,kalman.cpp 中多处使用)。设 λθ = exp(-σa²/2)、λθ' = exp(-2σa²),则在量测 (r,θ) 处转换后的直角坐标量测噪声协方差为:
$$
R_{xx}=\left(\lambda_\theta^{-2}-2\right)r^2\cos^2\theta+\tfrac12\left(r^2+\sigma_r^2\right)\left(1+\lambda'_\theta\cos 2\theta\right)
$$
$$
R_{yy}=\left(\lambda_\theta^{-2}-2\right)r^2\sin^2\theta+\tfrac12\left(r^2+\sigma_r^2\right)\left(1-\lambda'_\theta\cos 2\theta\right)
$$
$$
R_{xy}=\left(\lambda_\theta^{-2}-2\right)r^2\sin\theta\cos\theta+\tfrac12\left(r^2+\sigma_r^2\right)\lambda'_\theta\sin 2\theta
$$
其中 σr、σa 取自配置项 `sigma_range` / `sigma_azimuth`(默认 10 m / 0.02 rad,见 10.2)。
### 9.2 点迹凝聚
对同一 CPI(TWS 为相邻两 CPI 合并后)内所有点迹两两比较,门限满足且幅度较小者被标记删除(Use_Flag=1):
| 模式 | 距离门限 | 方位门限(环绕最小角差) | 速度门限 |
|---|---|---|---|
| radar_work_mode==0(近程) | ≤ 80 m(point_cohesion_range) | ≤ 6°(point_cohesion_azimuth) | ≤ 2 m/s(point_cohesion_velocity) |
| radar_work_mode!=0(中/远程) | ≤ 80 m | ≤ 6° | 不约束 |
方位差按环绕角处理:
$$
\Delta\theta = \min\left(|\theta_0-\theta_1|,\ 2\pi-|\theta_0-\theta_1|\right)
$$
凝聚后删除量程外的点(下限/上限由配置项 `point_cohesion_range_min` / `point_cohesion_range_max` 给定,默认 100 m / 100000 m)。TWS 的 dot_coh_process_buff 将上一帧缓存点标记区号 1、当前帧点标记区号 2,合并凝聚后:区号 1 的点输出到 point_recv(进入关联),区号 2 的点存入 data_input_buff 供下一帧凝聚——形成两帧滑窗。
### 9.3 航迹起始(逻辑法)
每圈(model=1)在 `track_init_process_logic()` 中按**固定顺序**执行下列四步,顺序不可颠倒:
1. **点-临时航迹关联**:本圈未关联点迹优先延长已有的 ≥2 点临时航迹(判据见 (1));
2. **点-航迹头关联**:随后点迹与 1 点航迹头配对,产生新的 2 点临时航迹(判据见 (2));
3. **剩余点迹转航迹头**:前两步只把命中的点迹标记为已使用(`Use_Flag=1`),两步都做完后才统一删除这些点迹,其余点迹逐条转为新航迹头(见 (3));
4. **转可靠航迹(起批)**:长度达标的临时航迹经三点卡尔曼初始化转为可靠航迹(见 (4));起批动作完成后才消亡不满足条件的临时航迹。
> 两点补充:① 第 1、2 步**互不排斥**——航迹头关联不检查临时航迹关联留下的 `Use_Flag`,因此同一点迹可能既延长一条临时航迹、又开启一条新的两点临时航迹;两类关联也都不做一对一分配(同一条临时航迹可被本圈多个点延长,同一个航迹头也可与本圈多个点配对)。② 每圈入口先把**所有**临时航迹所有点的 `buff_round` 加 1 再做关联,新建点(航迹头或被关联上的新点)`buff_round = 1`,因此当圈新建的 2 点临时航迹要到下一圈末点 `buff_round` 变为 2 之后才参与第 1 步。
#### (1) 点-临时航迹关联(延长 ≥2 点临时航迹)
对 ≥ 2 点的临时航迹(末点 buff_round ≥ 2),用航迹末点状态做 EKF 一步预测,计算三维(距离-方位-径向速度)马氏统计距离 d(见 9.5.3),并要求 |r_point − r_temp| ≥ 5 m,同时满足:
$$
d^2 \le track\_init\_threshold^2 = 64,\qquad
\alpha < track\_init\_angle = 60°,\qquad
v_{r,point}\cdot v_{r,track}>0
$$
折角 α 为最近三点连线夹角(度):
$$
\alpha=\arccos\left(\frac{\vec{D_{12}}\cdot\vec{D_{23}}}{\|\vec{D_{12}}\|\,\|\vec{D_{23}}\|}\right)\cdot\frac{180}{\pi}
$$
关联成功后**复制原临时航迹并追加该点迹**,新航迹的 4 维状态用最近两点做**两点卡尔曼初始化**(见 9.5.2)重新得到。同一处(V1.5.8 起)随即重算该临时航迹的**航迹质量**:长度恰为 3 时对三点写入同一质量值,长度 >3 时只更新末点(指数平滑),详见 9.11。
#### (2) 点-航迹头关联(两点起始)
对单点航迹头(buff_round ≥ 2),量测点需同时满足以下四个条件(7d5a56f 起的判据):
$$
V_{min}\Delta T \le d_{12} \le V_{max}\Delta T,\qquad
v_{r,point}\cdot v_{r,head}>0,\qquad
d_{12} \ge \left|v_{r,point}\right|\Delta T,\qquad
d_{12} \ge \left|v_{r,head}\right|\Delta T
$$
其中 d12 为两点间平面距离,ΔT 为时间差(秒),V_min/V_max 取配置项 `track_init_velocity_min` / `track_init_velocity_max`(默认 1 / 50 m/s;代码中 vmax 的近程/中远程分支取值相同)。后两条为**多普勒-几何一致性约束**:切向飞行目标在 ΔT 内的实际位移远小于 |vr|·ΔT,据此被排除,用于限制切向高速点迹起批出的短航迹。
> 历史行为(已注释停用):原先按扫描体制与距离分段收紧速度门限——近程 r≥1000 用全速、r<1000 用半速;中远程 r≥2000 用全速、r<2000 取下限 1/2·最小速度·ΔT / 上限 1/3·最大速度·ΔT。
关联成功用 **两点卡尔曼初始化**(见 9.5.2)生成 2 点临时航迹:第 1 点为原航迹头,第 2 点为该点迹。
#### (3) 剩余点迹转航迹头
第 (1)(2) 步结束后统一删除 `Use_Flag==1` 的点迹;剩余点迹回写 `point_recv`(随后被整体清空),并**逐条新建 1 点临时航迹(航迹头)**:位置直接取点迹的直角坐标、速度置 0、`buff_round = 1`。新航迹头当圈不再参与任何关联,只能从下一圈开始按第 (2) 步配对。
#### (4) 转可靠航迹(起批)
临时航迹长度 N 满足 track_init_point_num_min ≤ N ≤ 10(起批点数由配置项 `track_init_point_num_min` 给定,默认 3,加载器校验 3~9)、不在起批屏蔽区内(屏蔽区为距离-方位矩形区域,最多 30 个)**且航迹质量达到该长度对应的门限**(V1.5.8 新增,见 9.11)时进入起批队列;同源(前三点时间/距离相同)的重复航迹只保留 d 较小者(比较下标 `track_init_point_num_min-1` 处的 d)。起批时令 L = track_init_point_num_min,用航迹中下标 L-3、L-2、L-1 的三个点做 **三点卡尔曼初始化** 得到 6 维状态(航迹长度恰为 L 时即最近三点),构造 Trust_Track:
- 三个 IMM 子模型用同一状态/协方差初始化,模型概率 u = [1/3, 1/3, 1/3];
- 质量状态初始化:`Quality` = 临时航迹末点质量,`Point_sum` = `Valid_point_sum` = L,`Unupdated_time` = 0;
- 分配航迹号(1~500,见 9.8);
- 输出仅写入前 L 个历史点(`Trust_Track_Output[i][0..L-1]`,`Point_Sum = L`),每点写入 `Quality = 该点临时航迹质量 × 100`;航迹长度大于 L 时其余点不输出;
- 起批输出不写 `Flag_Direction`、`x_Predict/y_Predict/z_Predict`、`Range_Predict/Azimuth_Predict/Elevation_Predict`、`Target_Type`、`prf_point`、`v_z` 等字段,且 DLL 不清零输出数组,宿主读到的是自身缓存的旧值(详见 docs/track_init_readme.md 第 14 节)。
### 9.4 IMM 框架(3 个 Singer 模型)
TWS/TAS 关联共用同一套 IMM 结构(代码各自实现一份)。状态 [x, vx, ax, y, vy, ay],x/y 两轴解耦,机动相关时间常数固定 α = 0.2。
**模型转移概率矩阵**:
$$
P_t=\begin{bmatrix}0.8&0.15&0.05\\0.3&0.4&0.3\\0.05&0.15&0.8\end{bmatrix}
$$
**交互(mix)**:归一化常数与混合概率
$$
\bar c_j=\sum_{i}p_{ij}\,\mu_i,\qquad
\mu_{i|j}=\frac{p_{ij}\,\mu_i}{\bar c_j}
$$
混合状态 X0j = Σ μ(i|j) Xi,混合协方差 P0j = Σ μ(i|j) [Pi + (Xi − X0j)(Xi − X0j)ᵀ](实现中对 c̄j 做了 ≥ 1e-12 钳位防除零)。
**子模型滤波**:每个模型以各自的 F、Qj 做 EKF 预测/更新(9.5)。
**模型概率更新**:以新息协方差行列式归一化的高斯似然
$$
\Lambda_j=\frac{1}{\sqrt{(2\pi)^3\det S_j}}\exp\left(-\tfrac12 d_j\right),\qquad
\mu_j'=\frac{\Lambda_j\,\bar c_j}{\sum_k \Lambda_k\,\bar c_k}
$$
其中 dj 为该模型的马氏距离平方。实现中 det Sj ≤ 1e-12 时 Λj = 0,分母 ≤ 1e-12 时保持上一拍概率。
**输出融合**:
$$
\hat X=\sum_j\mu_j'\hat X_j,\qquad
P=\sum_j\mu_j'\left[P_j+\left(\hat X_j-\hat X\right)\left(\hat X_j-\hat X\right)^T\right]
$$
### 9.5 卡尔曼滤波
#### 9.5.1 Singer 模型状态转移与过程噪声
每轴状态转移矩阵(α = 0.2,T = ΔT 为时间差,秒):
$$
F_{axis}=\begin{bmatrix}
1 & T & \dfrac{\alpha T-1+e^{-\alpha T}}{\alpha^2}\\[2mm]
0 & 1 & \dfrac{1-e^{-\alpha T}}{\alpha}\\[2mm]
0 & 0 & e^{-\alpha T}
\end{bmatrix}
,\qquad
F=\begin{bmatrix}F_{axis}&0\\0&F_{axis}\end{bmatrix}
$$
过程噪声 Qj = qj · Q̄,Q̄ 每轴为对称矩阵,元素为 Singer 模型离散化的标准结果:
$$
\bar q_{11}=\frac{1}{2\alpha^5}\left[1-e^{-2\alpha T}+2\alpha T+\frac{2\alpha^3T^3}{3}-2\alpha^2T^2-4\alpha T e^{-\alpha T}\right]
$$
$$
\bar q_{12}=\frac{1}{2\alpha^4}\left[e^{-2\alpha T}+1-2e^{-\alpha T}+2\alpha T e^{-\alpha T}-2\alpha T+\alpha^2T^2\right]
$$
$$
\bar q_{13}=\frac{1}{2\alpha^3}\left[1-e^{-2\alpha T}-2\alpha T e^{-\alpha T}\right]
$$
$$
\bar q_{22}=\frac{1}{2\alpha^3}\left[4e^{-\alpha T}-3-e^{-2\alpha T}+2\alpha T\right]
$$
$$
\bar q_{23}=\frac{1}{2\alpha^2}\left[e^{-2\alpha T}+1-2e^{-\alpha T}\right],
\qquad
\bar q_{33}=\frac{1}{2\alpha}\left[1-e^{-2\alpha T}\right]
$$
过程噪声强度 qj 按航迹速度分档(对应三个机动等级):
| 模型 | TWS 版(track_asso.cpp) | TAS 版(track_asso_tas.cpp) |
|---|---|---|
| 模型 1(低机动) | q1 = model_1_Q_slow(恒定) | 同左 |
| 模型 2(中机动) | v≤5: slow/20;5<v≤30: slow;v>30: fast | v≤5: slow/20;50<v≤100: 10·fast;其余: fast |
| 模型 3(高机动) | v≤5: slow/20;5<v≤20: slow;20<v≤50: fast;50<v≤100: 2·fast;v>100: 10·fast | v≤5: slow/20;50<v≤100: 10·fast;其余: fast |
> 注意:`model_1_Q_fast` 配置项当前未参与计算(模型 1 只用 slow);各档系数以源码为准,对应配置文件 `[singer_model]` 段(见 10.2)。
#### 9.5.2 两点初始化(临时航迹,4 维)
两直角量测 Z0=(x0,y0)、Z1=(x1,y1),时间差 T:
$$
X=[x_1,\ (x_1-x_0)/T,\ y_1,\ (y_1-y_0)/T]^T,\qquad
P_{axis}=\begin{bmatrix}R&R/T\\R/T&2R/T^2\end{bmatrix}
$$
其中 R 为 Z1 处的转换量测协方差(9.1)。x/y 轴独立填充 P[4][4]。
#### 9.5.3 三点初始化(可靠航迹,6 维)
三点 Z0, Z1, Z2,时间差 T1, T2,取末点与差分近似速度/加速度:
$$
X=\left[x_2,\ \frac{x_2-x_1}{T_2},\ \frac{(x_2-x_1)/T_2-(x_1-x_0)/T_1}{(T_2+T_1)/2},\
y_2,\ \frac{y_2-y_1}{T_2},\ \frac{(y_2-y_1)/T_2-(y_1-y_0)/T_1}{(T_2+T_1)/2}\right]^T
$$
协方差按误差传播由 R0, R1, R2(各点转换量测协方差)构造,x 轴块 P11 形式为:
$$
P_{11}=\begin{bmatrix}
R_2^{xx} & R_2^{xx}/T_2 & \dfrac{R_2^{xx}/T_2}{(T_2+T_1)/2}\\[1mm]
R_2^{xx}/T_2 & \dfrac{R_2^{xx}+R_1^{xx}}{T_2^2} & \dfrac{(R_2^{xx}+R_1^{xx})/T_2^2+R_1^{xx}/(T_1T_2)}{(T_1+T_2)/2}\\[1mm]
\dfrac{R_2^{xx}/T_2}{(T_2+T_1)/2} & \dfrac{(R_2^{xx}+R_1^{xx})/T_2^2+R_1^{xx}/(T_1T_2)}{(T_1+T_2)/2} & \dfrac{4\left[(R_2^{xx}+R_1^{xx})/T_2^2+(R_1^{xx}+R_0^{xx})/T_1^2+2R_1^{xx}/(T_1T_2)\right]}{(T_1+T_2)^2}
\end{bmatrix}
$$
P12(x-y 交叉块)、P22(y 轴块)同构,把 Rxx 换成 Rxy、Ryy。
> ⚠ 当前实现未对 T=0 的重复时间戳做除零保护(BUG-18,暂不修复),调用方需保证点迹时间严格递增。
#### 9.5.4 线性卡尔曼滤波(二维直角量测)
标准预测/更新:
$$
\hat X_{k|k-1}=F\hat X_{k-1},\qquad
P_{k|k-1}=FP_{k-1}F^T+Q
$$
$$
S=HP_{k|k-1}H^T+R,\qquad
K=P_{k|k-1}H^TS^{-1}
$$
$$
\hat X_k=\hat X_{k|k-1}+K\left(Z-H\hat X_{k|k-1}\right),\qquad
P_k=\left(I-KH\right)P_{k|k-1}
$$
H 为位置选择矩阵(6 维状态取 x/y)。统计距离(马氏距离平方):
$$
d=\nu^T S^{-1}\nu,\qquad \nu=Z-H\hat X_{k|k-1}
$$
此形式用于两点临时航迹的门限 d_cal_track_init(CV 模型 FCV、Q=(0.03)²I)。
#### 9.5.5 扩展卡尔曼滤波(距离-方位-径向速度量测)
量测向量 Z = [r, θ, vr],非线性量测函数(由预测状态计算):
$$
h(\hat X)=\begin{bmatrix}r\\\theta\\v_r\end{bmatrix}=
\begin{bmatrix}\sqrt{x^2+y^2}\\ \operatorname{atan2}(y,x)\bmod 2\pi\\ -\dfrac{x\,v_x+y\,v_y}{\sqrt{x^2+y^2}}\end{bmatrix}
$$
雅可比(在预测点处线性化):
$$
H=\frac{\partial h}{\partial X}=
\begin{bmatrix}
\dfrac{x}{r}&0&0&\dfrac{y}{r}&0&0\\[2mm]
-\dfrac{y}{r^2}&0&0&\dfrac{x}{r^2}&0&0\\[2mm]
-\dfrac{y(v_xy-v_yx)}{r^3}&-\dfrac{x}{r}&0&-\dfrac{x(v_yx-v_xy)}{r^3}&-\dfrac{y}{r}&0
\end{bmatrix}
$$
量测噪声 R = diag(σr², σa², σv²)。新息与增益/更新同 9.5.4,并做两项残差修正:
- **方位环绕**:νθ = wrapToPi(θ_mea − θ_pred),归一到 [-π, π);
- **多普勒盲速折叠**:νv = νv − Round(νv / v_bind)·v_bind,其中盲速
$$
v_{bind}=\frac{150000}{f_{GHz}\cdot PRI_{µs}}\quad(\mathrm{m/s}),\qquad
f_{GHz}=9.2+0.02\cdot f_{ind}
$$
(PRI ≤ 0 或 f ≤ 0 时返回安全值 1.0,接口约定 PRI 不允许为 0。)
关联判定与模型似然共用 d = νᵀS⁻¹ν,滤波后输出完整 3×3 新息协方差 S 供似然归一化使用(BUG-24 已修复)。
### 9.6 点航关联(最近邻)
#### TWS(track_asso.cpp)
对每条航迹 × 每个点计算三模型 d1, d2, d3,波门按航迹距离分段(`associate_threshold = 4`,配置项 `[track_associate] associate_threshold`,判据写作 `d*d < associate_threshold*associate_threshold`,而 d 本身已是马氏距离平方,故下表的等价门限为 d < 4):
| 航迹距离 | 模型 1/2 门限 | 模型 3 门限 |
|---|---|---|
| r_track ≤ 500 m | d_i² < 16 | d_3² < 16/1000(≈关闭) |
| 500 < r_track < 1000 m | d_i² < 16 | d_3² < 16/100(收紧) |
| r_track ≥ 1000 m | d_i² < 16 | d_3² < 16 |
关联判据在 `model_filter()` 中拆为三个布尔量,三者同时通过才记为候选:`thd_d`(上表统计距离门限)、`thd_h`(高度门限)、`thd_r`(距离门限)。
- **高度门限 thd_h**(e0bf227 起生效):以 |h_track − h_point| 与航迹距离分段比较,取值与 TAS 通道一致——≤ 1000 m 时 ≤ 150 m、1000~2000 m 时 ≤ 200 m、2000~3000 m 时 ≤ 250 m、3000~5000 m 时 ≤ 300 m、> 5000 m 时不约束。该项原为注释停用的代码块(等价于恒通过),现正式参与关联判定,用于压制俯仰测量跳变引起的错误关联;
- **俯仰门限 d_p**:分距离段 7°/5°/10° 的逻辑仍在源码中注释停用,不参与判定(其作用已由高度门限覆盖);
- **距离门限 thd_r**:以航迹-点迹弦距 R = √(r_t² + r_p² − 2·r_t·r_p·cos Δθ)(Δθ 为环绕方位差)与航迹速度位移 VT = v_track·ΔT 判断:
$$
VT<100\ \text{且}\ R>300\ \Rightarrow 拒绝;\qquad
100\le VT\le300\ \text{且}\ R/VT>3\ \Rightarrow 拒绝;\qquad
VT>300\ \text{且}\ R>1200\ \Rightarrow 拒绝
$$
候选对按 d_min = min(d1,d2,d3) 全局排序,**最近邻**原则逐个取点:每条航迹每圈最多关联一个点、每个点只属于一条航迹。关联成功后:三模型分别 EKF 更新 → 模型概率更新 → 更新航迹时间/幅度/SNR/RCS/十字星数据 → 高度平滑。
**靠近/远离方向标志 Flag_Direction(fc49707 起、42b598e 调整,TWS/TAS 同步)**:不再使用实测径向速度(原 `Flag_Direction = vr_point > 0 ? 1 : 0`,实测多普勒在速度模糊时符号可能取反),改为按航迹 IMM 融合状态的速度矢量与位置矢量判定:
$$
D=\operatorname{atan2}(X[4],X[1])\ \text{(速度方向角)},\qquad
Flag\_Direction=\begin{cases}1,& \arccos\!\left(\dfrac{-x\cos D-y\sin D}{r}\right)<\dfrac{\pi}{2}\\[2mm]0,&\text{否则}\end{cases}
$$
其中 x、y 为经 `radar_system_delay` 补偿后的航迹位置,r = √(x²+y²),`Direction_Angle` 输出字段即 D 的度数形式。该判据等价于「目标速度方向与『雷达→目标』位置方向的夹角大于 90°」,即**滤波速度矢量的径向分量指向雷达(径向接近)时判为靠近(1)**,否则远离(0);中间版本曾按合速度归一化并把门限取为 π/4(45° 锥角),42b598e 去掉归一化并放宽到 π/2。外推(虚点)输出同样按该判据写 `Flag_Direction`。
**ΔT ≤ 0 的候选(604f158 起的行为)**:ΔT = (点迹 CPI 时间 − 航迹 T_track)/1000,ΔT ≤ 0 表示该点迹时间戳不晚于航迹时间(典型场景:航迹已按 TAS 点迹更新过,本圈 TWS 点迹的时间戳更早,或存在重复时间戳)。这种候选**不再被剔除**,仍参与最近邻最小 d 的比较与选取,但选中后:
- 不执行 IMM/EKF 更新,不写回 X1/X2/X3、P1/P2/P3 与模型概率;
- 不刷新航迹时间 T_track / GNSS_time 与点迹信息;
- 不置实点标志:`Extrapolate_round`、`point_flag`、`associate_point_number` 均保持原值,因此该航迹仍按「未关联航迹」在后续外推环节推进一帧(见 9.9);
- 该候选对连同该航迹本圈的其余候选对被一并移出候选表,因此该航迹本圈不会再关联其他点迹;由于时间戳更早的候选仍参与最小 d 比较,它可能先于有效候选(ΔT>0)被取中;
- 该点迹的 `Use_Flag` 被置 1 消费掉:`track_asso_process()` 在关联结束后会把 `Use_Flag==1` 的点迹从 `point_recv` 中删除(track_init 入口也会再剔除一次 `Use_Flag==1` 的点),因此该点迹不会进入航迹起始、不会再参与起批,避免生成虚假 TWS 航迹。
> 历史行为:604f158 之前,ΔT ≤ 0 的候选在选取时被直接剔除并 `continue`,点迹保持未被使用,可能被后续用于航迹起始。该分支原有的 `RDP_LOG` 告警日志现已注释停用;TAS 关联(track_asso_tas.cpp,见下)中同类告警日志仍启用。**b227ae1 起该分支的写法由 `if (delta_T <= 0) {空} else {...}` 调整为 `if (delta_T > 0) {...}`**,判定结果与滤波行为不变;同一提交为每个候选补充了 `min_d_flag`(被最近邻取中时置 1)并配合 `RdpRecAssoInfo` 记录全部候选与取中结果(见 5.2 的 rdp_record 行)。
#### TAS(track_asso_tas.cpp)
只处理 tas_track_idx 指定的航迹,只有统计距离与高度两个门限,两者同时通过(`thd_d && thd_h`)才记为候选:
$$
thd\_d:\ d_i^2 < associate\_threshold^2 = 16 \qquad\text{且}\qquad thd\_h:\ \text{高度门限通过}
$$
高度门限按航迹距离分段:≤1000 m:|h_t−h_p| ≤ 150 m;1000~2000 m:≤ 200 m;2000~3000 m:≤ 250 m;3000~5000 m:≤ 300 m;>5000 m:不约束(与 TWS 通道 9.6 的取值相同)。
输出航迹同样写入**方向标志** `Flag_Direction`,判据与 TWS 通道完全一致(fc49707/42b598e:按 IMM 融合速度矢量与位置矢量的夹角判定,见上文 TWS 小节)。
> ⚠ **波门语义提示**:代码中 d 本身已是马氏距离平方,但门限写作 d*d < associate_threshold*associate_threshold,`associate_threshold = 4` 时等效于 d < 4(而非 √d < 4)。该行为在 BUG-20 中被识别,**有意保留未改**;associate_threshold/1000、/100 已改为浮点除法(BUG-21 修复)。TAS 不区分距离段,`associate_threshold` 原值直接作为门限。
### 9.7 高度平滑
关联实点后,点迹高度入滑窗 Hight_smooth,输出高度取最近 w 个值的平均(不足 w 个则全平均)。
按距离分段取窗长 `w`,通道与体制不同(窗长基数取配置项 `height_smooth_win`,样例配置为相扫 6;机扫需配 3。TAS 的偏移段于 6284f3f 由 +2/+3/+4/+6 改为 +6/+8/+10/+12):
| 距离段 | TWS(`height_smooth_win + 2/3/4/6`) | TAS(`height_smooth_win + 6/8/10/12`) |
|---|---|---|
| r ≤ 1000 m | 8 / 5 | 12 / 9 |
| 1000 < r ≤ 2000 m | 9 / 6 | 14 / 11 |
| 2000 < r ≤ 4000 m | 10 / 7 | 16 / 13 |
| r > 4000 m | 12 / 9 | 18 / 15 |
(每格「相扫 / 机扫」;TWS 与 TAS 的实现在 `track_asso.cpp` / `track_asso_tas.cpp` 的 `track_hight_update()` 中,分段边界相同。)
$$
\hat h=\frac{1}{w}\sum_{i=N-w+1}^{N} h_i
$$
> 已知问题(BUG-02):缓存只增不减,航迹存活越久内存占用越大,当前有意保留。
### 9.8 航迹号管理(track_index_mangement.cpp)
- 空航迹表时从 1 开始;否则从 lastest_index+1 向上找第一个未占用号(含 500,BUG-35 已修复),找不到则从 1 回绕;全满(500 条)返回 0(不起批)。
- 写占用表前校验 1 ≤ Track_Index ≤ 500,防御异常批号越界(BUG-10 修复)。
### 9.9 航迹外推与消亡
#### 外推
- **TWS**:未关联到实点的航迹(`manual_tracking_flag==0`)按 TWS 数据率配置项 `data_rate_tws` 预测一帧(原实现按 `radar_work_mode` 在 `DATA_RATE_SHORT/MIDDLE/FAR` 三档中三选一,新结构体统一为单字段 `data_rate_tws`,见 10.3;ΔT≤0 的候选虽被消费但未刷新航迹状态,其 `point_flag` 仍为 0,故同样在本环节外推,见 9.6)。预测用各子模型 Singer F/Qj 推进,`Extrapolate_round+1`,`point_flag=0`(虚点/补点),航迹时间同步推进,并置 `Track_Update_Flag=1`(本圈输出)。
> **时间差取值(56b5449 → b4aed8a)**:56b5449 曾把 TWS 外推的 ΔT 改为按最新时间戳实时计算(`(latest_timestamp − T_track)/1000`,并对 `ΔT ≤ 0` 跳过),b4aed8a 已**回调**为按 `work_mode` 取固定数据率(原因:按最新时间戳推进会在 TAS 工作时同步外推出 TWS 航迹)。因此 `track_asso_process()` 与 `model_filter()` 虽接收 `latest_timestamp` 形参,但当前不参与 ΔT 计算(实时计算的两行代码以注释保留在源码中)。
- **TWS 外推上限(50e0b5c)**:仅当 `Extrapolate_round <= extrapolate_max`(默认 3)时才做上述预测;超过上限后不再推进位置与航迹时间,只执行 `Extrapolate_round+1`、`point_flag=0`、`Track_Update_Flag=0`——该航迹当圈不输出、位置冻结在最后一次预测处,直到重新关联到实点(`Extrapolate_round` 清零)才恢复。目的是避免长时间未关联的航迹被反复外推到远处。
- **质量衰减(V1.5.8)**:本环节对每条未关联航迹(不论是否已超外推上限)按未更新时长降低 `Quality`,`Unupdated_time` 同步累加,因此**超限后航迹虽不再输出,质量仍在下降**,直到触发质量消亡(见下)。因为 ΔT 已移到上限判断之外计算,这一衰减在上限内/外都按 `work_mode` 的数据率推进。
- **TAS**:按 `latest_timestamp − T_track` 预测(ΔT ≤ 0 跳过),航迹时间推进到最新时间戳。上限判定为 `Extrapolate_round >= extrapolate_max_tas`(配置项,样例为相扫 5;机扫需配 48)时才预测并输出,未达该轮数时只累加 `Extrapolate_round` 且不输出(位置与航迹时间停在最后一次关联处)。⚠ 判定方向与 TWS 的 `<=` 相反,见 11.2。TAS 通道**不维护航迹质量**(`track_asso_tas.cpp` 未更新 `Quality`),消亡仍按外推圈数。
- **输出门控**:`track_asso_process()` / `track_asso_process_tas()` 的输出循环只写 `Track_Update_Flag==1` 的航迹,写完即清零;因此「本圈未更新」的航迹(外推超限等)不会出现在 `Trust_Track_Output` 中。
#### 消亡(track_die.cpp / track_die_tas.cpp)
**TWS 普通航迹自 V1.5.8 起改为按航迹质量消亡**(`Quality < track_die_quality`,默认 0.3),其余通道仍按外推圈数(判据 `Extrapolate_round > 阈值`,50e0b5c 起由 `>=` 改为 `>`),满足其一即消亡:
| 通道 | 条件 |
|---|---|
| TWS 普通航迹 | Track_Mode==0 且 primary_target_flag==0 且 **Quality < track_die_quality(样例 0.3)**(V1.5.8,782bff5) |
| TWS 重点航迹 | Track_Mode==0 且 primary_target_flag==1 且 Extrapolate_round > track_die_round_pramary(样例 10) |
| TAS 航迹 | Track_Mode==1 且 Extrapolate_round > track_die_round_tas(样例配置为相扫 20;机扫需配 96) |
| 任意航迹 | manual_delete_flag==1(手动删除标记,不区分通道) |
消亡批号写入 Track_die_Index_Output 并删除本地航迹。重点航迹实际连续 11 圈无实点关联才消亡(TAS 相扫 21 圈 / 机扫 97 圈,因 `Extrapolate_round` 每圈未关联只自增 1;相扫 TAS 阈值于 5d105d2 由 10 提高到 20);普通 TWS 航迹的存活时长改为由质量衰减速度决定——未关联时间越长衰减越快,`Quality` 降到 `track_die_quality` 以下即消亡,不再有固定圈数上限(`track_die_round`(原 6 圈)仍可配置但已不被引用,见 10.2)。`track_process()` 中的调用顺序为 `track_asso → track_die → track_init`(data_process.cpp),即消亡先于航迹起始执行。
> 重点目标标记(`primary_target_add` / `primary_target_cancel`)在 TWS 上决定「按质量消亡(普通)」还是「按 10 圈轮数消亡(重点)」,不改变关联、滤波、波束控制等其他环节,也不体现在输出航迹字段中。
### 9.10 TAS 波束控制(tas_ctrl.cpp)
- **入队条件**(仅手动):manual_tracking_flag==1 且 Track_Mode==0 且队列未满(配置项 `tas_track_num_max`,样例为相扫 4;机扫需配 1,上限 `RDP_TAS_QUEUE_CAPACITY`=30)且不在 TAS 禁止区内。入队即置 Track_Mode=1、以航迹时间初始化 last_track_time,并输出一次航迹更新。
- **出队**:队列中目标在航迹表中不存在、或不再处于手动 TAS 状态时清除。(自动转 TAS / 自动退出的 tas_auto_start/tas_auto_end 逻辑全部注释停用——只支持手动。)
- **波束输出**:在 TAS 队列内遍历,逐个目标先按**数据率门控**筛选——仅要求目标距上次波束输出(`last_track_time`)的时间 `delta_T_last_track = (latest_timestamp − last_track_time)/1000` 大于配置项 `data_rate_tas` 秒(单位 s,1521592 起由 Hz 改为 s,加载器校验须 >0),保证 TAS 目标输出间隔不随波束时间(Beam_Ctrl 调用频率)变化;对通过门控的目标再比较航迹时间 `T_track`,取 CPI 时间最早者,选中后按其 CPI 时间与最新时间戳之差外推到 latest_timestamp:
$$
\Delta T=(latest\_timestamp-CPI\_time)/1000,\qquad
x_p=x+v_x\Delta T,\quad y_p=y+v_y\Delta T,\quad
r_p=\sqrt{x_p^2+y_p^2},\quad \theta_p=\operatorname{atan2}(y_p,x_p)
$$
输出 TrackingBeam{open_flag=1, type=default_track_beam_type(配置项,样例 1), Range=rp, Azi=θp(°), Elev=asin(h/rp)(°), TAS_track_index};队空、目标不在航迹表或数据率门控未通过时 open_flag=0。输出后更新该目标队列项的 last_track_time;原每次 Beam_Ctrl 末尾的整队循环移位(队列轮转)已停用,改为按数据率门控在队列内轮换目标。
> e0bf227 修正:数据率门控原先同时要求「距上次波束输出」与「航迹时间 T_track 距最新时间戳」都超过 `data_rate_tas`,第二个条件与「选 CPI 最早目标」的语义冲突(航迹时间越早反倒越容易被抑制),会漏掉本应输出的波束;现已只保留前者。
- tas_ctrl_process 入口强制 *Trust_track_num_Output=0 并在写入前检查容量,防止输出数组越界(BUG-09 修复)。
### 9.11 航迹质量(V1.5.8,1ae0cf2 / d9a7bd0 / 4b70b24 / 782bff5)
内部质量 `Quality` 为 **0~1** 的归一化值(`Temp_track::quality`、`Trust_Track::Quality`),输出时乘 `track_quality_max`(配置项,100)折算为 **0~100** 写入 `Track.Quality`。它贯穿「临时航迹 → 起批 → 关联 → 外推 → 消亡」全过程,是普通 TWS 航迹**自动**消亡的唯一依据。
**三个公共分量**
| 分量 | 公式 | 说明 |
|---|---|---|
| 统计距离项 `d_tmp` | `exp(−d)` | `d` 为所选点迹的最近邻统计距离(TWS 为三模型 `d_min`;临时航迹为末点 `d`) |
| SNR 项 `snr_tmp` | `1/(1+exp(−(SNR−16)/1.2))` | 以 16 为中心、尺度参数 1.2 的 Sigmoid,SNR 越高越接近 1 |
| 长度项 `len_tmp` | `sigmoid((Valid_point_sum−4)/1.2)×0.5 + (1 − Valid_point_sum/Point_sum)×0.5` | 仅在关联更新时使用;两项各占 0.5,衡量「已积累实点数」与「实点占比」 |
**① 临时航迹阶段(`track_init.cpp::point_temp_track_asso()`)**:每成功延长一个点后重算——`quality_tmp = (0.5·d_tmp + 0.3·snr_tmp)/(0.5+0.3)`(只用距离与 SNR 两项,不含长度项)。
- 长度 L = 3:SNR 取三点平均,`quality_tmp` **写满三个点**;
- 长度 L > 3:SNR 只取末点,末点质量 = `前一点质量×0.8 + quality_tmp×0.2`(指数平滑,系数为配置项 `track_quality_iter_coeff`,默认 0.8)。
**② 关联更新(`track_asso.cpp::model_filter()`)**:关联到实点并完成 IMM/EKF 更新后,用 `tq = track_quality_d_weight·d_tmp + track_quality_snr_weight·snr_tmp + track_quality_len_weight·len_tmp`(权重默认 0.5/0.3/0.2)求即时质量,再 `Quality = Quality×track_quality_iter_coeff + tq×(1−track_quality_iter_coeff)`(默认 0.8/0.2);随后 `Point_sum++`、`Valid_point_sum++`(**质量用的是自增前的计数**),`Unupdated_time` 清零。注意 `Valid_point_sum/Point_sum` 为**整数除法**(先截断再乘 0.5)。
**③ 外推衰减(`track_asso.cpp::model_filter()` 外推环节)**:按累计未更新时长做二次衰减。记 `t = Unupdated_time/1000`(秒),每次先 `Quality -= f(t_old)`、执行 `Unupdated_time += ΔT`、再 `Quality += f(t_new)`,净效果为 `Quality += [f(t_new) − f(t_old)]`(即 `Quality -= [f(t_old) − f(t_new)]`),其中
$$
f(t)=track\_quality\_decrease\_coeff\_o2\,t^2+track\_quality\_decrease\_coeff\_o1\,t,\qquad O_2=-0.0008,\; O_1=-0.0025
$$
因两系数为负,`f` 单调递减,故每圈质量下降 `0.0008\,(t_{new}^2-t_{old}^2)+0.0025\,(t_{new}-t_{old})`——**未关联越久、衰减越快**;结果钳位到 ≥0。该衰减在上限内/外都会执行(见 9.9)。
**④ 起批门限(`tmp_track_to_trust_track()`)**:除长度 3~10 与屏蔽区判断外,按长度取最低质量:
| 航迹长度 L | 3 | 4 | 5 | 6 | ≥7 |
|---|---|---|---|---|---|
| 最低质量 | 0.7 | 0.6 | 0.5 | 0.4 | 0.3 |
不达标的本圈不起批,临时航迹继续留在表中积累(受 `buff_round`/长度 10 的临时航迹消亡约束)。
**⑤ 消亡(`track_die.cpp`)**:普通 TWS 航迹 `Quality < track_die_quality`(默认 0.3)即消亡;重点航迹与 TAS 航迹仍按外推圈数(见 9.9)。
**⑥ 调试入库(1ffb287)**:记录功能启用时,临时航迹表 `RdpRecTempTrack` 增加 `quality`、可靠航迹表 `RdpRecTrustTrack` 增加 `Quality` / `Unupdated_time` / `Point_sum` / `Valid_point_sum`,可用 SQL 直接观察质量从起批、关联平滑到未关联衰减的全过程(字段顺序见 docs/data_record_debug.md 第 7 节)。
> 参数来源:质量相关参数位于配置文件 `[track_quality]` 段(`track_quality_max`/`min`、`track_quality_d_weight`(0.5) / `snr_weight`(0.3) / `len_weight`(0.2)、`track_quality_iter_coeff`(0.8)、`track_quality_decrease_coeff_o2/o1`),起批质量门限位于 `[track_init]` 段(`track_init_quality_L3~L7`),消亡质量门限位于 `[track_die]` 段(`track_die_quality(_pramary)`);全部经 `parameters_reload()` 加载(见 10)。
>
> 已知局限(详见 11.2):TAS 通道不维护质量;`track_quality_min`、`track_die_quality_pramary`、`track_die_round` 当前可配置但未参与计算;起批质量门限按**临时航迹长度**取值,而实际起批只用末点质量。
---
## 10. 参数说明
> 自「参数配置方式改造」起,工作参数的唯一来源是 **TOML 配置文件 → `struct.h::RDP_parameter`**:`parameters.h` 不再含雷达工作参数宏,公开头中也不再有 `struct RadarPara`。宿主只需在 `GetB()` 后调用 `parameters_reload(配置文件路径)`。数值与改造前一致,默认值见 `config/config_tmp.toml`。
### 10.1 参数加载机制与校验规则
```text
宿主:GetB() → parameters_reload("config/config_tmp.toml") → data_preprocess / track_process / Beam_Ctrl ...
(重连或切换配置时再次 parameters_reload 即可热重载;成功返回 0,失败返回 -1)
DLL :rdp_parameter_load() 解析 TOML → 严格校验 → 全部通过后一次性赋值给 Data_Process::rdp_parameter
```
配置段与 `RDP_parameter` 的注释分组一一对应,**键名 = 结构体成员名**:
| 配置段 | 内容 |
|---|---|
| `[radar_params]` | 雷达工作参数:工作模式、**扫描模式 `scan_mode`**、频点、平台高度、系统延迟、TWS/TAS/纯跟踪数据率 |
| `[cohesion]` | 点迹凝聚参数:距离/速度/方位门限、有效量程上下限 |
| `[track_associate]` | 航迹关联参数:量测误差 `sigma_*`、关联门限 `associate_threshold`、外推上限、高度平滑窗长 |
| `[track_init]` | 航迹起始参数:起批波门/折角/点数、起批质量门限 L3~L7、起始速度范围 |
| `[track_die]` | 航迹消亡参数:消亡圈数(普通/重点/TAS)、质量消亡门限 |
| `[track_quality]` | 航迹质量参数:折算上下限、三项权重、平滑与衰减系数 |
| `[track_index]` | 航迹批号管理:`track_index_max` |
| `[beam_control]` | 波束调度:默认跟踪波束类型、最大同时跟踪 TAS 目标数 |
| `[singer_model]` | 三个 Singer 模型的过程噪声强度(fast/slow) |
| `[track_init_prohibite_area]` | 起批屏蔽区:`*_num` + 4 个与成员同名的 TOML 数组 |
| `[tas_prohibite_area]` | 禁止 TAS 跟踪区:`*_num` + 4 个与成员同名的 TOML 数组 |
**加载器严格校验规则**(`rdp_parameter_loader.cpp`,任一不满足即失败):
1. 11 个配置段**全部必填**,且必须是 TOML 表;顶层出现未知配置段直接拒绝;
2. 所有**标量键必填**,类型必须匹配(浮点参数接受整数或浮点,整数参数只接受整数),且不得超出 C++ `float`/`int` 可表示范围;
3. 每个段内只允许登记过的键,**拼错的键按未知参数拒绝**(不会静默忽略);
4. 取值范围校验:如 `radar_work_mode∈[0,2]`、`scan_mode∈{0,1}`、`freq_0_GHz>0`、`data_rate_tws/data_rate_tas>0`、`sigma_*>0`、`associate_threshold>0`、`height_smooth_win≥1`、`track_init_point_num_min∈[3,9]`、`track_init_angle∈(0,180]`、`track_init_quality_L3~L7∈[0,1]`、`track_init_velocity_max>min≥0`、消亡圈数≥0、质量门限∈[0,1]、质量衰减系数≤0、`track_index_max∈[1, MAX_TRACK_NUM]`、`tas_track_num_max∈[0, RDP_TAS_QUEUE_CAPACITY]`、Singer 模型 Q>0 等(完整清单以源码为准);
5. 屏蔽区:`*_num∈[0,30]`;4 个数组的元素个数必须**等于** `*_num`(`*_num=0` 时数组可省略,存在时必须为空数组);并逐区校验距离 `0≤min<max`、方位 `0≤min<max≤360`;
6. 失败语义:返回 -1,并经可选 `std::string* error_msg` 给出**首条**可读原因(`Data_Process::parameters_reload` 会打印到 `RDP_LOG`),**当前已加载参数保持不变**(加载过程先写入临时对象,全部成功后才整体赋值)。
> 兼容性提示:改造前 `TRACK_DIE_ROUND_TAS`、`MAX_EXTRAPOLATE_NUM_TAS`、`H_F_WIN_LEN`、`TAS_QUEUE_LENGTH`/`MAX_TAS_NUM` 按扫描体制取不同宏值;现在同一份配置对所有体制生效。`config/config_tmp.toml` 是**相扫**取值(`scan_mode=0` + 下列 4 项相扫值),机扫部署需配为 `scan_mode=1`、`track_die_round_tas=96`、`extrapolate_max_tas=48`、`height_smooth_win=3`、`tas_track_num_max=1`(其余参数两体制相同)。**判圈逻辑由配置项 `scan_mode` 决定**(0 相扫 / 1 机扫,见 7.2);机扫/相扫已合并为同一份构建,不再有编译期体制或版本后缀(见 4.2)。
### 10.2 参数表(`RDP_parameter` 字段 ↔ TOML 键 ↔ 样例值)
「样例值」为 `config/config_tmp.toml` 的取值(相扫);数值含义与改造前相同。
| 配置段 | 键(=结构体字段) | 样例值 | 含义 / 影响 |
|---|---|---|---|
| radar_params | `radar_work_mode` | 0 | 工作模式:0 近程 / 1 中程 / 2 远程(当前影响凝聚是否带速度维约束;TWS 外推已改为固定 `data_rate_tws`、不再按模式三选一;原 `RadarPara.work_mode`) |
| radar_params | `scan_mode` | 0 | **扫描模式:0 相扫 / 1 机扫**(加载器校验仅允许 0/1),决定 `data_preprocess()` 的 TWS 判圈逻辑(见 7.2);构建不区分体制,同一份 DLL 通过该配置切换扫描模式(见 4.2) |
| radar_params | `freq_0_GHz` | 9.2 | 载波频点(GHz,盲速计算基准;原 `FREQ0`) |
| radar_params | `radar_height` | 0 | 雷达平台高度(m,输出 z 叠加;原 `Height`) |
| radar_params | `radar_system_delay` | 0 | 系统延迟(s,输出位置按 `x + vx·delay` 补偿;原 `Sys_delay`) |
| radar_params | `data_rate_tws` | 3 | TWS 数据率/外推步长(s;原按 `work_mode` 在 `DATA_RATE_SHORT/MIDDLE/FAR` 中三选一) |
| radar_params | `data_rate_tas` | 1 | TAS 波束输出间隔(s,校验 >0;原 `DATA_RATE_TAS`,1521592 起单位由 Hz 改为 s) |
| radar_params | `data_rate_track_only` | 0.2 | 纯跟踪模式数据率(s;当前实现保留未用) |
| cohesion | `point_cohesion_range` | 80 | 距离凝聚门限(m;原 `DOT_COH_RANGE`) |
| cohesion | `point_cohesion_velocity` | 2 | 速度凝聚门限(m/s;原 `DOT_COH_V`) |
| cohesion | `point_cohesion_azimuth` | 6 | 方位凝聚门限(°;原 `DOT_COH_AZI`) |
| cohesion | `point_cohesion_range_min` | 100 | 有效量程下限(m;原 `R_MIN`) |
| cohesion | `point_cohesion_range_max` | 100000 | 有效量程上限(m;原 `R_MAX`,校验 > 下限) |
| track_associate | `sigma_range` | 10.0 | 距离量测误差(m;原 `SIGMA_R`) |
| track_associate | `sigma_azimuth` | 0.02 | 方位量测误差(rad;原 `SIGMA_A`) |
| track_associate | `sigma_pitch` | 0.2 | 俯仰量测误差(rad;原 `SIGMA_E`) |
| track_associate | `sigma_velocity` | 2.0 | 速度量测误差(m/s;原 `SIGMA_V`) |
| track_associate | `associate_threshold` | 4.0 | 关联波门(原 `ASSO_THORD`,判据 `d*d < 该值²`,语义见 9.6) |
| track_associate | `extrapolate_max` | 3 | TWS 最大外推圈数(原 `MAX_EXTRAPOLATE_NUM`) |
| track_associate | `extrapolate_max_tas` | 5 | TAS 外推轮数阈值(原 `MAX_EXTRAPOLATE_NUM_TAS`;机扫需配 48) |
| track_associate | `height_smooth_win` | 6 | 高度平滑窗长基数(原 `H_F_WIN_LEN`;机扫需配 3,见 9.7) |
| track_init | `track_init_threshold` | 8 | 起批统计距离波门(原 `TRACK_START_THRESHOLD`;实际生效 `d ≤ 8`) |
| track_init | `track_init_angle` | 60 | 起批折角上限(°;原 `ALPHA_START`) |
| track_init | `track_init_point_num_min` | 3 | 起批所需点数(3~9;原 `RadarPara.track_start_point_num`) |
| track_init | `track_init_quality_L3`~`L7` | 0.7 / 0.6 / 0.5 / 0.4 / 0.3 | 按临时航迹长度 3/4/5/6/≥7 的起批最低质量(原 `TRACK_START_QUALITY_L3~L7`) |
| track_init | `track_init_velocity_min` | 1 | 航迹头关联速度下限(m/s;原 `V_MIN`,校验 < 上限) |
| track_init | `track_init_velocity_max` | 50 | 航迹头关联速度上限(m/s;原 `V_MAX`) |
| track_die | `track_die_round` | 6 | 普通 TWS 消亡圈数(V1.5.8 起改按质量消亡,**当前未被引用**,保留) |
| track_die | `track_die_round_pramary` | 10 | 重点航迹消亡圈数(原 `TRACK_DIE_ROUND_PRIMARY`) |
| track_die | `track_die_round_tas` | 20 | TAS 航迹消亡圈数(原 `TRACK_DIE_ROUND_TAS`;机扫需配 96) |
| track_die | `track_die_quality` | 0.3 | TWS 普通航迹质量消亡门限(原 `TRACK_DIE_QUALITY`) |
| track_die | `track_die_quality_pramary` | 0.3 | 重点航迹质量门限(保留,当前未参与计算) |
| track_quality | `track_quality_max` | 100 | 质量折算上限(输出 `Track.Quality` = 内部质量 × 该值) |
| track_quality | `track_quality_min` | 0 | 质量下限(保留,当前未使用) |
| track_quality | `track_quality_d_weight` | 0.5 | 质量三要素权重:统计距离 |
| track_quality | `track_quality_snr_weight` | 0.3 | 质量三要素权重:SNR |
| track_quality | `track_quality_len_weight` | 0.2 | 质量三要素权重:有效点占比 |
| track_quality | `track_quality_iter_coeff` | 0.8 | 质量指数平滑系数(`新 = 旧×c + 即时×(1−c)`) |
| track_quality | `track_quality_decrease_coeff_o2` | −0.0008 | 质量衰减二次项系数(须 ≤0,见 9.11) |
| track_quality | `track_quality_decrease_coeff_o1` | −0.0025 | 质量衰减一次项系数(须 ≤0) |
| track_index | `track_index_max` | 500 | 航迹号上限(1~500;原 `MAX_TRACK_INDEX`,内部航迹号表按该值分配) |
| beam_control | `default_track_beam_type` | 1 | 跟踪波束 `TrackingBeam.type` 取值(原硬编码 1) |
| beam_control | `tas_track_num_max` | 4 | 最大同时跟踪 TAS 目标数(0~30;原 `MAX_TAS_NUM`,机扫需配 1) |
| singer_model | `model_1_Q_fast` | 0.000001 | 模型 1 过程噪声(**当前未参与计算**,模型 1 只用 slow) |
| singer_model | `model_1_Q_slow` | 0.000001 | 模型 1 过程噪声(恒定,见 9.5.1) |
| singer_model | `model_2_Q_fast` | 0.01 | 模型 2 过程噪声 fast 档 |
| singer_model | `model_2_Q_slow` | 0.01 | 模型 2 过程噪声 slow 档 |
| singer_model | `model_3_Q_fast` | 1.0 | 模型 3 过程噪声 fast 档 |
| singer_model | `model_3_Q_slow` | 1.0 | 模型 3 过程噪声 slow 档 |
| track_init_prohibite_area | `track_init_prohibite_area_num` | 0 | 起批屏蔽区数(0~30;原 `RadarPara.track_prohibite_area_num`) |
| track_init_prohibite_area | `track_init_prohibite_area_range_min/max`、`_azimuth_min/max` | `[]` | 4 个 TOML 数组,长度必须等于 `*_num`(距离 m / 方位 °;原 `R_min/max_track_prohibited`、`Azimuth_min/max_track_prohibited`) |
| tas_prohibite_area | `tas_prohibite_area_num` | 0 | 禁止 TAS 跟踪区数(0~30;原 `RadarPara.TAS_prohibite_area_num`) |
| tas_prohibite_area | `tas_prohibite_area_range_min/max`、`_azimuth_min/max` | `[]` | 4 个 TOML 数组,长度必须等于 `*_num`(原 `R_min/max_TAS_prohibited`、`Azimuth_min/max_TAS_prohibited`) |
> ⚠ 结构体成员名 `track_die_round_pramary`、`track_die_quality_pramary` 沿用源码既有拼写(pramary),配置键必须与之一致,不是笔误修正对象。
### 10.3 旧参数 → 新字段对照(宿主/调参迁移用)
**(a)旧 `struct RadarPara` 字段**
| 旧字段 | 新字段(配置键) | 说明 |
|---|---|---|
| `work_mode` | `radar_work_mode` | 工作模式 |
| `Height` | `radar_height` | 雷达平台高度 |
| `Sys_delay` | `radar_system_delay` | 系统延迟 |
| `DATA_RATE_SHORT/MIDDLE/FAR` | `data_rate_tws` | 原按 `work_mode` 三选一,现为单字段(契约确认的等价改法) |
| `DATA_RATE_TAS` | `data_rate_tas` | TAS 数据率 |
| `track_start_point_num` | `track_init_point_num_min` | 起批点数 |
| `track_start_threshold`(原实现未用) | `track_init_threshold` | 起批波门 |
| `track_asso_threshold`(原实现未用) | `associate_threshold` | 关联波门 |
| `track_prohibite_area_num` | `track_init_prohibite_area_num` | 起批屏蔽区数 |
| `R_max_track_prohibited` / `R_min_track_prohibited` | `track_init_prohibite_area_range_max/min` | 起批屏蔽区距离 |
| `Azimuth_max_track_prohibited` / `Azimuth_min_track_prohibited` | `track_init_prohibite_area_azimuth_max/min` | 起批屏蔽区方位 |
| `TAS_prohibite_area_num` | `tas_prohibite_area_num` | TAS 禁止区数 |
| `R_max_TAS_prohibited` / `R_min_TAS_prohibited` | `tas_prohibite_area_range_max/min` | TAS 禁止区距离 |
| `Azimuth_max_TAS_prohibited` / `Azimuth_min_TAS_prohibited` | `tas_prohibite_area_azimuth_max/min` | TAS 禁止区方位 |
| `V_MAX` / `V_MIN` | `track_init_velocity_max/min` | 航迹头关联速度范围 |
| `Model1_Q_fast/slow`、`Model2_Q_*`、`Model3_Q_*` | `model_1/2/3_Q_fast/slow` | Singer 模型过程噪声 |
| `R_TAS_max/min`、`V_TAS_max/min`、`TAS_Height_1~5`、`cfar_th`、`north_angle`、`Beam_num` | 无 | 实现未使用,新结构体已排除(自动 TAS 逻辑保持停用) |
| —(新增配置项,无旧字段对应) | `scan_mode` | 扫描模式 0 相扫 / 1 机扫,替代原 `data_process.cpp` 的编译期 `PHASE_SCANNING`/`MECHANICAL_SCANNING` 判圈分支(见 7.2) |
**(b)旧 `parameters.h` 宏**
| 旧宏 | 新字段(配置键) | 说明 |
|---|---|---|
| `FREQ0` | `freq_0_GHz` | 载波频点 |
| `SIGMA_R` / `SIGMA_A` / `SIGMA_E` / `SIGMA_V` | `sigma_range` / `sigma_azimuth` / `sigma_pitch` / `sigma_velocity` | 量测误差 |
| `DOT_COH_RANGE` / `DOT_COH_V` / `DOT_COH_AZI` | `point_cohesion_range` / `point_cohesion_velocity` / `point_cohesion_azimuth` | 凝聚门限 |
| `R_MIN` / `R_MAX` | `point_cohesion_range_min` / `point_cohesion_range_max` | 有效量程 |
| `ASSO_THORD` | `associate_threshold` | 关联波门 |
| `MAX_EXTRAPOLATE_NUM` / `MAX_EXTRAPOLATE_NUM_TAS` | `extrapolate_max` / `extrapolate_max_tas` | 外推上限 |
| `H_F_WIN_LEN` | `height_smooth_win` | 高度平滑窗长基数 |
| `TRACK_START_THRESHOLD` / `ALPHA_START` | `track_init_threshold` / `track_init_angle` | 起批波门/折角 |
| `TRACK_START_QUALITY_L3~L7` | `track_init_quality_L3~L7` | 起批最低质量 |
| `TRACK_DIE_QUALITY` / `TRACK_DIE_QUALITY_PRAMARY` | `track_die_quality` / `track_die_quality_pramary` | 消亡质量门限 |
| `TRACK_DIE_ROUND` / `TRACK_DIE_ROUND_PRIMARY` / `TRACK_DIE_ROUND_TAS` | `track_die_round` / `track_die_round_pramary` / `track_die_round_tas` | 消亡圈数(`track_die_round` 当前未被引用) |
| `TRACK_QUALITY_MAX` / `MIN` | `track_quality_max` / `track_quality_min` | 质量折算上下限(min 当前未使用) |
| `TRACK_QUALITY_D_WEIGHT` / `SNR_WEIGHT` / `LEN_WEIGHT` | `track_quality_d_weight` / `snr_weight` / `len_weight` | 质量权重 |
| `TRACK_QUALITY_ITER_COEFF` | `track_quality_iter_coeff` | 质量平滑系数 |
| `TRACK_QUALITY_DECREASE_COEFF_O2` / `O1` | `track_quality_decrease_coeff_o2` / `o1` | 质量衰减系数 |
| `MAX_TRACK_INDEX` | `track_index_max` | 航迹号上限(原定长占用表改为按该值分配的 `std::vector`) |
| `MAX_TAS_NUM` | `tas_track_num_max` | 最大同时跟踪 TAS 目标数 |
| `TAS_QUEUE_LENGTH` | 编译期常量 `RDP_TAS_QUEUE_CAPACITY`(30,见 10.4) | 队列容量仍为编译期常量,运行期上限用 `tas_track_num_max` |
| 硬编码 `Tracking_beam->type = 1` | `default_track_beam_type` | 跟踪波束类型 |
| `UNCONF_TARGET` | 无(宏已删除) | 未确认目标类型语义常量;起批处 `Target_Type` 直接写 0,语义不变 |
| `PI`、`MAX_TRACK_NUM`、版本/日志/记录宏、`Round` | 保留不变 | 见 10.4 |
### 10.4 编译期常量(parameters.h 保留宏)
`parameters.h` 已删除全部雷达工作参数宏(改为配置文件,见 10.1~10.3),仅保留接口/内存布局所需的编译期常量、版本/日志/记录宏:
| 宏 / 常量 | 取值 | 含义 |
|---|---|---|
| `MAX_TRACK_NUM` | 500 | 输出航迹数组 `Track[500][10]` 的固定容量(宿主接口维度) |
| `RDP_TAS_QUEUE_CAPACITY` | 30 | TAS 跟踪队列容量上限;运行期配置项 `tas_track_num_max` 不得超过该值 |
| `PI` | 3.1415926f | 圆周率常量 |
| `MAJOR_VERSION` / `MINOR_VERSION` / `PATCH_VERSION` | 1 / 5 / 9 | 版本号(拼装为 `VERSION_STRING`,见 7.1) |
| `VERSION_INFO` / `VERSION_STRING` | `"GENERIC"`、`V1.5.9.GENERIC` | 版本后缀(机扫/相扫已合并为同一版本,无体制后缀)与完整版本串(由 `GetB()` 写入 `version_info`) |
| `Round(x)` | 宏 | 四舍五入取整(盲速折叠用) |
| RDP_LOG_ENABLE | 注释停用(默认不启用) | 日志文件输出开关:定义时将 `std::cout` 重定向到日志文件;**当前源码中该宏为注释状态**(parameters.h 注释文字仍写「定义(默认)」,以代码实际状态为准),不重定向、日志输出到标准输出/控制台 |
| RDP_LOG_DIR | `.\rdp_logs\` | 日志文件输出目录(相对宿主进程当前工作目录,目录不存在时自动创建) |
| RDP_RECORD_ENABLE | 由 CMake 选项 `RDP_DATA_RECORD` 定义(AUTO 时 Debug 定义) | 数据记录调试开关:**不要在 parameters.h 中手工定义**(由构建系统传入);定义时记录模块参与编译,未定义时全部记录宏(6 个异步入队宏 + 遗留 `RDP_RECORD`/`RDP_RECORD_BATCH`)展开为空操作,见 4.3 与 11.3 |
| RDP_RECORD_DB_DIR | `.\rdp_records\` | 数据记录库输出目录(相对宿主进程当前工作目录,目录不存在时自动创建;仅记录功能启用时产生) |
| RDP_RECORD_POINTS / RDP_RECORD_COHESION_TWS / RDP_RECORD_COHESION_TAS / RDP_RECORD_TEMP_TRACKS / RDP_RECORD_TRUST_TRACKS / RDP_RECORD_ASSO_INFOS | 由 `RDP_RECORD_ENABLE` 条件定义(记录开启时展开为 `std::move` + 异步入队,关闭时 `((void)0)`) | 6 个异步入队记录点宏,参数为对应源结构体的 `std::vector`(`PointRecv` / `Temp_track` / `Trust_Track` / `Asso_Info`),宏内部 `std::move`、调用后 vector 为空;宏与表的对应关系见 docs/data_record_debug.md 第 4、7 节。遗留的 `RDP_RECORD`/`RDP_RECORD_BATCH` 为同步接口(会阻塞) |
| RDP_RECORD_QUEUE_CAP_BYTES | `64*1024*1024`(64 MB) | 入队队列字节上限;超过该值整批丢弃并计入 `stats().dropped_rows`,不阻塞处理线程 |
| RDP_RECORD_QUEUE_MAX_BATCHES | 4096 | 入队队列批数上限(与字节上限同时生效) |
| RDP_RECORD_WRITE_BATCH_ROWS | 4096 | 写线程每个事务的目标提交行数(按表累积到该行数即提交) |
| RDP_RECORD_WRITE_MAX_WAIT_MS | 50 | 写线程为凑批等待的最长时间(ms),超时后提交现有数据 |
| RDP_RECORD_ASSO_CHUNK_ROWS | 131072 | 关联信息(⑥)单次入队分块上限,限制处理线程收集 `Asso_Info` 的内存峰值 |
| RDP_RECORD_SQLITE_CACHE_KB | 8192 | SQLite 页缓存大小(KB,执行 `PRAGMA cache_size=-8192`,即 8 MB) |
| RDP_RECORD_SQLITE_BUSY_TIMEOUT_MS | 2000 | SQLite 忙等待超时(ms) |
| RDP_RECORD_SQLITE_WAL | 1 | 是否尝试开启 WAL(1=尝试;失败/不支持时回退默认 journal 模式并提示) |
| RDP_RECORD_MAX_CONSECUTIVE_ERRORS | 10 | 异步批量写入连续失败达到该次数后全局熔断(停止记录并丢弃队列) |
| RDP_RECORD_DROP_LOG_INTERVAL | 1024 | 队列丢弃日志限频:每累计丢弃该行数提示一次 |
| rdp_record::Stats / stats()(非宏) | — | 运行统计结构体(定义于 `rdp_record.h`,任意时刻线程安全读取、`Shutdown()` 时自动打印):`enqueued_rows`/`dropped_rows`/`written_rows`/`transactions`/`write_errors`/`queue_peak_bytes`/`queue_peak_rows` |
> **构建期扫描体制宏已移除(机扫/相扫版本合并)**:`CMakeLists.txt` 不再有 `RADAR_SCAN_MODE` 缓存变量,也不再定义 `PHASE_SCANNING` / `MECHANICAL_SCANNING` 编译宏;`parameters.h` 的 `VERSION_INFO` 为固定字符串 `"GENERIC"`。扫描模式只由运行期配置项 `[radar_params] scan_mode` 决定(见 4.2、7.2),同一份 DLL 同时适用于两种体制的部署。
---
## 11. 已知问题与限制
详见 archived_docs/BUG_REPORT.md(37 项分析)与 archived_docs/BUG_FIX_REPORT.md(修复明细)。要点:
### 11.1 已修复(archived_docs/BUG_FIX_REPORT.md)
- **越界/防御**:TAS Point_Sum 限幅 150(BUG-04);size()-1 下溢(BUG-05);起批点数校验(BUG-06);航迹号下标校验(BUG-10);Beam_Ctrl 输出计数清零+容量检查(BUG-09);消亡空向量保护(BUG-34);航迹号 500 可复用(BUG-35);局部结构体值初始化(BUG-37)。
- **时间戳/时序**:TWS 关联 ΔT≤0 的候选不参与滤波更新、不刷新航迹状态并消费该点迹(604f158 起由「剔除候选、点迹保持未使用」改为当前行为,仍属 BUG-15 处置范围);TAS 关联 ΔT≤0 拒绝(BUG-16);TAS 外推负时间差跳过(BUG-17);Bind_speed 除零保护(BUG-19)。
- **数值稳定性**:方位残差 ±π 环绕(BUG-22);IMM 概率零分母/奇异保护(BUG-23);EKF 似然 3×3 新息协方差(BUG-24);航向角 atan2(BUG-26);asin 定义域钳位(BUG-27);近程模型 3 门限浮点除法(BUG-21);track_clear_all 全模块 reset(BUG-28);未初始化变量修复(BUG-11/12/14)。
- **后修订(e0bf227,BUG_FIX_REPORT.md 成文之后)**:TWS 关联高度门限由注释状态改为实际生效(`track_asso.cpp`),统计距离/高度/距离三类判据拆为独立布尔量,关联门限 `associate_threshold` 由 3 调大至 4;TAS 关联高度门限 2000~3000 m 段放宽至 250 m;修复 `tas_beam_output()` 数据率门控误判(详见 CHANGELOG 的 [1.5.8] 与 9.6、9.10)。
- **后修订(50e0b5c、fc49707、42b598e、e8c56f9,BUG_FIX_REPORT.md 成文之后)**:输出航迹增加 `Track_Update_Flag` 门控(只输出本圈有更新的航迹);未关联航迹外推增加圈数上限;消亡判据改为 `>`,正常/重点航迹分别定为 6 / 10 圈(TAS 相扫 10、机扫 96;**其中 TAS 相扫其后于 5d105d2 调整为 20,且普通 TWS 航迹的 6 圈判据已改为质量消亡,见 10.2 与 11.2**);`Flag_Direction` 改用滤波速度矢量判定,修复速度模糊时的向站/背站误判;手动操作接口补 `break`;`DataRev`/`Track` 新增归一化幅度与速度维 FFT 点数字段(输入侧其后已打通,TAS 输出仍未写回,见 11.2)。
### 11.2 有意保留 / 未修复(archived_docs/BUG_REPORT.md 标注项 + 后续源码观察)
- **BUG-01**:基类无虚析构,Destroy() 按基类指针 delete。
- **BUG-02**:Hight_smooth 只增不减,长时运行内存持续增长。
- **BUG-03**:工厂 GetB/Destroy 非线程安全,接口线程模型未定义(宿主应单线程调用)。
- **BUG-07**:禁止区个数在实现内部仍未二次校验,配置过大仍可能越界读;但**配置入口已加防护**——加载器强制 `track_init_prohibite_area_num`/`tas_prohibite_area_num` 在 0~30 且 4 个数组长度等于 `*_num`,非法配置在 `parameters_reload` 阶段即返回 -1、不会进入处理流程(见 10.1)。
- **BUG-08**:消亡航迹输出数组容量未传入,仅约定 ≤500。
- **BUG-13(参数初始化,已被本次改造改变)**:`Data_Process::rdp_parameter{}` 为零初始化,未加载配置时 `data_rate_tws`/`sigma_*` 等均为 0(非法)。宿主必须在**首次 `data_preprocess` 之前**调用 `parameters_reload()` 且确认返回 0;加载失败时保留的是上一次成功参数(首次失败则为全 0),DLL 不会自动纠正。
- **BUG-18**:卡尔曼两点/三点初始化对零/负时间差无保护(起批时间戳必须严格递增)。
- **BUG-20**:门限对马氏距离平方再次平方(e0bf227 把 `associate_threshold` 调为 4 后等效 d < 4),有意保留。
- **BUG-25**:TWS 关联/输出未排除 Track_Mode==1 的 TAS 航迹(原 `manual_tracking_flag==0` 过滤代码块已于 fc49707 删除,未恢复过滤)。
- **BUG-29**:tracking_stop 后 TAS 队列项延迟到下一次 Beam_Ctrl 才移除。
- **BUG-33**:起批关联未显式校验 ΔT>0。
- **BUG-36**:TAS 波束关闭时只清 open_flag,其余字段保留旧值。
- **归一化幅度 / 速度维 FFT 点数(e8c56f9 新增,输入侧已打通)**:`data_preprocess()` 现已在 TWS、TAS 两条分支都把 `DataRev.amp_asv` / `DataRev.prn_fftn` 拷入内部 `PointRecv`(`data_process.cpp`,并随 `RdpRecPoint` 落库),因此 TWS 关联路径(`track_asso.cpp` 写航迹、输出时写回 `Track`)取到的是有效数据。**TAS 通道仍未打通**:`track_asso_tas.cpp` 的关联与输出路径没有涉及这两个字段,TAS 输出航迹中 `amp_asv_point` / `prn_fftn_point` 仍保持宿主原值,宿主暂不应依赖 TAS 侧的这两个字段。
- **TAS 外推上限判据方向与 TWS 相反(50e0b5c)**:TWS 用 `Extrapolate_round <= extrapolate_max` 外推,TAS 用 `Extrapolate_round >= extrapolate_max_tas`,实际效果是 TAS 航迹在未达上限的若干圈内既不外推也不输出(位置与航迹时间停在最后一次关联处),达到上限后才恢复逐帧外推输出;如属笔误,宜与 TWS 侧统一。
- **Flag_Direction 判据的 acos 无定义域钳位(fc49707/42b598e)**:对 `(-x·cos D − y·sin D)/r` 直接取 `acos`(与 BUG-27 同类问题),浮点舍入使参数略微越过 ±1 时返回 NaN,比较为假、按「远离 0」输出;`r` 为 0 时还存在除零。
- **航迹质量仅覆盖 TWS 通道(V1.5.8)**:`track_asso_tas.cpp` 既不更新 `Quality` 也不在 `model_output()` 写 `Track.Quality`,因此 TAS 航迹的 `Quality` 停留在起批时的初值(手动转 TAS 后不再变化),TAS 消亡仍按外推圈数。宿主若要按质量过滤,需自行区分 `Track_Mode`。
- **质量相关参数存在未使用项(V1.5.8)**:配置项 `track_quality_min`、`track_die_quality_pramary` 可配但未参与任何计算;`track_die_round` 在 TWS 普通航迹改为质量消亡后也不再被引用(保留备用)。调参时不要误以为三者生效。
- **起批质量门限取的是临时航迹「末点」质量**:`tmp_track_to_trust_track()` 用 `(*Iter)[L-1].quality` 与按长度取的门限比较,而临时航迹质量只在 L=3 时写过所有点、L>3 时只更新末点,因此门限表实际是针对「最新一点的质量」,不是整条航迹的平均质量。
- **质量长度项含整数除法**:`1 − Valid_point_sum/Point_sum` 中两操作数均为 `int`,先做整数除法截断再乘 0.5,`Valid_point_sum/Point_sum` 的精度损失最大约 1/Point_sum;对点数很多的航迹影响可忽略,但精确复现公式时需注意。
- **数据记录未采用关联信息裁剪与记录策略(P0-a / P2,V1.5.8 优化时明确不做)**:⑥ 关联信息仍按「每个候选一行」写入(单圈 ≈ 点迹数 × 航迹数),未裁剪为只记录取中候选,也未做按容量/时长切库与旧库清理;因此高航迹密度场景下判圈帧仍有可观记录开销(200 目标/150 点压测 p99 ≈ 13~24 ms),记录库也可能很大(60 圈约 1.06 GB)。属本轮刻意取舍,评价实时性时需区分普通帧(p99 ≈ 0.1 ms)与判圈帧。
- **`scan_mode` 与实际雷达体制需一致(部署约束)**:DLL 不校验配置项 `scan_mode` 与实际雷达体制/波位号序列是否一致(不报错);机扫部署须把 `scan_mode` 配为 1 且 4 项数值按机扫取值(见 4.2)。机扫/相扫已合并为同一份构建,不再有编译期体制可作交叉校验。
### 11.3 未启用功能
- direct_tracking_process(引导跟踪)、tracking_point(手动打波束)为**空实现**;Track_Init_Direct_Tracking::track_init_process_logic 同样为空。
- track_asso_direct_tracking.cpp **未加入 CMake 源列表**(与旧 .pro 一致)。
- TAS **自动**开启/退出逻辑(tas_auto_start/tas_auto_end)注释停用,仅支持手动 tracking_start/tracking_stop。
- 新结构体 `RDP_parameter` 已排除旧 `RadarPara` 中实现未使用的字段(`R_TAS_max/min`、`V_TAS_max/min`、`TAS_Height_1~5`、`cfar_th`、`north_angle`、`Beam_num`;其中前两组用于已停用的 TAS 自动开启/退出逻辑),这些功能仍保持停用(见 10.3)。
- build/output/ 下为早期打包导出物,其 data_process_class_dll.h 时间戳仍为 32 位 int,与当前 64 位接口不一致,勿作为对接依据。
- **数据记录调试功能默认只在 Debug 启用**:CMake 选项 `RDP_DATA_RECORD` 的 AUTO 默认值为「Debug 启用、Release 关闭」,交付/Release 构建下记录模块(`rdp_record.cpp`、`sqlite3.c`)不参与编译、所有记录宏为空操作(导出符号与依赖均无变化);如需在 Release 构建中临时排查可显式 `-DRDP_DATA_RECORD=ON`,但正式交付应保持 AUTO/OFF(见 docs/data_record_debug.md)。记录点中的字段错误只在启用记录功能的构建中才会被检查(关闭时宏丢弃实参)。
- **记录表的三个观察**:① 可靠航迹表 `RdpRecTrustTrack` 在输出分支内写库,而该分支入口已把 `Track_Update_Flag` 清零(`track_asso.cpp` / `track_asso_tas.cpp` 均先置 0 再输出),因此表中的 `Track_Update_Flag` 恒为 0,判断「本圈是否更新」应改用该表是否出现对应 `track_id`/`circle_id` 的记录;② `Trust_Track` 的极坐标量快照 `Range`/`Azimuth`/`Elevation`/`Velocity` 只在航迹当圈有输出时回填,长期未输出(外推超限)的航迹在表中该项为 0 或旧值;③ TAS 关联信息行中 `R`/`VT` 为占位 0、`thd_r` 恒为 true、`track_index` 存的是 TAS 目标批号(TWS 行才是航迹表下标),跨通道分析时不要按 TWS 语义解读。
- **数据记录为异步写线程 + 有界队列(V1.5.8 优化)**:处理线程只做收集与入队,写线程在 Windows 下以 BELOW_NORMAL 优先级运行、承担全部实体构造与写库(遗留同步接口经 `db_mtx` 串行化);队列满时**整批丢弃**(`stats().dropped_rows` 可查,日志默认每 1024 行提示一次),处理线程绝不因记录阻塞。因此:① 进程异常退出(未调用 `Destroy()`)时队列尾部与 WAL 尾部可能丢失,采集结束务必 `Destroy()`;② 同一份记录的**跨表写入顺序不保证**,`id` 为 SQLite ROWID 自增、单调但不保证连续;③ WAL 依赖本地盘/共享内存文件系统,网络盘上可能回退为默认 journal;④ 写失败时该表永久跳过、连续 10 次错误全局熔断,均只降级记录功能、不影响雷达处理。
### 11.4 航迹起始相关的未修复观察(详见 docs/track_init_readme.md 第 15 节)
以下为阅读源码得到的观察,**未在本轮文档更新中改动代码**;修改前请结合实测数据评估:
- 点-临时航迹关联硬编码 `|Δr| ≥ 5 m` 门限,切向/远距离慢速目标可能漏关联导致起批失败。
- 起批判据对马氏距离平方再次平方(`d*d ≤ track_init_threshold²`),`track_init_threshold=8` 时实际门限为 `d ≤ 8`,按字面 `d² ≤ 64` 理解会严重放宽;调 `track_init_threshold` 时需注意这一层。
- 折角计算 `acos` 无定义域钳位,浮点越界产生 NaN 时条件恒假(静默丢弃该关联)。
- 起批输出数组行号可能越过容量:容量判据用 `trust_track->size() < track_index_max`,而输出行计数在 track_asso 阶段(track_die 删除航迹之前)已推进,极端场景(当圈消亡 ≥ 2 条且起批占满配额)可写到 `MAX_TRACK_NUM` 之外。
- 起批输出有多个字段未赋值(见 9.3(4) 与 docs/track_init_readme.md 第 14 节),宿主不应依赖这些字段。
---
## 12. 版本历史
当前代码版本:**V1.5.9**(`parameters.h` 的 `PATCH_VERSION` = 9、`VERSION_INFO` = `"GENERIC"`,版本串 `V1.5.9.GENERIC`——机扫/相扫已合并为同一份构建,无体制后缀;对应提交 019af7a,2026-10-27)。版本号自 1.5.6 起可运行时读取(`version_info`,见 7.1)。中间状态 b4aed8a 曾把版本号置为 7,但未单独发布/记录。**1.5.8 之后又有若干未发版的代码改动**(构建脚本重构、记录性能优化、TAS 消亡圈数与高度平滑调整、质量入库、参数配置方式改造、机扫/相扫版本合并与构建脚本适配),已记入 CHANGELOG 的 `[Unreleased]`,下表前列为其提交/工作区状态。
近期提交(git log --oneline,新→旧;仅列代码改动,纯文档提交略):
| 提交 | 内容 |
|---|---|
| 工作区(构建脚本适配机扫/相扫合并,未提交) | 构建不再区分 `PHASE_SCANNING` / `MECHANICAL_SCANNING`:`CMakeLists.txt` 删除 `RADAR_SCAN_MODE` 缓存变量与体制编译宏;构建目录改为 `build/<Debug\|Release>/<REC_AUTO\|REC_OFF\|REC_ON>`(去掉 PS/MS 维度);`config_paths.bat`/`configure.bat`/`build.bat`/`clean.bat` 参数改为 `<Debug\|Release> [AUTO\|ON\|OFF]`,新增 `build_config.bat`(单配置配置+构建,取代 `build_all.bat`),`clean_all.bat` 同时清理旧版 `build/X256_PS`、`build/X256_MS`;`tasks.json` 5 个任务改为「清理全部」+ 4 个「配置并构建(...)」;`settings.json`(buildDirectory 去掉 scanMode 维度)、`cmake-variants.yaml`(移除 scanMode 变体)、`c_cpp_properties.json`(合并为单个 X256 配置)、`launch.json` 同步。验证:5 个任务返回 0,4 种配置(Release/Debug × REC_OFF/REC_ON)0 warning 0 error,编译命令无体制宏,增量重建 0 编译步骤 |
| 423c200 / 019af7a(参数配置方式改造 + 机扫/相扫版本合并) | **参数配置方式改造:TOML 配置文件 → `RDP_parameter`**。新增 `rdp_parameter_loader.h/.cpp`(严格校验 11 个配置段、标量键必填、类型/范围校验、未知段/键拒绝、屏蔽区数组长度等于 `*_num`,失败 -1 且不改变当前参数)与示例 `config/config_tmp.toml`;内置 toml++ v3.4.0 单头文件 `third_party/toml/toml.hpp`;公开头删除 `struct RadarPara` 与 `track_process_parameters_initial/modify`,新增 `virtual int parameters_reload(const char*)`(`Data_Process` 实现为加载成功后整体替换 `rdp_parameter`);`data_process.h` 删除 `Work_Parameter`,各模块(kalman 11 个方法、dot_coh、dot_coh_tas、track_asso(_tas/_direct_tracking)、track_init(_direct_tracking)、track_die(_tas)、track_index_mangement、tas_ctrl)改为 `const RDP_parameter& rdp_parameter`,宏与旧字段按映射等价替换;**新增配置项 `scan_mode`(0 相扫 / 1 机扫)**,`data_process.cpp` 的 TWS 判圈由编译期 `#ifdef PHASE_SCANNING` 改为按 `scan_mode` 运行时选择(行为逐分支等价);019af7a 进一步把机扫/相扫合并为**同一份代码与同一份构建**(版本号 1.5.9、`VERSION_INFO` 改为 `GENERIC`,`PHASE_SCANNING`/`MECHANICAL_SCANNING` 不再参与任何功能);`parameters.h` 仅保留 PI、版本/日志/记录宏、`MAX_TRACK_NUM`、`RDP_TAS_QUEUE_CAPACITY`、`Round`(`UNCONF_TARGET` 已删除,起批处 `Target_Type` 直接写 0);`track_index_mangement` 航迹号表改按 `track_index_max` 分配,TAS 队列容量用 `RDP_TAS_QUEUE_CAPACITY`、运行期上限用 `tas_track_num_max`,波束类型用 `default_track_beam_type`。验证(Lead 实测,2026-10-27):合并前 8 配置、合并后 4 配置均 0 warning 0 error;Release REC_OFF DLL 331,776 字节、Debug REC_ON 4,694,528 字节、导出表 31 项(新增 `parameters_reload`,旧参数接口与 `RadarPara` 符号消失);加载器单测 233 项断言、公开接口运行期测试(含判圈运行时切换)全部通过;`RDP_parameter` 成员 / 加载器键 / TOML 键均为 63 个,11 个配置段不变。详见 CHANGELOG `[Unreleased]` |
| 1ffb287 | 增加航迹质量记录到数据库:`RdpRecTempTrack` 增 `quality`,`RdpRecTrustTrack` 增 `Quality`/`Unupdated_time`/`Point_sum`/`Valid_point_sum` 并同步注册 |
| 6284f3f | 修改 TAS 模式高度平滑点数:`track_asso_tas.cpp` 分段偏移 `+2/+3/+4/+6` → `+6/+8/+10/+12`,相扫 `H_F_WIN_LEN` 3→6(相扫 TAS 窗口 12/14/16/18、机扫 9/11/13/15;TWS 相扫随之 8/9/10/12) |
| 5d105d2 | 修改相扫模式下 TAS 航迹消亡圈数:`TRACK_DIE_ROUND_TAS` 10→20(机扫保持 96),相扫 TAS 实际连续 21 圈无实点才消亡 |
| 17a3d99 | 数据记录调试功能性能优化:`rdp_record.h` 新增 `Stats`/`stats()` 与 6 个异步入队接口及对应宏(旧 `RDP_RECORD`/`RDP_RECORD_BATCH` 保留为遗留同步接口);`Init()` 启动**异步写线程**,处理线程只入队、实体构造与批量事务由写线程完成;有界队列(64 MB / 4096 批,满则丢弃并计数);WAL + `synchronous=OFF` + 8 MB 缓存 + 去除 `AUTOINCREMENT`;写失败每表提示一次、连续 10 次熔断;`Shutdown()` 排空后 `wal_checkpoint(TRUNCATE)`;12 个记录点改为「收集 → 一次入队」,记录行数与表列不变;`parameters.h` 新增 10 个可调宏。验证与完整条目见 CHANGELOG `[Unreleased]` |
| 3dee734 | 优化配置构建脚本:构建目录改为按完整配置隔离 `build/<X256_PS\|X256_MS>/<Debug\|Release>/<REC_AUTO\|REC_OFF\|REC_ON>`;新增 `config_paths.bat`(目录推导与参数校验)、`build_all.bat`(两种扫描体制依次配置+构建)、`clean_all.bat`(清理全部配置);`configure.bat`/`build.bat`/`clean.bat` 参数改为「扫描体制 + 构建类型 + 记录模式」并自动推导目录;`tasks.json` 原有 15 个任务全部删除,仅保留 5 个任务(清理全部 + Release/Debug × REC_OFF/REC_ON 的「配置并构建全部」);`settings.json`/`cmake-variants.yaml`/`c_cpp_properties.json`/`launch.json` 同步;验证:5 个任务实际执行均返回 0,8 种配置(PS/MS × Release/Debug × REC_OFF/REC_ON)0 warning、0 error,产物位于各配置目录的 `bin/`、`lib/`(**该 PS/MS 双构建布局已由工作区的「构建脚本适配机扫/相扫合并」取代**) |
| 3088ce4(**V1.5.8** 版本号来源) | 更新版本号至 V1.5.8(`PATCH_VERSION` 7→8) |
| 782bff5 | 调整航迹质量下降逻辑(改为按未更新时长的二次函数衰减,系数 −0.0008 / −0.0025);**普通 TWS 航迹消亡条件改为由航迹质量确定**(`Quality < TRACK_DIE_QUALITY` = 0.3),重点航迹与 TAS 仍按外推圈数 |
| 4b70b24 | 航迹质量下降策略改为按点迹未更新时间计算:`Trust_Track` 新增 `Unupdated_time`,外推 ΔT 计算移到外推上限判断之外,超限后质量继续下降 |
| d9a7bd0 | 优化临时航迹质量评估(L=3 时取三点平均 SNR 并写满三点,L>3 只对末点指数平滑);航迹起始增加**按长度分级的质量门限**(L3~L7:0.7/0.6/0.5/0.4/0.3) |
| 1ae0cf2 | 增加航迹质量:`Track` 新增 `Quality`(×100 输出 0~100)、`Trust_Track` 新增 `Quality`/`Point_sum`/`Valid_point_sum`、`Temp_track` 新增 `quality`;起批时初始化质量,关联实点时按「距离+SNR+有效点占比」加权更新 |
| 3e6763c | 扫描一圈完成判据按体制区分:相扫比较前后两帧方位波位号(`Beam_index_aiz <= last_beam_num` 判满圈、`last_beam_num` 重新参与判断),机扫保持「方位波位号 == 0」(避免转台反转误判) |
| b4aed8a | 回调 TWS 外推时间差计算方法:ΔT 由「按最新时间戳实时计算」恢复为按 `work_mode` 取 `DATA_RATE_SHORT/MIDDLE/FAR` 固定值,避免 TAS 工作时同步外推出 TWS 航迹;同时把版本号置为 1.5.7(未单独发布);实时计算代码与 `latest_timestamp` 形参保留但不再参与计算 |
| e982804 | 调整临时航迹记录时机:`RdpRecTempTrack` 的写入由 `track_init_process_logic()` 末尾移到**转为可靠航迹之前**,避免本圈起批的临时航迹转走后在记录中丢失当前帧数据 |
| 56b5449 | (已被 b4aed8a 回调)TWS 外推 ΔT 改为按最新时间戳计算:`track_asso_process()`/`model_filter()` 新增 `latest_timestamp` 形参,ΔT 取 `(latest_timestamp − T_track)/1000` 且 `ΔT ≤ 0` 时跳过 |
| 5cb67cc | 增加 TAS 航迹信息与 TAS 关联信息记录:`track_asso_tas.cpp` 的输出环节记录 `RdpRecTrustTrack`、关联环节改用全局 `Asso_Info` 并记录 `RdpRecAssoInfo`;`Asso_Info`/`RdpRecAssoInfo` 新增 `tas_flag` 区分 TWS/TAS 来源 |
| b227ae1(**V1.5.6** 版本号来源) | 数据处理增加版本号输出:`parameters.h` 新增版本宏(`MAJOR_VERSION`/`MINOR_VERSION`/`PATCH_VERSION` = 1.5.6、体制后缀 `VERSION_INFO`、拼装宏 `VERSION_STRING`),基类新增公开成员 `const char* version_info` 并由 `GetB()` 赋值;Debug 下记录可靠航迹与关联信息:`struct.h` 新增全局 `Asso_Info`(含 `min_d_flag` 与门限量)、`Trust_Track` 新增 `track_id`/`point_id`/`circle_id` 与极坐标量快照 `Range`/`Azimuth`/`Elevation`/`Velocity`,新增 `RdpRecTrustTrack`/`RdpRecAssoInfo` 两张表并在 `track_asso.cpp` 输出循环与关联三处埋点,移除 `data_process.cpp` 中按输出数组批量记录的旧示例(`RdpRecTrackOut` 实体注释停用);`track_asso.cpp` 的 ΔT 分支改写为 `if (delta_T > 0)`(行为等价) |
| c3c7e66 | 增加临时航迹录入数据库(新增 `RdpRecTempTrack` 表与 `track_init.cpp` 记录点)、输入点迹增加圈 ID(`PointRecv::circle_id`、`Data_Process::circle_id` 在满圈/TAS 帧末自增);`Temp_track` 字段更名(`snr`→`SNR`、`Amp`→`amplitude`、`T`→`CPI_time`、`Temp_track_section_idx`→`temp_track_section_idx`)并新增 `temp_track_id`/`point_id`/`circle_id`/`pitch_num`;临时航迹起批时把 ID 透传给 `Trust_Track` |
| a4f32e4 | 新增数据记录功能:把过程数据录入数据库(凝聚后点迹 `RdpRecPointCohesionTWS/TAS`,输入点迹改为 `RdpRecPoint`)、`data_process.h` 新增 `point_id`/`frame_id`/`circle_id` 计数、`dot_coh`/`dot_coh_tas` 埋记录点;<br>(该提交同时把上一轮的 CMake/工具链与记录框架改动一并提交,内容见下方「工作区(未提交…)」两条) |
| 工作区(已随本次发布归档,数据记录调试功能) | 新增可选编译的数据记录调试功能:CMake 缓存变量 `RDP_DATA_RECORD`(AUTO/ON/OFF,AUTO = Debug 启用 / Release 关闭)与独立静态库 `rdp_record`(**以 C++20 编译**,雷达代码保持 C++17);内置第三方源码 `third_party/ormpp`(ormpp 0.2.0 + iguana 1.0.5 + frozen + SQLite 3.49.1 amalgamation,附 UPSTREAM.md);新增 `rdp_record.h`(`Init`/`Shutdown`/`db_path` + `RDP_RECORD`/`RDP_RECORD_BATCH` 宏,关闭时展开为空操作)、`rdp_record_entity.h`(记录实体定义区)与 `rdp_record.cpp`(实体注册区、按实体自动建表、单条/批量写入、失败降级);`Data_Process_Factory::GetB()/Destroy()` 调用 `rdp_record::Init()/Shutdown()`;`parameters.h` 新增 `RDP_RECORD_DB_DIR`(`.\rdp_records\`);`configure.bat` 新增第 4 个参数(AUTO/ON/OFF);`.gitignore` 增加 `rdp_records/`;新增 `docs/data_record_debug.md`。验证:Release(PS/MS)导出表与依赖表与改动前逐行一致、DLL 体积不变(178,688 / 178,176 字节)、构建树无记录模块目标文件;Debug(PS/MS,AUTO→启用)0 warning 0 error;运行时校验(临时程序 + Python sqlite3)确认建库、一实体一表、批量事务写入、`id` 自增、取值一致、`integrity_check` = ok,且记录目录不可创建时接口照常返回、仅提示一次 |
| 工作区(已随本次发布归档) | 编译器由 MSVC 2013(Visual Studio 12,x86)升级为 **MSVC 2022(v143,x64)**、C++ 标准提升至 **C++17**:`CMakeLists.txt` 重写(`CMAKE_CXX_STANDARD 17`、`_MSC_VER >= 1930` 强校验、`/utf-8` `/Zc:__cplusplus` `/W3`)、`.vscode/scripts/` 全部构建脚本改为 MSVC 2022(新增共享的 `msvc_env.bat`,`configure.bat` 自动清理旧工具集构建树)、VS Code 配置同步(settings / c_cpp_properties / cmake-variants / tasks 改为 MSVC2022 x64 + C++17)、修复 MSVC 2022 新增的 17 处 C4267 窄化告警;X256_PS/X256_MS × Release/Debug 四种配置均 0 warning 0 error 通过,产物为 x64 DLL(导出符号与升级前一致,仅名称修饰随架构变化) |
| e8c56f9 | 输入/输出结构适配「归一化幅度」与「速度维 FFT 点数」:`DataRev` 新增 `amp_asv`/`prn_fftn`,`Track` 新增 `amp_asv_point`/`prn_fftn_point`,内部 `PointRecv`/`Trust_Track` 同步新增字段;`track_asso.cpp` 关联实点时写入航迹、TWS 输出时写回输出结构(TAS 侧未打通,见 11.2) |
| 42b598e | 调整「向站/背站」判断条件:判据由 `acos((-x·vx − y·vy)/r/Range_V) < π/4` 改为 `acos((-x·cos(Direction_Angle) − y·sin(Direction_Angle))/r) < π/2`(去掉按合速度归一化,锥角门限由 45° 放宽到 90°),TWS/TAS 同步 |
| fc49707 | 「向站/背站」判断改用滤波速度矢量:`Flag_Direction` 不再取 `vr_point > 0`(实测径向速度受多普勒模糊影响、符号可能取反),改按航迹 IMM 速度方向与位置矢量的夹角判定(TWS/TAS 同步);`primary_target_add/cancel`、`tracking_start/stop` 命中目标后 `break`;删除 TWS 输出循环中的注释残留代码块 |
| 50e0b5c | 新增手动重点目标接口(`primary_target_add`/`primary_target_cancel` + `Trust_Track::primary_target_flag`)与重点航迹消亡圈数 `TRACK_DIE_ROUND_PRIMARY`(10);输出航迹改为只输出 `Track_Update_Flag==1` 的本圈更新航迹;未关联航迹外推限制在 `MAX_EXTRAPOLATE_NUM`(3)圈内,TAS 侧新增 `MAX_EXTRAPOLATE_NUM_TAS`(相扫 5 / 机扫 48);`TRACK_DIE_ROUND` 由 4 调整为 6、`TRACK_DIE_ROUND_TAS` 相扫由 5 调整为 10,消亡判据改为 `>`;同步更新 README/CHANGELOG/docs |
| e0bf227 | 关联判定重构并加强:TWS `track_asso.cpp` 新增按航迹距离分段的高度门限(原高度门限代码块为注释状态)、统计距离/高度/距离三类判据拆为 `thd_d`/`thd_h`/`thd_r` 布尔量;`parameters.h` 的 `ASSO_THORD` 由 3 调大至 4(等效门限 d < 4,提高机动目标关联概率);TAS `track_asso_tas.cpp` 高度门限 2000~3000 m 段由 200 m 放宽至 250 m;修复 `tas_beam_output()` 的数据率门控条件(去掉与「取最早 CPI 目标」冲突的 T_track 判据);删除 `docs/data_process_flow_report.html`;`.gitignore` 增加 `design_docs/`;同步更新 README/CHANGELOG/docs |
| f249fdc | 输出航迹新增「靠近/远离」方向标志:`track_asso.cpp`(TWS)与 `track_asso_tas.cpp`(TAS)在写入 `vr_point` 后补 `Flag_Direction = vr_point > 0 ? 1 : 0`;新增 `docs/data_process_flow_report.md`、`docs/data_process_flow_report.html`、`docs/track_init_readme.md` 三份流程与专项文档(其中 HTML 版已于 e0bf227 删除) |
| 7d5a56f | 满圈判据由「波位号变小」改为「方位波位号 == 0」(避免机扫转台反转误判,`data_process.cpp`);点-航迹头关联改为统一速度区间 `V_MIN·ΔT ≤ dis ≤ V_MAX·ΔT` 并新增 `dis ≥ |vr_point|·ΔT`、`dis ≥ |v_track_head|·ΔT` 两条多普勒-几何一致性约束,限制切向高速短航迹(`track_init.cpp`);同步更新 README/CHANGELOG |
| 604f158 | TWS 关联中 ΔT≤0(点迹时间戳不晚于航迹时间)的候选不再剔除:仍参与最近邻选取但不更新 IMM/EKF、不刷新航迹时间与新鲜度,并标记该点迹已使用(`Use_Flag=1`)消费掉,避免其继续参与航迹起始生成虚假 TWS 航迹;`track_asso.cpp` 的 ΔT≤0 告警日志注释停用;过期文档(BUG_REPORT.md、BUG_FIX_REPORT.md、requirements.md)移入 archived_docs/ 留档 |
| d6cdbc0 | 删除 `data_process.cpp`、`dot_coh.cpp` 中已注释停用的调试输出与早期 1 km SNR 过滤代码残留(不改变运行逻辑);同步更新 README/CHANGELOG |
| 1521592 | 新增日志模块(`rdp_log.h/.cpp`,CMake SOURCES 注册、.gitignore 忽略 `rdp_logs/`):`RDP_LOG_ENABLE` / `RDP_LOG_DIR` 宏(parameters.h)、std::cout 经 `rdbuf()` 重定向到 `.\rdp_logs\` 下日期+时间命名日志、`RDP_LOG` 前缀宏、ΔT≤0 告警日志;`RadarPara.DATA_RATE_TAS` 单位由 Hz 改为 s;修复 `tas_beam_output()` 将向量下标误赋给 `Tracking_beam->TAS_track_index` 的问题;更新 README/CHANGELOG |
| 5f82098 | 修复 MSVC `/W3` 下全部 C4819 / C4018 / C4244 警告(UTF-8 with BOM、size_t / static_cast 等);更新项目文档 |
| f438ac5 | 优化 TAS 调度:波束输出改为在队列内选择满足数据率门控且 CPI 时间最早的目标,停用整队循环移位;DATA_RATE_TAS 编译期宏停用、统一使用运行时参数;#pragma message 提示扫描体制 |
| e729c5b | 频点宏精简为 FREQ0 = 9.2 GHz(原 FREQ0~FREQ20 均为 16.8 GHz) |
| b3e2f52 | TAS 波束控制改为按固定数据率调度,RadarPara 新增 DATA_RATE_TAS 运行时参数;新增 CHANGELOG.md、requirements.md,README 补充相应说明 |
| 93d3924 | 新增 README.md(本文档);移除 requirements.md;调整 .gitignore |
| 3500652 | 去掉 1 km 以内航迹起批的 20 dB 信噪比门限 |
| 01d28e0 | 改用 VS Code + CMake 重新编译(编译器不变);修复若干逻辑 BUG(见 archived_docs/BUG_FIX_REPORT.md) |
| 0cb31b4 | 删除不必要文件;输入点迹/输出航迹的 CPI 与 GNSS 时间改为 64 位整型;修复 TAS 外推时间差可能无效的问题 |
| d101fe9 | 增加航迹清空功能(解决重连乱窜);TAS 外推时间间隔按波束时间计算;增加 1 km 内 SNR<20 dB 不起批限制(后于 3500652 移除) |
| 8636179 | 机扫/相扫程序合并,宏定义配置切换 |
| 06d45f5 | 机扫跟踪增加高度门限判断 |
| 8b1896d | 适配四面阵机扫跟踪模式 |
| ae3ef84 | 扫描一圈完成判断改为「波位号变小」 |
| e9b8a32 | 修复 R 矩阵赋值、波位号判断、点数上限、空容器、雅可比取值、起批负索引、容器 push_back 后修改失效、机扫参数等 8 项 |
| 28fcf06 | 统一代码缩进格式 |
| 7c10ae9 / 958ff6b | TWS 关联增加俯仰门限 / 点航距离门限(限制远距离突跳关联) |
| 2b1293a / 167fa79 | 去掉自动转 TAS,只保留手动转 TAS;起批时手动转跟踪标志清零 |
| 6008959 | 添加「航迹点迹区分区说明.vsdx」(后随 0cb31b4 删除不必要文件而移除) |
| d6e43d6 / 199ae34 | 点迹凝聚角度约束调整;凝聚条件按模式区分(近程:距离/速度/方位;中远程:距离/方位) |
| 06938b2 | 航迹起始增加屏蔽区域 |
---
## 13. 参考文档
| 文档 | 内容 |
|---|---|
| CHANGELOG.md | 变更日志(Keep a Changelog 格式,按 git 提交记录维护) |
| docs/data_process_flow_report.md | 数据处理流程与关键逻辑说明(按当前源码整理:前处理与判圈、凝聚、TWS/TAS 关联与滤波、航迹起始、外推消亡、TAS 波束控制、参数脉络;参数来源已同步为 TOML → `RDP_parameter`;含与本文档的历史差异提示)——原同内容 HTML 渲染版(`data_process_flow_report.html`)已于 e0bf227 删除,HTML 版本在 git 忽略的 `design_docs/` 内留档 |
| docs/track_init_readme.md | 航迹起始(Track Init)专项说明:分阶段流程、起始条件汇总、调参直觉、输出字段映射(含未赋值字段)、已知风险与代码索引 |
| docs/data_record_debug.md | 数据记录调试功能说明:开关与构建(`RDP_DATA_RECORD`、C++20 隔离与 C 编译器要求、关闭时零代码依据)、运行期行为(异步写线程、有界队列与丢弃、批事务参数、WAL/PRAGMA、去 AUTOINCREMENT、失败降级与熔断、Shutdown 排空与统计、Destroy→GetB 重连)、记录实体(表)约定、**新增记录点四步配方**(实体→异步入队接口/宏→写线程分支→业务侧收集调用)、当前 6 张在用记录表与记录点清单(含新宏与 file:line)、查询示例、已知限制与验收参考 |
| third_party/ormpp/UPSTREAM.md | 内置第三方源码的来源说明:ormpp / iguana / frozen / SQLite 版本、许可证、复现与升级步骤(含 blob 校验值) |
| archived_docs/BUG_REPORT.md | 全量逻辑 BUG 分析(P0~P3 共 37 项,含位置、说明、建议、处置结论)——过期留档,仅作历史参考 |
| archived_docs/BUG_FIX_REPORT.md | 修复明细、修复状态汇总表与 MSVC 2013 x86 编译验证记录——过期留档(对应 01d28e0 时期) |
| requirements.md | 修改需求说明:**雷达参数配置方式改造**(删除 `RadarPara`/旧参数接口、新增 `parameters_reload(const char*)`、TOML 配置文件 → `RDP_parameter`)——已按该说明实现(见 10);此前同名的数据记录调试功能与日志文件输出需求亦已实现,分别见 docs/data_record_debug.md 与 10.4 |
| config/config_tmp.toml | 参数配置样例(TOML,11 个配置段、63 个键与 `RDP_parameter` 成员一一对应,样例为相扫取值(`scan_mode=0`);机扫差异项见 10.1 兼容性提示)——参数表见 10.2 |
| third_party/toml/toml.hpp | 内置 toml++ v3.4.0 单头文件(MIT,上游原样保存);仅参数加载器 `rdp_parameter_loader.cpp` 以 `#pragma warning(push, 0)` 包裹使用,来源与许可证信息见文件头 |
| backup/data_process_class_dll/data_process_class_dll.pro | 迁移前的 Qt/qmake 工程文件(源文件清单参考) |
| .vscode/tasks.json、.vscode/cmake-variants.yaml、.vscode/scripts/*.bat | VS Code 任务、构建变体与构建脚本(构建目录布局见 4.3) |
| build/<Debug\|Release>/<REC_*>/bin/RadarConfigParam.ini | 回放测试工具(rdp_playback.exe)配置样例(需自行放置) |