# 雷达数据处理 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. 先修 P0:BUG-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 一致),其中问题与主流程同类问题重复,修复主流程时可同步修改或暂缓。