Files
radar_data_process/archived_docs/BUG_REPORT.md
T
waiwaylee 604f1585f6 更新:1、TAS航迹不关联时间戳更早的TWS点迹,但标记点迹已使用,避免生成TWS航迹;
2、调整目录结构,将过期的文档都放到archived_docs文件夹中留档;

Signed-off-by: waiwaylee <waiwaylee@foxmail.com>
2026-09-12 10:01:15 +08:00

277 lines
20 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 逻辑 BUG 分析报告
分析范围:`data_process_class_dll/` 下全部源码(不含 `Eigen/`),以迁移后的当前代码行号为准。
严重级别定义:
- **P0**:可能导致崩溃、越界读写、内存破坏或长时间运行内存泄漏,建议优先修复。
- **P1**:在常见异常时序/边界输入下会出错,或属于明显算法逻辑错误。
- **P2**:健壮性、数值稳定性、状态一致性、功能缺失等问题。
- **P3**:代码质量/可维护性问题。
---
## 1. 内存与生命周期
### BUG-01 [P0] 基类没有虚析构函数,工厂按基类指针 delete 派生对象
- 位置:`data_process_class_dll.h:168``data_process_class_dll.cpp:25-32`
- 说明:`Data_process_class_dll` 没有声明虚析构函数,而 `Data_Process` 内部包含多个 `std::vector` 和若干成员对象。`Data_Process_Factory::Destroy()` 执行 `delete p` 时静态类型是基类指针,只会调用基类析构函数,派生类成员(`Data_buffer``trust_track``temp_track`、Eigen 相关对象等)的析构不会执行,属于未定义行为并造成内存泄漏。
- 建议:在基类中增加 `virtual ~Data_process_class_dll() {}`;同时让工厂支持重复销毁、销毁后返回 nullptr。
- 暂不修复
### BUG-02 [P1] `Hight_smooth` 高度平滑缓存只增不减,长时间运行内存持续增长
- 位置:`track_asso.cpp:890``track_asso_tas.cpp:722``track_asso_direct_tracking.cpp:639`
- 说明:每次高度更新都执行 `Hight_smooth.push_back(...)`,从未裁剪或清空。航迹存活时间越长,该 vector 越大;500 条航迹长时间运行时内存会持续增长。
- 建议:仅保留最近 `height_win_length` 个高度值(如 `resize`/`erase(begin)` 后再 push),或改用固定长度 `std::deque`;航迹消亡时随结构体释放。
- 暂不修复
### BUG-03 [P2] 工厂单例创建/销毁非线程安全
- 位置:`data_process_class_dll.cpp:15-32`
- 说明:`GetB()``Destroy()` 对静态指针 `p` 无任何同步。若宿主在多线程环境调用,可能创建两个实例(泄漏一个)或对同一对象重复销毁。
- 建议:用 C++11 `static Data_Process instance;` 返回地址,或对工厂方法加锁;明确 DLL 接口的线程模型。
- 暂不修复
---
## 2. 数组/向量越界
### BUG-04 [P0] TAS 输入点迹未限制 `Point_Sum <= 150`
- 位置:`data_process.cpp:66`
- 说明:TWS 分支使用 `min(Point_Sum, 150)`,但 TAS 分支直接 `data_num = Data_Input[0].Point_Sum` 并循环读取 `Data_Input[i]`。当协议传入 `Point_Sum > 150` 时,会越界读取 `Data_Input[150]`
- 建议:与 TWS 分支一致,使用 `data_num = min(max(Point_Sum,0), 150)`,并校验 `Point_Sum >= 0`
- 按建议修复
### BUG-05 [P0] `Track_to_start.size()-1` 在空容器时下溢导致越界
- 位置:`track_init.cpp:534`
- 说明:与已发现示例一致。`size()` 返回 `size_t`,空容器减 1 得到极大值,随后 `Track_to_start[i]` 越界。
- 建议:`if (Track_to_start.empty()) return;`,或改为 `for (size_t i = 0; i + 1 < Track_to_start.size(); ++i)`
- 按建议修复,改为 `for (size_t i = 0; i + 1 < Track_to_start.size(); ++i)`
### BUG-06 [P0] `track_start_point_num` 未校验,取值 0/1/2 或大于 9 时多处越界
- 位置:`track_init.cpp:533,544-545,588-594``track_init_direct_tracking.cpp:316-322`
- 说明:重复航迹比较固定访问 `Track_to_start[i][1]``[2]`,三点初始化访问 `[L-3]/[L-2]/[L-1]`。该参数由外部 `RadarPara` 传入,若未初始化或配置为 0/1/2,会出现负下标或越界;若大于 9,`tmp_track_die` 会在 `n>=10` 时删除临时航迹,逻辑也无法起批。
- 建议:在 `track_process_parameters_initial/modify` 中校验 `3 <= track_start_point_num <= 9`;使用 `Track_to_start[i].size()` 作为实际长度并在访问前检查。
- 按建议修复
### BUG-07 [P0] 禁止区域个数未限制在 30 以内,外部配置过大时数组越界
- 位置:`track_init.cpp:711``track_prohibite_area_num`)、`tas_ctrl.cpp:123``TAS_prohibite_area_num`
- 说明:循环上界直接使用外部传入的计数,而对应数组固定为 `[30]`。配置大于 30 时越界读。
- 建议:循环上界改为 `min(count, 30)`,并在参数初始化/修改时拒绝非法计数或截断。
- 暂不修复
### BUG-08 [P1] 消亡航迹号输出无数组容量检查
- 位置:`track_die.cpp:24``track_die_tas.cpp:26`
- 说明:`Track_die_Index_Output[*Track_die_num_Output-1] = ...` 不检查数组容量。正常流量下最多 500 条航迹,与 `MAX_TRACK_NUM` 一致,但接口没有把容量传入,一旦宿主传入较小数组、或计数被异常修改,就会越界写。
- 建议:接口增加 `die_array_capacity` 参数,或内部保证 `*Track_die_num_Output < MAX_TRACK_NUM` 后再写。
- 暂不修改
### BUG-09 [P1] `Beam_Ctrl` 路径中输出计数未初始化/无上界,可能越界写航迹输出数组
- 位置:`data_process.cpp:193-198``tas_ctrl.cpp:74-78`
- 说明:`Beam_Ctrl()` 直接使用宿主传入的 `Trust_track_num_Output`,而 `tas_ctrl_process` 不会先清零,`tas_target_add` 会基于旧值自增并写 `Trust_Track_Output[*Trust_track_num_Output-1]`。若调用方未清零或旧值接近 `MAX_TRACK_NUM`,会越界写。
- 建议:`tas_ctrl_process` 内部保存 `*count = 0` 或在每次写入前检查 `*count < MAX_TRACK_NUM`;同时校验指针非空。
- 按建议修改
### BUG-10 [P1] 航迹号直接作为数组下标,未校验范围
- 位置:`track_index_mangement.cpp:29`
- 说明:`List[(*trust_track)[i].Track_Index-1] = 1`,若航迹号不在 `[1, MAX_TRACK_INDEX]` 内(异常数据、内存损坏、外部修改),立即越界。
- 建议:写前检查 `Track_Index >= 1 && Track_Index <= MAX_TRACK_INDEX`,异常航迹号返回错误或跳过。
- 按建议修改
---
## 3. 未初始化变量
### BUG-11 [P1] `Track_Asso_Tas::model_filter` 在找不到 TAS 目标时使用未初始化变量
- 位置:`track_asso_tas.cpp:228-232`,随后在 `271/276/280/282` 等使用
- 说明:`X1/X2/X3/P1/P2/P3/T_track/v_track/r_track/h_track` 只在 `Track_Index == tas_track_idx` 时赋值。若 `tas_track_idx` 不存在(例如目标已被消亡、主程序传入失效批号),后续仍用这些未初始化值计算 IMM、距离门限和外推,结果不可预测。MSVC `/W4` 已报 C4701。
- 建议:函数开头初始化这些变量,并在找不到目标时直接 return;上层也应处理“TAS 目标不存在”的返回值。
- 按建议修改
### BUG-12 [P1] `tas_beam_output` 在队列目标不在航迹表中时使用未初始化变量
- 位置:`tas_ctrl.cpp:242-271`
- 说明:`H_track``X_now[]` 只在找到匹配航迹时赋值;若 `track_clear_all()` 后队列未清空、或目标已被删除而队列未同步,循环找不到目标,随后 `asin(H_track/range)``X_now[...]` 使用未初始化数据。Cppcheck 和 MSVC `/W4` 均报 C4701。
- 建议:找不到目标时立即 `open_flag=0` 并 return;变量声明时初始化。
- 按建议修改
### BUG-13 [P2] `Data_Process::Work_Parameter` 及若干成员在构造后未初始化
- 位置:`data_process.h:28-31,78-95`
- 说明:构造函数为空,`Work_Parameter``Beam_num``data_num``TAS_track_idx` 等未初始化。若宿主在调用 `track_process_parameters_initial` 前就调用 `data_preprocess/track_process/Beam_Ctrl``Work_Parameter.track_start_point_num``Sys_delay``V_MIN/V_MAX` 等是垃圾值,可能导致起批越界、除零或异常门限。
- 建议:构造函数中对 `Work_Parameter` 进行 `memset`/值初始化并设置安全默认参数;在处理函数入口检查“参数是否已初始化”。
- 暂不修复
### BUG-14 [P3] `Track_Ind_Mangement::lastest_index` 未初始化
- 位置:`track_index_mangement.h:17``track_index_mangement.cpp:33`
- 说明:只有空航迹表分支会赋值为 1;如果首次调用时航迹表非空,就会读取未初始化的 `lastest_index`
- 建议:声明为 `int lastest_index = 0;` 或增加构造函数初始化。
- 按建议修改
---
## 4. 时间戳/时序处理
### BUG-15 [P1] TWS 关联在 `delta_T <= 0` 时仍把点迹标记为已关联并刷新航迹状态
- 位置:`track_asso.cpp:610-691`
- 说明:滤波和航迹信息更新在 `if (delta_T > 0)` 内,但 `Extrapolate_round=0``point_flag=1``associate_point_number++`、点迹 `Use_Flag=1` 都在 if 之外。重复/乱序时间戳的点仍会“占用”点迹、让航迹看起来已更新,实际状态未更新。
- 建议:`delta_T <= 0` 时直接跳过该关联候选(或作为无效量测处理),不要标记点迹已使用、不要刷新航迹新鲜度。
- 按建议修改
### BUG-16 [P1] TAS 关联完全没有 `delta_T > 0` 检查
- 位置:`track_asso_tas.cpp:271-335,385-452`
- 说明:TAS 路径计算 `delta_T` 后直接进入统计距离和滤波,即使 `delta_T <= 0` 也会生成 F/Q 并更新航迹,可能把航迹时间更新到过去。
- 建议:与 TWS 一致,只有 `delta_T > 0` 才允许关联;否则跳过该点。
- 按建议修改
### BUG-17 [P1] TAS 外推使用未校验的 `latest_timestamp - T_track`,负时间差导致反向预测
- 位置:`track_asso_tas.cpp:483-506`
- 说明:若 `latest_timestamp < T_track`(乱序/重复时间戳),`delta_T` 为负,`T_track += delta_T*1000` 会回退航迹时间,IMM F/Q 也按负时间生成。
- 建议:`delta_T = max(0, latest_timestamp - T_track)/1000.0`;若为 0 则直接返回或保持原状态。
- 按建议修改
### BUG-18 [P1] 卡尔曼初始化及统计距离函数对零/负时间差没有保护
- 位置:`kalman.cpp:13-46,126-130,158-168`;调用点 `track_init.cpp:275,450,593-594``track_init_direct_tracking.cpp:135,271,321-322`
- 说明:两点/三点初始化直接除以 `T/T1/T2`。同一 CPI 重复点、时间戳相等或乱序会产生除零、inf/NaN,随后污染航迹协方差和模型概率。
- 建议:调用前统一校验时间差大于最小阈值(如 >0 或 >1 ms);`kalman_filter_init_2dots/3dots` 内部对非法时间返回错误。
- 暂不修改
### BUG-19 [P1] `Bind_speed` 对 `prt == 0` 无保护,而接口说明 PRI 可给 0
- 位置:`kalman.cpp:766-770``data_process_class_dll.h:29`
- 说明:`return 150000.0/(freq*prt)`,当 `PRI=0` 时除零;结果传给 `Round()` 会把 inf/NaN 转换为未定义整型。
- 建议:`prt <= 0` 时返回固定安全值或直接返回无效距离;统一约定 PRI 单位与默认值。
- 按建议修改,同时修改接口说明:PRI不可为0
---
## 5. 关联门限与滤波算法逻辑
### BUG-20 [P1] 统计距离 d 已经是平方形式,门限中又平方了一次
- 位置:`track_asso.cpp:544-546``track_asso_tas.cpp:335``track_asso_direct_tracking.cpp:286``track_init.cpp:221`
- 说明:`d_cal_EKF` 返回的是 `delta_z^T S^{-1} delta_z`(马氏距离平方),后续门限却写成 `d*d < THRESHOLD*THRESHOLD`。例如阈值 3 时本意是 `d < 9`,实际变成 `d < 3`,波门明显偏小。
- 建议:统一改为 `d < TRACK_START_THRESHOLD*TRACK_START_THRESHOLD` / `d < ASSO_THORD*ASSO_THORD`
- 暂不修改
### BUG-21 [P1] 近程模型 3 门限因整数除法恒为 0
- 位置:`track_asso.cpp:544-545`
- 说明:`ASSO_THORD` 是 int 宏,`ASSO_THORD*ASSO_THORD/1000``/100` 按整数计算,结果均为 0,导致 `d3*d3 < 0` 永远不成立;近距离下模型 3 实际被禁用。
- 建议:写为 `ASSO_THORD*ASSO_THORD/1000.0``/100.0`,同时按 BUG-20 修正平方关系。
- 按建议修改,但不修改BUG-20
### BUG-22 [P1] EKF 方位角残差未按 0/2π 环绕处理
- 位置:`kalman.cpp:265-298,457-492,642-680`;凝聚 `dot_coh.cpp:35,44``work_mode==0` 分支)、`dot_coh_tas.cpp:33,42`
- 说明:预测方位被归一化到 `[0,2π)`,但量测方位未归一化,`delta_z = Z_mea - Z_pred` 未做 ±π 环绕。目标跨正北时残差会接近 2π,导致错误拒绝/错误滤波。凝聚中 `work_mode==0` 和 TAS 凝聚也直接 `fabs(angle)`,未处理 360° 环绕。
- 建议:方位差统一按 `wrapToPi()` 处理;`work_mode==0` 与 TAS 凝聚复用同一环绕角差函数。
- 按建议修改
### BUG-23 [P1] IMM 模型概率计算缺少零分母/奇异矩阵保护
- 位置:`track_asso.cpp:157-165,627-647``track_asso_tas.cpp:122-130,406-431``track_asso_direct_tracking.cpp:95-103,352-374`
- 说明:`c[0..2]``Possibility1*c[0]+...``det_S` 都可能为 0 或负;`1/sqrt(2*PI*det_S)` 对负/零行列式产生 NaN。一旦概率变 NaN,后续 `model_output` 会把整条航迹状态污染。
- 建议:计算前检查 `det_S > eps`、分母 > eps;异常时保持上一拍模型概率或回退为等概率 `{1/3,1/3,1/3}`
- 按建议修改
### BUG-24 [P2] EKF 似然只取 3x3 新息协方差左上角 2x2 的行列式
- 位置:`kalman.cpp:515-519`(S 为 3x3,但输出只保存 2x2);调用处 `track_asso.cpp:627-633``track_asso_tas.cpp:406-412``track_asso_direct_tracking.cpp:352-358`
- 说明:EKF 量测为距离/方位/径向速度三维,新息协方差 S 是 3x3,但接口 `S_filter[2][2]` 和似然计算只使用二维子块,模型似然不完整。
- 建议:将接口改为 3x3,并采用完整 3 维高斯归一化因子 `1/sqrt(pow(2*PI,3)*detS)`(若只比较相对大小,也至少应保持三个模型使用相同维数)。
- 按建议修改
### BUG-25 [P1] TWS 航迹关联/输出没有排除 TAS 航迹
- 位置:`track_asso.cpp:65-133`(输出)、`141-228`(交互
)、`414-570`(滤波)
- 说明:原代码中有 `// if manual_tracking_flag==0` 的过滤逻辑但被注释掉。当前 TWS 处理会遍历并更新所有航迹,包括 `Track_Mode==1` 的 TAS 航迹;TWS 输出循环也会把 TAS 航迹当作 `point_type=0` 输出,造成 TAS 航迹被 TWS 点迹错误更新和重复输出。
- 建议:TWS 的交互、关联、输出统一跳过 `Track_Mode == 1`(或 `manual_tracking_flag == 1`)的航迹;TAS 目标只在 TAS 流程中处理。
- 暂不处理
### BUG-26 [P2] 输出航向角使用 `atan(y/x)` 而不是 `atan2`
- 位置:`track_asso.cpp:100``track_asso_tas.cpp:66``track_asso_direct_tracking.cpp:59`
- 说明:当 `vx == 0` 时除法结果接近 ±inf,现有象限修正逻辑不完整,某些象限会输出负角度或 90° 偏差。
- 建议:统一使用 `atan2(X[4], X[1])` 并归一化到 `[0,2π)`
- 按建议修改
### BUG-27 [P2] `asin(height/range)` 缺少定义域和零距离保护
- 位置:`track_asso_tas.cpp:54``track_asso_direct_tracking.cpp:48``track_init.cpp:646,673`
- 说明:`range` 为 0 或 `height > range` 时,`asin` 参数超出 `[-1,1]` 产生 NaN,并输出到 `Track.Elevation`
- 建议:计算前钳位 `h/r``[-1,1]`,并对 `r <= eps` 特殊处理。
- 按建议修改
---
## 6. 状态清理与接口一致性
### BUG-28 [P1] `track_clear_all` 清理不彻底,重连后可能输出幽灵航迹/幽灵波束
- 位置:`data_process.cpp:219-229`
- 说明:只清空 6 个顶层 vector,未清理:
- `Dot_Coh::data_input_buff`(滑窗凝聚缓存);
- `TAS_Ctrl::tas_target_queue``tas_target_num`
- `last_beam_num`(扫描圈判断);
- `Track_Ind_Mangement::lastest_index`
- 各关联类的 `point_process` 成员。
清空后若立即调用 `Beam_Ctrl`TAS 队列仍认为有目标,但 `trust_track` 已空,会触发 BUG-12 的未初始化路径并输出错误波束;下一次 TWS 处理也可能输出清空前的缓存点迹。
- 建议:为 `Dot_Coh``TAS_Ctrl``Track_Ind_Mangement` 增加 `reset()``track_clear_all` 调用所有 reset,并恢复 `last_beam_num=INT_MAX`
- 按建议修改
### BUG-29 [P2] `tracking_stop` 后 TAS 队列要到下一次 `Beam_Ctrl` 才移除
- 位置:`data_process.cpp:260-270``tas_ctrl.cpp:138-162`
- 说明:`tracking_stop` 只清标志位和 `Track_Mode`,不会立即清 `tas_target_queue`。在调用 `Beam_Ctrl` 前,队列仍会输出该目标的跟踪波束。
- 建议:`tracking_stop` 内同步删除 TAS 队列项并更新 `tas_target_num`,或明确接口时序并文档化。
- 暂不修改
### BUG-30 [P2] 工作模式枚举与代码分支不一致
- 位置:`data_process_class_dll.h:140`(注释:0 进程、1 中程、3 远程)、`track_asso.cpp:729-744`(按 0/1/2/else 分支)
- 说明:注释定义远程模式为 3,但代码按 `work_mode==2` 使用远距数据率;当外部按注释传 3 时,会落入 else 使用近程数据率 `DATA_RATE_SHORT`
- 建议:统一枚举定义,或代码改为 `work_mode==3` 使用 `DATA_RATE_FAR`
- 注释有误,修改注释为:0 进程、1 中程、2 远程
### BUG-31 [P2] `tracking_point` 和引导跟踪处理是空实现
- 位置:`data_process.cpp:282-286``data_process_class_dll.h:200-213``track_init_direct_tracking.cpp:11-21`
- 说明:`tracking_point` 直接返回 0`Data_Process` 没有重写 `direct_tracking_process`,基类默认返回 0`Track_Init_Direct_Tracking::track_init_process_logic` 也是空函数。若接口已被主程序调用,则相关功能实际未生效。
- 建议:确认这两个接口是否已废弃;若仍需要,补齐实现或至少在文档中明确为未实现并返回错误码。
- 在注释中明确接口未启用,保留空实现
---
## 7. 其他逻辑与健壮性
### BUG-32 [P2] 凝聚内层循环没有跳过已标记使用的点
- 位置:`dot_coh.cpp:25,148``dot_coh_tas.cpp:25`
- 说明:内层只检查当前基准点 `loop_of_point``Use_Flag`,没有检查被比较点 `i``Use_Flag`。已被凝聚掉的点仍可参与后续比较,甚至反过来把高幅度基准点标记掉。
- 建议:内层同样判断 `(*data_input)[i].Use_Flag != 1`(以及 `data_tmp[i]`)。
- 按建议修改
### BUG-33 [P2] 起批/临时航迹关联未校验 `delta_T > 0`,重复时间戳可能产生非法卡尔曼初始化
- 位置:`track_init.cpp:189,381,450``track_init_direct_tracking.cpp:67,221,271`
- 说明:点迹与临时航迹、点迹与航迹头的关联均使用 `T_point - T_track_head`,未要求正时间差。`kalman_filter_init_2dots` 遇到 0/负 T 会产生除零。
- 建议:在关联条件中显式要求 `T_point > T_track_head`,且时间差需大于最小步长。
- 暂不修改
### BUG-34 [P2] 临时航迹消亡函数在空向量时直接取 `[n-1]`
- 位置:`track_init.cpp:694-695``track_init_direct_tracking.cpp:417-418`
- 说明:`int n = (*Iter).size();` 后立即 `(*Iter)[n-1]`。正常流程每条临时航迹至少 1 个点,但没有防御;一旦出现空内层向量,`n-1` 为负并越界。
- 建议:先判断 `n > 0`,空向量直接删除。
- 按建议修改
### BUG-35 [P3] 航迹号复用逻辑漏掉 `MAX_TRACK_INDEX`
- 位置:`track_index_mangement.cpp:44,56`
- 说明:回绕查找循环写作 `i < MAX_TRACK_INDEX`,因此 500 号航迹永远不会被复用;与第一段 `i <= MAX_TRACK_INDEX` 不一致。
- 建议:两处回绕循环改为 `i <= MAX_TRACK_INDEX`
- 按建议修改
### BUG-36 [P3] TAS 波束关闭时只清 `open_flag`,其他字段保留旧值
- 位置:`tas_ctrl.cpp:277-284`
- 说明:当 `tas_target_queue[0].empty_flag==0` 时,仅设置 `Tracking_beam->open_flag=0``Range/Azi/Elev/type/TAS_track_index` 保留上一拍内容。主程序若只按 `open_flag` 判断则无问题,但字段语义不清晰。
- 建议:关闭时同时清零 `type/Range/Azi/Elev/TAS_track_index`
- 暂不修改
### BUG-37 [P3] 部分结构体局部变量未完整初始化
- 位置:`track_init.cpp:80,598``track_init_direct_tracking.cpp:325`
- 说明:`Temp_track temp_track_tmp``Trust_Track trust_track_tmp``P` 矩阵等字段未显式初始化。当前流程部分字段未被读取,但依赖调用顺序;后续维护容易读到垃圾值。
- 建议:使用值初始化 `Temp_track tmp = {};` 或为结构体提供构造函数/`init()` 统一初始化所有字段。
- 按建议修改
---
## 建议修复顺序
1. 先修 P0BUG-01、BUG-04、BUG-05、BUG-06、BUG-07、BUG-11、BUG-12。
2. 再修 P1 时间与关联逻辑:BUG-15~BUG-23、BUG-25、BUG-28。
3. 最后处理数值稳定性、状态一致性和未启用功能:BUG-24、BUG-26~BUG-37。
> 说明:`track_asso_direct_tracking.cpp` 和 `track_init_direct_tracking.cpp` 当前未加入 CMake 构建(与旧 .pro 一致),其中问题与主流程同类问题重复,修复主流程时可同步修改或暂缓。