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

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

20 KiB
Raw Permalink Blame History

雷达数据处理 DLL 逻辑 BUG 分析报告

分析范围:data_process_class_dll/ 下全部源码(不含 Eigen/),以迁移后的当前代码行号为准。 严重级别定义:

  • P0:可能导致崩溃、越界读写、内存破坏或长时间运行内存泄漏,建议优先修复。
  • P1:在常见异常时序/边界输入下会出错,或属于明显算法逻辑错误。
  • P2:健壮性、数值稳定性、状态一致性、功能缺失等问题。
  • P3:代码质量/可维护性问题。

1. 内存与生命周期

BUG-01 [P0] 基类没有虚析构函数,工厂按基类指针 delete 派生对象

  • 位置:data_process_class_dll.h:168data_process_class_dll.cpp:25-32
  • 说明:Data_process_class_dll 没有声明虚析构函数,而 Data_Process 内部包含多个 std::vector 和若干成员对象。Data_Process_Factory::Destroy() 执行 delete p 时静态类型是基类指针,只会调用基类析构函数,派生类成员(Data_buffertrust_tracktemp_track、Eigen 相关对象等)的析构不会执行,属于未定义行为并造成内存泄漏。
  • 建议:在基类中增加 virtual ~Data_process_class_dll() {};同时让工厂支持重复销毁、销毁后返回 nullptr。
  • 暂不修复

BUG-02 [P1] Hight_smooth 高度平滑缓存只增不减,长时间运行内存持续增长

  • 位置:track_asso.cpp:890track_asso_tas.cpp:722track_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-594track_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:711track_prohibite_area_num)、tas_ctrl.cpp:123TAS_prohibite_area_num
  • 说明:循环上界直接使用外部传入的计数,而对应数组固定为 [30]。配置大于 30 时越界读。
  • 建议:循环上界改为 min(count, 30),并在参数初始化/修改时拒绝非法计数或截断。
  • 暂不修复

BUG-08 [P1] 消亡航迹号输出无数组容量检查

  • 位置:track_die.cpp:24track_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-198tas_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_trackX_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_ParameterBeam_numdata_numTAS_track_idx 等未初始化。若宿主在调用 track_process_parameters_initial 前就调用 data_preprocess/track_process/Beam_CtrlWork_Parameter.track_start_point_numSys_delayV_MIN/V_MAX 等是垃圾值,可能导致起批越界、除零或异常门限。
  • 建议:构造函数中对 Work_Parameter 进行 memset/值初始化并设置安全默认参数;在处理函数入口检查“参数是否已初始化”。
  • 暂不修复

BUG-14 [P3] Track_Ind_Mangement::lastest_index 未初始化

  • 位置:track_index_mangement.h:17track_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=0point_flag=1associate_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-594track_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_speedprt == 0 无保护,而接口说明 PRI 可给 0

  • 位置:kalman.cpp:766-770data_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-546track_asso_tas.cpp:335track_asso_direct_tracking.cpp:286track_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,44work_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-647track_asso_tas.cpp:122-130,406-431track_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-633track_asso_tas.cpp:406-412track_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:100track_asso_tas.cpp:66track_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:54track_asso_direct_tracking.cpp:48track_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_queuetas_target_num
    • last_beam_num(扫描圈判断);
    • Track_Ind_Mangement::lastest_index
    • 各关联类的 point_process 成员。 清空后若立即调用 Beam_CtrlTAS 队列仍认为有目标,但 trust_track 已空,会触发 BUG-12 的未初始化路径并输出错误波束;下一次 TWS 处理也可能输出清空前的缓存点迹。
  • 建议:为 Dot_CohTAS_CtrlTrack_Ind_Mangement 增加 reset()track_clear_all 调用所有 reset,并恢复 last_beam_num=INT_MAX
  • 按建议修改

BUG-29 [P2] tracking_stop 后 TAS 队列要到下一次 Beam_Ctrl 才移除

  • 位置:data_process.cpp:260-270tas_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-286data_process_class_dll.h:200-213track_init_direct_tracking.cpp:11-21
  • 说明:tracking_point 直接返回 0Data_Process 没有重写 direct_tracking_process,基类默认返回 0Track_Init_Direct_Tracking::track_init_process_logic 也是空函数。若接口已被主程序调用,则相关功能实际未生效。
  • 建议:确认这两个接口是否已废弃;若仍需要,补齐实现或至少在文档中明确为未实现并返回错误码。
  • 在注释中明确接口未启用,保留空实现

7. 其他逻辑与健壮性

BUG-32 [P2] 凝聚内层循环没有跳过已标记使用的点

  • 位置:dot_coh.cpp:25,148dot_coh_tas.cpp:25
  • 说明:内层只检查当前基准点 loop_of_pointUse_Flag,没有检查被比较点 iUse_Flag。已被凝聚掉的点仍可参与后续比较,甚至反过来把高幅度基准点标记掉。
  • 建议:内层同样判断 (*data_input)[i].Use_Flag != 1(以及 data_tmp[i])。
  • 按建议修改

BUG-33 [P2] 起批/临时航迹关联未校验 delta_T > 0,重复时间戳可能产生非法卡尔曼初始化

  • 位置:track_init.cpp:189,381,450track_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-695track_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=0Range/Azi/Elev/type/TAS_track_index 保留上一拍内容。主程序若只按 open_flag 判断则无问题,但字段语义不清晰。
  • 建议:关闭时同时清零 type/Range/Azi/Elev/TAS_track_index
  • 暂不修改

BUG-37 [P3] 部分结构体局部变量未完整初始化

  • 位置:track_init.cpp:80,598track_init_direct_tracking.cpp:325
  • 说明:Temp_track temp_track_tmpTrust_Track trust_track_tmpP 矩阵等字段未显式初始化。当前流程部分字段未被读取,但依赖调用顺序;后续维护容易读到垃圾值。
  • 建议:使用值初始化 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.cpptrack_init_direct_tracking.cpp 当前未加入 CMake 构建(与旧 .pro 一致),其中问题与主流程同类问题重复,修复主流程时可同步修改或暂缓。