# 雷达数据处理流程与关键逻辑说明 > 适用对象:本仓库 `data_process_class_dll`(X256 雷达数据处理动态链接库) --- ## 0. 一页速览 | 环节 | 输入 | 处理 | 输出 | |---|---|---|---| | ① 前处理 | 一帧原始点迹(TWS 或 TAS) | 单位换算、缓存、判圈 | 处理模式码 0/1/2/3 | | ② 调度 | 模式码 | 分流到 TWS / TAS 通道 | — | | ③ 凝聚 | 单 CPI 或相邻两 CPI 点迹 | 同类点合并(保幅度大者) | 凝聚点迹表 | | ④ 关联 | 凝聚点迹 + 已有航迹 | IMM 交互 → 波门筛选 → 最近邻一对一 → EKF 更新 | 更新航迹 + 剩余点迹 | | ⑤ 起始 | 剩余(未关联)点迹 | 逻辑法(每圈顺序固定):点 × ≥2 点临时航迹关联 → 点 × 1 点航迹头关联 → 剩余点转新航迹头 → 达标临时航迹起批 | 新可靠航迹 + 更新后的临时航迹表 | | ⑥ 外推/消亡 | 未关联航迹 | 未到外推上限则按数据率预测一帧并输出,超限只累加轮数、不再预测也不再输出(TWS 上限 3 轮;TAS 判据方向相反,相扫 5 / 机扫 48 轮起才预测) | 本圈有更新的航迹(含补点行)/ 消亡批号 | | ⑦ 波束控制 | TAS 队列 + 航迹 | 数据率门控 + 队列调度 → 位置外推 | 跟踪波束指令 | **贯穿全流程的三条主线** 1. **时间主线**:所有时间戳为 64 位毫秒(CPI/GNSS),参与运算时除 1000 转秒;ΔT = 点迹时间 − 航迹时间,ΔT 的正负决定"有效更新 / 只消费不更新 / 跳过"。 2. **状态主线**:每条可靠航迹维护一套 IMM(3 个 Singer 模型)状态 [x, vx, ax, y, vy, ay],x/y 两轴解耦,量测为「距离-方位-径向速度」三维 EKF。 3. **生命周期主线**:可靠航迹的消亡分两种判据——**TWS 普通航迹自 V1.5.8 起按航迹质量**(`Quality < TRACK_DIE_QUALITY` = 0.3),**重点目标按外推轮数**(判据 `> 10`)、**TAS 按外推轮数**(判据 `> 阈值`:相扫 10 / 机扫 96 圈);临时航迹靠"缓存圈数 buff_round"消亡。 --- ## 1. 总体数据流 ```mermaid flowchart TD IN["宿主逐波位/逐CPI送入 DataRev[150]"] --> DP["data_preprocess 前处理与判圈"] DP -->|"model=2 TWS未满圈"| M2["滑窗凝聚(只凝聚,不关联)"] DP -->|"model=1 TWS满一圈"| M1["TWS 通道"] DP -->|"model=3 TAS数据"| M3["TAS 通道"] M2 --> BUF["本帧凝聚结果留作下一圈缓存"] M2 --> PR["上一帧凝聚点 → point_recv(参与下一圈关联)"] M1 --> A1["IMM 交互 + 波门筛选 + 最近邻关联 + EKF 更新"] A1 --> A2["未关联航迹外推 / 超限消亡"] A2 --> A3["剩余点迹 → 逻辑法起始:点×临时航迹 → 点×航迹头 → 剩余点转航迹头 → 起批"] A3 --> OUT1["输出更新航迹 + 起批航迹历史点 + 消亡批号"] M3 --> B1["TAS 凝聚(单帧)"] B1 --> B2["仅对指定批号航迹做关联/EKF 或外推"] B2 --> B3["TAS 超时消亡"] B3 --> OUT2["输出该批号航迹"] OUT1 --> BC["Beam_Ctrl 波束控制"] OUT2 --> BC BC --> OUT3["TrackingBeam:距离/方位/俯仰/批号"] ``` --- ## 2. 入口前处理与"判圈" ### 2.1 前处理动作 对每一个输入点迹统一做下面几件事(TWS 与 TAS 相同): | 动作 | 说明 | |---|---| | 单位换算 | 方位 度 → 弧度(内部统一弧度,输出再转度) | | 高度折算 | `Height = Range · sin(Elevation)`(由量测俯仰直接折算,不经坐标滤波) | | 字段搬运 | 幅度、SNR、RCS、时间戳、频点号、PRI、俯仰波位、十字星数据(`speed_dim[129]`/`range_dim[8]`)全部透传 | | 使用标记 | 全部置 0(未使用) | | 数量保护 | TWS:`min(Point_Sum, 150)`;TAS:`clamp(Point_Sum, 0, 150)` | | 全局时间 | 每次调用都用本帧首点的 CPI 时间刷新"最新时间戳",供 TAS 外推/波束使用 | ### 2.2 判圈逻辑(决定走哪条通道) ```mermaid flowchart TD A["收到一帧点迹"] --> B{"point_type ?"} B -->|"0 = TWS"| C["写入 TWS 缓存"] C --> D{"判圈条件成立 ?
相扫: Beam_index_aiz <= last_beam_num
机扫: Beam_index_aiz == 0"} D -->|"是"| E["return 1:满一圈,执行 TWS 航迹处理"] D -->|"否"| F["return 2:未满圈,仅做滑窗凝聚"] B -->|"1 = TAS"| G["写入 TAS 缓存
记录 TAS 批号与本帧时间戳"] G --> H["return 3:TAS 处理"] B -->|"其它"| I["return 0:无效数据,丢弃"] ``` **要点** - 判圈条件按扫描体制区分(3e6763c,源码用 `#ifdef PHASE_SCANNING` 编译期隔离): - **相扫**:比较前后两帧方位波位号,当前帧 `Beam_index_aiz <= last_beam_num` 判为满一圈;`last_beam_num` 参与判断,`track_clear_all()` 复位为 INT_MAX,故**清空后/首帧即判满一圈**; - **机扫**:判 **波位号为 0**(7d5a56f 起),避免转台反转时波位号变小导致误判一圈完成(代码中保留了旧判断的注释);该分支下 `last_beam_num` 仍被赋值但不参与判断。 - 机扫下波位号 0 是每圈的起始波位,因此**每圈恰好触发一次 model=1**。 - TAS 数据不参与判圈,**每来一帧就处理一次**(TAS 是调度的跟踪波位,本身就是单目标 CPI)。 ### 2.3 调度:model 与动作的对应 | model | 触发 | 实际执行的动作(顺序固定) | |---|---|---| | 2 | TWS 未满圈 | 两帧滑窗凝聚;缓存本帧点迹 | | 1 | TWS 满一圈 | ① 关联/滤波/外推 ② 航迹消亡 ③ 航迹起始 | | 3 | TAS 帧 | ① TAS 凝聚 ② TAS 关联/外推 ③ TAS 消亡 | | 0 | 非法类型 | 无 | > 顺序很关键:**消散在起始之前**,消亡腾出的资源不会与本圈更新冲突;**起始在最后**,只有"没被任何可靠航迹用掉"的点迹才有资格起批。 --- ## 3. 点迹凝聚 ### 3.1 目的与判据 同一目标在相邻波位/相邻 CPI 上会分裂成多个点,需先合并(保留幅度最大者,其余标记删除)。 | 模式 | 距离门限 | 方位门限 | 速度门限 | |---|---|---|---| | 近程 `work_mode==0` | ≤ 80 m | ≤ 6°(按环绕最小角差) | ≤ 2 m/s | | 中/远程 `work_mode!=0` | ≤ 80 m | ≤ 6° | 不约束 | 方位差按环绕处理: ``` Δθ = min( |θ0 − θ1| , 2π − |θ0 − θ1| ) ``` ### 3.2 合并规则(链式比较) ```mermaid flowchart TD A["两两比较点迹 (0, i)"] --> B{"距离/方位/速度
均在门限内?"} B -- 否 --> Z["跳过"] B -- 是 --> C{"幅度:点0 < 点i ?"} C -- 是 --> D["点0 标记删除
并把点i 的 R/方位/V/幅度
接管为当前基准值"] C -- 否 --> E["点i 标记删除"] D --> F["后续比较以幅度更大者为基准(链式凝聚)"] E --> F F --> G["统一删除:被标记点 + 量程外点
r < 100 m 或 r > 100000 m"] ``` ### 3.3 TWS 两帧滑窗(关键机制) ```mermaid flowchart TD A["上一帧缓存点(区号=1)"] --> C["合并成同一张表"] B["本帧新点(区号=2)"] --> C C --> D["整表凝聚 + 量程过滤"] D --> E{"点的区号"} E -->|"1(较早的点)"| F["输出到 point_recv
→ 本圈参与关联/起始"] E -->|"2(本帧的点)"| G["留在缓存中
→ 与下一帧合并后再输出"] F --> H["缓存清空,本帧剩余点成为新缓存"] ``` **为什么这样设计** - 相邻两个 CPI 的同一目标点会落在不同帧里,单帧凝聚无法合并 → 延迟一帧输出,换取跨 CPI 的分裂点合并; - 代价是关联/起始用的是"上一帧"的点,时间上滞后一圈,但由于后续所有 ΔT 都按真实 CPI 时间戳计算,滤波本身不受影响; - 因此 TWS 通道的正常节奏是:**未满圈 model=2 只做凝聚 + 缓存;满圈 model=1 用上一帧凝聚结果做关联与起始**。 > TAS 凝聚为**单帧**不缓存,门限恒为「距离 ≤ 80 m、方位 ≤ 6°、速度 ≤ 2 m/s」,之后同样做量程过滤。 --- ## 4. TWS 点航关联与滤波(model=1 的核心) ### 4.1 处理骨架 ```mermaid flowchart TD A["全部可靠航迹"] --> A1["IMM 交互(mix)"] A1 --> B["滤波前先统一置 point_flag=0(本圈默认未关联实点)"] B --> C["逐航迹 × 逐点:算 ΔT、三个模型马氏距离 d1/d2/d3"] C --> D{"波门判定
统计距离波门 thd_d + 高度门限 thd_h + 距离门限 thd_r"} D -- 通过 --> E["记入候选表(含 d_min = min(d1,d2,d3))"] D -- 不通过 --> F["丢弃该候选对"] E --> G["最近邻:反复取全表 d_min 最小者"] G --> H["该航迹本圈候选全部移除
该点迹候选全部移除
(一对一)"] H --> I{"ΔT > 0 ?"} I -- 是 --> J["三模型 EKF 更新 → 模型概率更新 → 融合输出
更新航迹时间/点信息/高度平滑
Extrapolate_round=0, point_flag=1"] I -- 否 --> K["不更新状态、不刷新航迹时间
但把该点迹标记为已使用(消费掉)"] J --> L{"还有候选?"} K --> L L -- 有 --> G L -- 无 --> M{"未关联航迹(point_flag==0 且非手动TAS):
Extrapolate_round ≤ MAX_EXTRAPOLATE_NUM ?"} M -- 是 --> M1["按数据率 Singer 预测一帧
推进航迹时间,Track_Update_Flag=1"] M -- 否 --> M2["不预测、不推进时间
仅 Extrapolate_round+1,Track_Update_Flag=0"] M1 --> N["只输出 Track_Update_Flag==1 的航迹行并清零该标志
(其后由 track_init 追加起批历史点)"] M2 --> N ``` ### 4.2 波门(统计距离、高度、距离三类都通过才算候选) **(1)统计距离波门 thd_d**——按航迹距离分段收紧高机动模型(`ASSO_THORD = 4`): | 航迹距离 r_track | 模型 1 / 2 | 模型 3 | |---|---|---| | ≤ 500 m | d² < 16 | d² < 16/1000(≈ 关闭,抑制近程高机动模型的乱关联) | | 500 ~ 1000 m | d² < 16 | d² < 16/100(收紧) | | ≥ 1000 m | d² < 16 | d² < 16 | > ⚠ **门限语义**:代码里 d 已经是马氏距离平方,判据又写作 `d*d < ASSO_THORD*ASSO_THORD`,`ASSO_THORD = 4` 时等效于 **d < 4**(而非 √d < 4)。调整 ASSO_THORD 时务必记住这一层"二次方"(该行为在 BUG-20 中被识别,有意保留)。 **(2)高度门限 thd_h**(e0bf227 起在 TWS 侧生效)——|h_track − h_point| 按航迹距离分段: | 航迹距离 r_track | 高度差门限 | |---|---| | ≤ 1000 m | 150 m | | 1000 ~ 2000 m | 200 m | | 2000 ~ 3000 m | 250 m | | 3000 ~ 5000 m | 300 m | | > 5000 m | 不约束 | > 该门限此前在 `track_asso.cpp` 中整块被注释、`d_h` 恒为 1(等于不生效),现改为独立布尔量 `thd_h` 参与判定,取值与 TAS 通道一致,用于压制俯仰测量跳变引起的错误关联。 **(3)距离门限 thd_r**——抑制远距离突跳。用航迹-点迹弦距 R 与航迹位移 VT = v_track·ΔT 判断: ``` VT < 100 且 R > 300 → 拒绝(慢速目标不允许 300 m 以上的跳变) 100 ≤ VT ≤ 300 且 R/VT > 3 → 拒绝(允许的跳变与速度位移成比例) VT > 300 且 R > 1200 → 拒绝(高速目标给固定 1200 m 上限) ``` **(4)俯仰门限 d_p**:分距离段 7°/5°/10° 的逻辑仍被注释停用,不参与判定(其作用已由高度门限覆盖)。 > 实现要点:三类判据分别算成 `thd_d` / `thd_h` / `thd_r` 三个布尔量,最后以 `thd_d && thd_h && thd_r` 决定是否记入候选表(e0bf227 起;此前三者混写在一个长 `if` 条件里)。 ### 4.3 最近邻(NN)选取规则 - 候选对按 `d_min = min(d1, d2, d3)` 排序,**每轮取全表最小值**; - 选中后,候选表中"该航迹的全部候选"和"该点迹的全部候选"一并删除 → **每条航迹每圈最多关联一个点,每个点最多被一条航迹使用**; - 直到候选表为空或遍历完航迹数。 ### 4.4 ΔT ≤ 0 的特殊处理(当前行为) ΔT = (点迹 CPI 时间 − 航迹 T_track)/1000 ≤ 0,典型场景是"航迹刚被 TAS 点迹更新过,本圈 TWS 点迹时间更早"或"重复时间戳"。 | 环节 | 行为 | |---|---| | 是否参与最近邻比较 | **参与**(仍可能与最小 d 一起被选中) | | IMM/EKF 更新 | **不执行**,X1/X2/X3、P1/P2/P3、模型概率均保持原值 | | 航迹时间/点信息 | **不刷新**(T_track、GNSS_time、关联点信息、幅度/SNR/RCS 都不变) | | 新鲜度标志 | `point_flag` 保持 0、`Extrapolate_round` 不归零、`associate_point_number` 不递增 | | 本圈后续 | 该航迹本圈不再关联其它点迹;由于 point_flag 仍为 0,**在随后的外推环节被推进一帧**(未超外推上限时;超限后只累加轮数、不再预测也不输出该行) | | 点迹归属 | 该点迹被标记"已使用"消费掉 → **不会再进入航迹起始**,避免生成虚假 TWS 航迹 | ### 4.5 关联成功后的更新内容 1. 三个模型的 EKF 状态/协方差更新; 2. 模型概率按新息协方差似然更新(见第 5 节); 3. 航迹时间 T_track / GNSS 时间跟进到该点迹; 4. 关联点信息(距离/方位/俯仰/径向速度/PRI)、幅度、SNR、RCS、归一化幅度 `amp_asv_point`、速度维 FFT 点数 `prn_fftn_point`、俯仰波位、十字星数据刷新; 5. **高度维平滑**(见 4.6); 6. `Extrapolate_round = 0`、`point_flag = 1`、`associate_point_number += 1`、`Track_Update_Flag = 1`(输出门控,见 4.7 末)。 ### 4.6 高度平滑 关联实点后把点迹高度压入滑窗,输出高度取最近 w 个点的均值(不足 w 个则全平均): | 点迹距离 | 窗口长度 w | |---|---| | ≤ 1000 m | 5 | | 1000 ~ 2000 m | 6 | | 2000 ~ 4000 m | 7 | | > 4000 m | 9 | > 距离越远俯仰测量跳变越大,窗口随之放长;仅 TWS/TAS 关联到实点时才刷新,外推补点不改变高度。 ### 4.7 未关联航迹的外推(含外推圈数上限) 对 `point_flag == 0` 且 `manual_tracking_flag == 0` 的航迹(含 ΔT≤0 被消费的情形),按 `Extrapolate_round` 分两支(50e0b5c): **(1)未到上限**:`Extrapolate_round <= MAX_EXTRAPOLATE_NUM`(机扫/相扫均为 3)时照常外推: - 推算步长取运行时数据率:`work_mode` 0/1/2 → `DATA_RATE_SHORT / MIDDLE / FAR`(秒); - 用各子模型的 Singer F、Q 推进一帧(**不做量测更新**); - `T_track`、`GNSS_time` 各推进 ΔT×1000 毫秒; - `Extrapolate_round += 1`,`point_flag = 0`(补点/虚点),`Track_Update_Flag = 1` → 本圈作为补点行输出。 **(2)已超上限**:判据不再成立时**不再做 Singer 预测、不推进航迹时间**,只执行: - `Extrapolate_round += 1`、`point_flag = 0`、`Track_Update_Flag = 0` → 本圈**不输出**该航迹(航迹仍留在航迹表中,等消亡判据命中)。 **输出门控(50e0b5c)**:TWS 输出航迹的循环改为「`Track_Update_Flag == 1` 才输出,输出后清零」,即每圈只输出**本圈关联到实点或成功外推**的航迹;此前是每圈把航迹表中全部可靠航迹各输出一行。门控只判更新标志、不判 `manual_tracking_flag`,因此手动转 TAS 的航迹若本圈在 TWS 侧关联到实点,仍会经 TWS 通道输出。 > **普通 TWS 航迹的消亡改由质量决定(V1.5.8)**:`track_die.cpp` 对 `Track_Mode==0 && primary_target_flag==0` 的航迹改用 `Quality < TRACK_DIE_QUALITY`(0.3)判消亡,因此外推超限后航迹仍会驻留,直到质量衰减到门限以下;`Extrapolate_round` 继续每圈 +1 但不再决定普通 TWS 航迹的存活。重点航迹(10 圈)与 TAS(相扫 10 / 机扫 96)不变。 > > 质量在外推环节按未更新时长二次衰减(`Unupdated_time` 累计,ΔT 由 `work_mode` 数据率决定),且该计算位于外推上限判断之外,故上限内、外都会衰减。 > > **TAS 通道的判据方向相反**(`track_asso_tas.cpp`):`Extrapolate_round >= MAX_EXTRAPOLATE_NUM_TAS` 时才做预测、推进航迹时间并置 `Track_Update_Flag = 1`;未达该轮数时只累加圈数(不预测、不输出)。即 TWS 是"先外推、到上限后停",TAS 是"先不预测、到轮数后才开始外推",详见 7.2 与第 10 节;TAS 不维护航迹质量。 --- ## 5. 航迹起始(逻辑法) ### 5.1 状态机(每圈按 ①→⑤ 的固定顺序执行) ```mermaid flowchart TD A["本圈未被可靠航迹关联的点迹"] --> A0["临时航迹所有点的 buff_round +1"] A0 --> B["① 点 × ≥2 点临时航迹关联(三点及以上)
EKF 统计距离 + 折角 + 多普勒同号
命中 → 复制原航迹 + 追加新点"] B --> C["② 点 × 1 点航迹头关联(两点起始)
速度区间 + 多普勒一致性
命中 → 两点卡尔曼初始化 → 2 点临时航迹"] C --> D["③ 删除 Use_Flag==1 的点迹
剩余点全部转成新航迹头(1 点,buff_round=1)
当圈不再参与关联"] D --> E{"④ 长度 ≥ 起批点数
且 ≤10 且不在起批屏蔽区?"} E -- 是 --> F["同源去重(保留末点 d 更小者)"] F --> G["三点卡尔曼初始化 → 分配航迹号 1~500
IMM 三模型同状态,u=1/3"] G --> H["输出该航迹的历史点(前 N 个点)"] E -- 否 --> I["留在临时航迹表,下一圈继续关联"] H --> J["⑤ 临时航迹消亡(不对外输出)
末点 buff_round > 2 或 长度 ≥ 10"] I --> J ``` **每圈顺序不可颠倒(`track_init.cpp` L49-126)**:点迹**先**做点-临时航迹关联(延长已有 ≥2 点临时航迹),**再**做点-航迹头关联(产生新的 2 点临时航迹),两阶段都结束后才把未被消费的点迹转成新航迹头,最后才把长度达标的临时航迹转可靠航迹,消亡放在最末。由此可得: - 当圈新建的 2 点临时航迹**不可能当圈起批**——长度不足,且新点 `buff_round=1` 要到下一圈才具备关联资格; - 当圈刚被延长到达标长度的临时航迹**可以当圈起批**(第 ④ 步在第 ① 步之后执行); - 两个关联阶段**互不排斥**:都只把命中的点迹标记 `Use_Flag=1`,航迹头阶段不检查临时航迹阶段留下的标记,因此同一点迹可同时延长一条临时航迹、又开启一条 2 点临时航迹,只有走完两阶段后才统一删除被标记的点迹。 > 第 ⑤ 步的消亡判据对**未起批**的临时航迹生效;已起批的航迹在第 ④ 步中已从临时航迹表移除。 ### 5.2 关联判据汇总 每圈按 **① 点-临时航迹关联 → ② 点-航迹头关联** 的顺序依次执行,两阶段的关联判据如下。 **阶段①:点 ↔ ≥2 点临时航迹(三点及以上)** ``` |r_point − r_末点| ≥ 5 m 距离差硬门限(近距点不参与) d ≤ 8(代码写作 d² ≤ TRACK_START_THRESHOLD²=64) 3 维 EKF 统计距离波门 α < ALPHA_START = 60° 折角:最近三点连线夹角 v_r,point · v_r,末点 > 0 多普勒同号 ``` - d 由 4 维 CV 状态一步预测 + 「距离-方位-径向速度」EKF 得到(过程噪声 0.03²、同样做方位环绕与盲速折叠); - 折角 α 为向量 D12(前一点→末点)与 D23(末点→新点)的夹角;α 越小越接近直线; - 门限同样写作 `d² ≤ TRACK_START_THRESHOLD²`,而 d 本身已是马氏距离平方,实际生效为 d ≤ 8(与可靠航迹关联门限的语义一致)。 **阶段②:点 ↔ 航迹头(两点起始)** 用航迹头位置与点迹的平面距离 `dis` 与 ΔT(秒): ``` dis ≤ V_MAX · ΔT 平均速度不超上限 dis ≥ V_MIN · ΔT 平均速度不低于下限(滤除静止/慢速杂波) v_r,point · v_r,head > 0 两点多普勒同号(同接近/同远离) dis ≥ |v_r,point| · ΔT 几何位移不小于"点迹自身多普勒"位移 dis ≥ |v_r,head| · ΔT 同上,用航迹头的多普勒约束 ``` - 后两条是**多普勒-几何一致性**约束,用于剔除"切向高速短航迹"(7d5a56f 新增):切向飞行时真实几何位移大而多普勒径向速度小,纯速度区间门限会放进虚假航迹; - 判据隐含要求 ΔT > 0(ΔT ≤ 0 时 `dis ≤ V_MAX·ΔT` 必然不成立); - 近程/中远程分支当前取值相同(都是 V_MAX),**实际不做距离分段**。 ### 5.3 临时航迹的"圈数"生命周期 `buff_round` 只在起始流程里自增,并且**每次调用(= 每圈)先把所有临时航迹所有点的 buff_round +1,再做关联**;因此关联判据看到的是自增后的圈数,当圈刚建立/刚追加的点(buff_round=1)当圈不可能再被关联: | 动作 | 效果 | |---|---| | 新点加入 | buff_round = 1 | | 关联资格 | 只看**末点**,要求 buff_round ≥ 2 → **上一圈加入的点本圈才能被延续**;同一圈内一条临时航迹可被多个点同时延续(每个点各复制出一条新航迹,见 6.4),并非一对一 | | 消亡条件 | 末点 buff_round > 2(连续 2 圈无新点)或长度 ≥ 10 | **时间轴示例(以第 k 圈加入新点为起点)** ``` 第 k 圈:新点加入 → 末点 buff_round=1(本圈不再关联) 第 k+1 圈:+1 → 2 → 允许关联;成功则新点 1,失败则 2(不 >2,存活) 第 k+2 圈:+1 → 3 → 仍允许关联;成功则新点 1,失败则 3>2 → 消亡 ``` 即:**允许中间空 1 圈**,最大关联间隔 2 圈;生命周期完全由"圈数"驱动,与绝对时间无关。 ### 5.4 航迹分裂与去重 - 关联阶段**不做一对一分配**:一个点满足多条临时航迹条件时,每条都各自复制出一条新航迹;多个点命中同一条临时航迹时也各自复制;点-航迹头阶段同理(一个航迹头可与多个点各生成一条 2 点临时航迹)→ 同一圈会产生大量同源临时航迹; - 两个关联阶段也**互不排斥**:点-航迹头阶段不检查点-临时航迹阶段留下的 `Use_Flag`,同一点迹可同时参与两边的分裂试探; - 起批前做**同源去重**:比较两条候选航迹的**前三个点**,只要有任一点的"时间 T + 距离 r"完全相同即判为同源,保留末点统计距离 d 更小者; - 这样既保证不漏关联(允许分裂试探),又不会让同一批点重复起批。 ### 5.5 起批与输出 | 条件 | 说明 | |---|---| | 长度 | `track_start_point_num ≤ L ≤ 10`(接口层校验 3~9,典型 3 或 4) | | 位置 | 末点不落在**起批屏蔽区**(距离-方位矩形,最多 30 个,用严格不等号判断) | | 容量 | 可靠航迹数 < 500 且能分配到一个未占用航迹号 | | 初始化 | 用**最后三个点**做三点卡尔曼初始化 → 6 维状态;三模型同状态、u=1/3 | | 输出 | 该航迹的**前 N 个点**(N = 起批点数)作为历史点一次性输出,每条航迹最多 10 个历史点 | > 达到长度即当圈起批,没有"连续 M 圈确认"的环节;若被屏蔽区拦住,航迹会继续在临时航迹表里增长,直到离开屏蔽区(此时长度已大于起批点数)或长度达到 10 被判消亡。 --- ## 6. 外推、消亡与航迹号管理 ### 6.1 消亡条件 | 通道 | 条件(满足其一即消亡) | |---|---| | 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_PRIMARY`(10) | | TAS 航迹 | `Track_Mode==1` 且 `Extrapolate_round > TRACK_DIE_ROUND_TAS`(相扫 10 / 机扫 96) | | 手动删除 | `manual_delete_flag == 1`(各通道单独判定,置位即消亡,由外部删除接口 `track_delete` 置位) | 轮数类判据都改为 `die_flag` 组合("或"关系),且比较符由 `>=` 改为 `>`(50e0b5c):即允许的外推圈数比旧版各多 1 圈,且**重点航迹与普通航迹走不同门限**。由于每圈未关联只自增 1,判据为 `>` 时实际是"连续 N+1 圈没有实点关联"才消亡:重点航迹 11 圈、TAS 相扫 11 圈 / 机扫 97 圈。 > **普通 TWS 航迹的消亡时长(V1.5.8)**:改按质量后不再有固定圈数,存活时长由质量衰减速度决定——未关联期间按 `Unupdated_time` 的二次函数加速衰减(见 9.9 / README 9.11),`Quality` 跌破 0.3 即消亡;`TRACK_DIE_ROUND`(6)已不再被引用。 > `primary_target_flag`(重点目标标记)由外部接口 `Data_Process::primary_target_add / primary_target_cancel` 按批号置 1 / 清 0(`data_process.cpp`);新起批航迹在 `track_init.cpp` 中以 `Trust_Track trust_track_tmp = {}` 零初始化,故恒为 0。该标记在 TWS 上决定走「质量消亡(普通)」还是「10 圈消亡(重点)」。 消亡时把批号写入消亡输出数组并从航迹表删除;**临时航迹消亡不对外输出**(起批失败的中间态对宿主不可见)。 ### 6.2 航迹号分配 ```mermaid flowchart TD A["需要起批"] --> B{"航迹表为空?"} B -- 是 --> C["分配 1"] B -- 否 --> D["用航迹表建立 1~500 占用位图"] D --> E["从 lastest_index+1 向上找第一个空闲号(含 500)"] E --> F{"找到?"} F -- 是 --> G["分配并更新 lastest_index"] F -- 否 --> H["从 1 回绕扫一遍找空闲号"] H --> I{"找到?"} I -- 是 --> G I -- 否 --> J["返回 0:全满,本候选不起批"] ``` 特点:**优先顺序递增分配**(便于人工按批号识别新老),只有走到表尾才回绕复用早期空号。 --- ## 7. TAS 通道(model=3) ### 7.1 与 TWS 通道的差异 | 项 | TWS | TAS | |---|---|---| | 凝聚 | 相邻两帧滑窗,近程多速度维约束 | 单帧,恒有速度维约束 | | 处理对象 | 全部可靠航迹 × 全部点 | **仅指定批号**的这一条航迹 × 全部点 | | 俯仰/高度门限 | 俯仰门限已注释停用;**高度门限生效**(按距离分段,e0bf227 起) | **高度门限生效**(按距离分段,取值与 TWS 相同) | | ΔT ≤ 0 | 参与选取但只消费点迹、不更新 | **直接跳过该点**(并记告警日志) | | 外推时间 | 按 work_mode 数据率固定步长 | 按 `最新时间戳 − 航迹时间` | | 外推触发轮数 | `Extrapolate_round <= MAX_EXTRAPOLATE_NUM`(3)才预测 | `Extrapolate_round >= MAX_EXTRAPOLATE_NUM_TAS`(相扫 5 / 机扫 48)才预测(方向与 TWS 相反) | | 输出 | 本圈有更新的航迹(关联到实点或成功外推,输出后清 `Track_Update_Flag`) | 该批号航迹且本圈有更新 | ### 7.2 TAS 关联与更新 ```mermaid flowchart TD A["TAS 本帧点迹 + 指定批号航迹"] --> B{"该批号航迹存在?"} B -- 否 --> Z["直接返回(不做任何处理)"] B -- 是 --> C["IMM 交互;航迹 point_flag 置 0"] C --> D["逐点:ΔT ≤ 0 → 记告警并跳过"] D --> E["逐点:三模型统计距离 d1/d2/d3 + 高度门限"] E --> F{"d² < 16(任一模型)且高度门限通过?"} F -- 是 --> G["记入候选表"] F -- 否 --> H["丢弃"] G --> I["取 d_min 最小的一点"] I --> J["三模型 EKF 更新 → 概率更新 → 融合
刷新时间/点信息/高度平滑"] J --> K["输出该批号航迹(Track_Update_Flag==1 才输出,输出后清零)"] E --> L{"候选表为空?"} L -- 是 --> L1{"Extrapolate_round ≥ MAX_EXTRAPOLATE_NUM_TAS ?"} L1 -- 是 --> M["按 ΔT = 最新时间戳 − 航迹时间 外推一帧
(ΔT ≤ 0 则跳过),Track_Update_Flag=1"] L1 -- 否 --> M2["不预测、不推进时间
仅 Extrapolate_round+1,Track_Update_Flag=0"] M --> K M2 --> K ``` **高度门限**(|h_航迹 − h_点迹| 上限,按航迹距离分段): | 航迹距离 | 门限 | |---|---| | ≤ 1000 m | 150 m | | 1000 ~ 2000 m | 200 m | | 2000 ~ 3000 m | 250 m | | 3000 ~ 5000 m | 300 m | | > 5000 m | 不约束 | **TAS 后续处理**:外推不受 work_mode 数据率约束,而是直接推进到"本帧最新时间戳",保证 TAS 航迹时间与波束调度时刻同步。 **TAS 外推轮数门控(50e0b5c)**:与 TWS **方向相反**——只有 `Extrapolate_round >= MAX_EXTRAPOLATE_NUM_TAS`(相扫 5 / 机扫 48)时才做预测、推进航迹时间并置 `Track_Update_Flag = 1`;未达该轮数时只 `Extrapolate_round += 1`、`point_flag = 0`、`Track_Update_Flag = 0`,既不预测也不输出。因此 TAS 航迹在刚丢失点迹时并不会立刻按"最新时间戳"外推:相扫体制下前 5 次未关联不产生任何输出行,第 6 次起才开始外推输出;机扫体制下前 48 次不输出。该不对称仅如实记录(成因不明,不作缺陷判定),连同 TWS/TAS 输出门控一并见第 10 节。 --- ## 8. TAS 波束控制(外部接口 Beam_Ctrl) ### 8.1 队列管理 ```mermaid flowchart TD A["Beam_Ctrl 调用"] --> B["输出航迹计数清零"] B --> C["入队 tas_target_add"] C --> D["出队 tas_target_del"] D --> E["波束输出 tas_beam_output"] E --> F["输出 TrackingBeam"] ``` **入队条件**(只支持手动转 TAS): - 该航迹 `manual_tracking_flag == 1`(由外部 `tracking_start` 置位); - 航迹当前 `Track_Mode == 0`(还不是 TAS); - 队列未满(相扫最多 4 个 / 机扫最多 1 个); - 不在 TAS 禁止区(距离-方位矩形)。 入队动作:写批号、标记非空、`last_track_time = T_track`、**航迹 Track_Mode 置 1**,并**立即输出一次该航迹更新**(通知宿主跟踪状态变化)。 **出队条件**:队列中的批号在航迹表中已不存在,或不再处于"手动 + TAS"状态 → 清空该队列项。 > 自动开启/退出 TAS 的逻辑(按距离/速度/高度阈值)已全部注释停用,**只支持手动**。 ### 8.2 波束输出调度(关键) ```mermaid flowchart TD A["遍历 TAS 队列"] --> B["按批号在航迹表中找到该航迹"] B --> C{"距上次波束输出 > DATA_RATE_TAS 秒
且 CPI 时间早于已选中的最早 CPI?"} C -- 否 --> A C -- 是 --> D["选中该目标(CPI 时间最早者)"] D --> E["位置外推:ΔT = (最新时间戳 − CPI 时间)/1000
x + vx·ΔT, y + vy·ΔT"] E --> F["Range = √(xp²+yp²),Azi = atan2(yp,xp)
Elev = asin(Height / Range)"] F --> G["open_flag=1, type=1, 批号=真实航迹号
更新该目标 last_track_time = 最新时间戳"] C -.->|"无任何合格目标"| H["open_flag = 0(其余字段保持旧值)"] ``` **要点** - 门控只用一个条件(e0bf227 修正):目标「距上次波束输出的时间」(`latest_timestamp − last_track_time`)要大于 `DATA_RATE_TAS` 秒(单位是秒,由宿主经参数初始化传入,须为 > 0 的有效值)→ 保证 TAS 目标的数据率**不随 Beam_Ctrl 的调用频率变化**;修正前还要求「航迹时间与最新时间戳之差」也大于该门限,与"取最早 CPI 目标"的语义冲突,会漏掉本应输出的波束; - 多目标时选**队列中 CPI 时间最早**的目标(同时要求其 CPI 时间早于当前已选者),等价于"按最久未更新者优先"的轮转; - 选中后才按该目标的 CPI 时间算外推步长 `ΔT = (最新时间戳 − CPI 时间)/1000`; - 原来的"每次调用整队循环移位"已停用; - 俯仰用航迹高度直接算(叠加雷达平台高度的处理只影响对外输出的 z,不参与波束俯仰)。 --- ## 9. 参数脉络(决定行为的旋钮) ### 9.1 编译期宏(随扫描体制切换) | 宏 | 相扫 | 机扫 | 作用点 | |---|---|---|---| | `SIGMA_R / A / E / V` | 10 / 0.02 / 0.2 / 2.0 | 同左 | 量测噪声、EKF 的 R、转换量测协方差 | | `DOT_COH_RANGE / V / AZI` | 80 / 2 / 6 | 同左 | 凝聚门限(距离 m / 速度 m/s / 方位 °) | | `R_MIN / R_MAX` | 100 / 100000 | 同左 | 有效量程(凝聚后过滤) | | `TRACK_START_THRESHOLD` | 8 | 同左 | 起始统计距离波门(d ≤ 8) | | `ALPHA_START` | 60 | 同左 | 起始折角上限(°) | | `ASSO_THORD` | 4 | 同左 | 关联波门(判据 d*d < ASSO_THORD²,d 已是马氏距离平方,等效 d < 4) | | `MAX_EXTRAPOLATE_NUM` | 3 | 同左 | TWS 未关联航迹最大外推轮数(`Extrapolate_round <= 该值` 才预测并输出) | | `MAX_EXTRAPOLATE_NUM_TAS` | 5 | 48 | TAS 未关联航迹开始外推的轮数(判据 `>=`,方向与 TWS 相反) | | `TRACK_DIE_ROUND` | 6 | 6 | **已不被引用**:V1.5.8 起 TWS 普通航迹改按质量消亡(宏保留备用) | | `TRACK_DIE_ROUND_PRIMARY` | 10 | 10 | TWS 重点航迹(`primary_target_flag==1`)消亡轮数 | | `TRACK_DIE_ROUND_TAS` | 10 | 96 | TAS 航迹消亡轮数(判据 `Extrapolate_round > 该值`) | | `TRACK_DIE_QUALITY` | 0.3 | 0.3 | TWS 普通航迹质量消亡门限(`Quality < 该值`;V1.5.8 新增) | | `TRACK_START_QUALITY_L3~L7` | 0.7 / 0.6 / 0.5 / 0.4 / 0.3 | 同左 | 起批最低质量(按临时航迹长度 3/4/5/6/≥7;V1.5.8 新增) | | `TRACK_QUALITY_*` | 见 README 10.1 | 同左 | 质量权重(D/SNR/LEN:0.5/0.3/0.2)、平滑系数 0.8、衰减系数 O2/O1 = −0.0008/−0.0025、折算上限 100(V1.5.8 新增) | | `MAX_TRACK_NUM / MAX_TRACK_INDEX` | 500 / 500 | 同左 | 航迹数上限 / 航迹号上限 | | `TAS_QUEUE_LENGTH / MAX_TAS_NUM` | 4 / 4 | 1 / 1 | TAS 队列长度 / 最大 TAS 目标数 | | `H_F_WIN_LEN` | 3 | 同左 | 高度平滑窗长基数(实际 +2/+3/+4/+6) | | `FREQ0` | 9.2 GHz | 同左 | 盲速计算的基准频率 | | `RDP_LOG_ENABLE / RDP_LOG_DIR` | — | — | 日志落盘开关与目录 | ### 9.2 运行时参数(宿主传入,随任务变化) | 参数 | 影响环节 | |---|---| | `work_mode`(0 近程/1 中程/2 远程) | 凝聚是否带速度维约束;TWS 外推步长;关联距离门限分支 | | `track_start_point_num`(校验 3~9) | 起批所需点数 | | `V_MAX / V_MIN` | 航迹头-点关联的速度区间 | | `DATA_RATE_SHORT / MIDDLE / FAR` | TWS 未关联航迹外推步长(秒) | | `DATA_RATE_TAS`(秒,须 > 0) | TAS 波束输出间隔门控 | | `Height` | 输出 z = 航迹高度 + 平台高度 | | `Sys_delay` | 输出位置做 x + vx·Sys_delay 的系统延迟补偿 | | `Model1/2/3_Q_slow/fast` | 三个 Singer 模型的过程噪声强度(分档见 5.2) | | `track_prohibite_area_*`(≤30 组) | 起批屏蔽区(距离 m + 方位 °) | | `TAS_prohibite_area_*`(≤30 组) | TAS 禁止区 | > `track_start_threshold / track_asso_threshold / track_asso_threshold_tas` 三个字段**当前未被实现读取**,实际门限来自编译期宏。 --- ## 10. 关键约定与注意事项 **时序与时间戳** - 时间戳为 64 位毫秒;`T_track` 输出为秒(`/1000`);所有 ΔT 用秒参与运算; - TWS 关联中 ΔT ≤ 0 的候选"只消费点迹、不更新航迹"(点迹不会再去起批); - TAS 关联中 ΔT ≤ 0 直接跳过该点;TAS 外推 ΔT ≤ 0 跳过本轮; - 两点/三点卡尔曼初始化对 T 无除零保护 → **起批路径的时间戳必须严格递增**。 **量纲与坐标** - 外部接口角度为度,内部统一弧度,输出再度; - 平面坐标为水平投影,z = 目标高度 + 雷达平台高度; - 点高度由 `R·sin(俯仰)` 直接折算,不参与滤波状态(由高度平滑单独维护)。 **门限语义** - 关联与起始的波门写作 `d² < 门限²`,而 d 已是马氏距离平方 → 实际等效 **d < 门限**; - 起始的"距离差 ≥ 5 m"为硬编码,对切向远距离慢速目标可能造成漏关联; - 起批去重只比较**前三个点**,若起批点数 > 3,共享前三点后分叉的两条航迹会被判为同源。 **容量与边界** - 点迹数上限 150(前处理已限幅);航迹数/航迹号上限 500,全满时新目标不再起批; - 屏蔽区/禁止区的组数按 30 组数组定义,配置数量未做上限校验; - 高度平滑缓存只增不减,长时运行下每条航迹的内存占用会持续增长。 **外推、消亡与输出门控(50e0b5c / fc49707 / 42b598e / e8c56f9 / V1.5.8)** - **外推圈数上限**:TWS 只在 `Extrapolate_round <= MAX_EXTRAPOLATE_NUM`(3)时预测并输出;TAS 相反,`Extrapolate_round >= MAX_EXTRAPOLATE_NUM_TAS`(相扫 5 / 机扫 48)时才预测并输出。两处比较方向不一致,此处仅如实记录,**不判定为缺陷**; - **普通 TWS 航迹消亡改按质量(V1.5.8)**:`Quality < TRACK_DIE_QUALITY`(0.3)即消亡,`TRACK_DIE_ROUND`(6)不再被引用;重点航迹仍按 `> TRACK_DIE_ROUND_PRIMARY`(10)、TAS 仍按 `> TRACK_DIE_ROUND_TAS`(相扫 10 / 机扫 96);`manual_delete_flag == 1` 单独判为消亡; - **航迹质量(V1.5.8)**:内部 0~1,临时航迹每延长一点按「距离+SNR」更新、关联实点按「距离+SNR+有效点占比」平滑更新、未关联期间按 `Unupdated_time` 二次衰减;起批需达按长度分级的最低质量;输出 `Track.Quality` 为 0~100(×100)。TAS 通道不维护质量; - **输出门控**:TWS 与 TAS 的输出航迹循环都新增 `Track_Update_Flag == 1` 判定并在输出后清零,只输出**本圈关联到实点或成功外推**的航迹(此前 TWS 每圈把航迹表中全部可靠航迹各输出一行); - **接近/远离判据**(fc49707 + 42b598e):`Flag_Direction` 不再用实测径向速度 `vr_point > 0`(受多普勒速度模糊影响符号可能取反),改为用 IMM 融合速度方向角判定——`Direction_Angle = atan2(X[4], X[1])`(弧度转度后输出到 `Track.Direction_Angle`),`x`、`y` 为经 `Work_Parameter.Sys_delay` 补偿后的位置、`r` 为其模,`acos((-x·cosθ - y·sinθ)/r) < π/2` 判为靠近(1)、否则远离(0),等价于"速度方向与雷达→目标位置方向夹角 > 90°"。中间版本 fc49707 曾写为 `acos((-x·vx - y·vy)/r/Range_V) < π/4`(按合速度归一化、门限 45°),42b598e 改为上式; - **归一化幅度 / 速度维 FFT 点数(e8c56f9 新增,输入侧已打通)**:`DataRev` 新增 `amp_asv`(归一化幅度 dB)、`prn_fftn`(速度维 FFT 点数),`Track`/内部 `PointRecv`/`Trust_Track` 也新增同名成对字段;`data_preprocess()` 现已在 TWS 与 TAS 两条分支都把这两个字段搬入 `PointRecv`(并随 `RdpRecPoint` 落库),因此 `track_asso.cpp` 写入航迹并在 TWS 输出行写回的 `amp_asv_point` / `prn_fftn_point` 有有效数据来源;**TAS 的关联与输出路径(`track_asso_tas.cpp`)仍未涉及这两个字段**,TAS 输出行中它们保持宿主原值。 - **版本号与记录标识(b227ae1 / c3c7e66 / 5cb67cc)**:`parameters.h` 新增版本宏并拼装为 `VERSION_STRING`(当前 `V1.5.8.PS` / `V1.5.8.MS`),实例创建后可由基类公开成员 `version_info` 读取;`Data_Process` 新增 `point_id` / `frame_id` / `circle_id` 自增计数(`circle_id` 在 TWS 每判满一圈、TAS 每帧末自增),`PointRecv`/`Temp_track`/`Trust_Track` 新增对应的标识字段,记录功能据此把「输入点迹 → 凝聚点迹 → 临时航迹 → 可靠航迹 → 关联信息」串成同一条链路;可靠航迹与关联信息的记录点为 TWS/TAS 双通道(关联信息以 `Asso_Info::tas_flag` 区分来源)。 **未启用** - 引导跟踪(direct tracking)、手动打跟踪波束接口为空实现; - TAS 自动开启/退出逻辑停用,只支持手动转/停 TAS; - `tracking_stop` 后,队列项要等到下一次 `Beam_Ctrl` 才真正移除。 --- ## 附录:与现有 `README.md` 的差异提示 > 说明:下表是本文档成文时(README 尚未同步 7d5a56f 改动)发现的差异,保留以说明改动缘由;随后已按下表结论更新 README 第 2、7.2、8.1、8.3、9.3、9.6、10.1 等节,「README 描述」列对应更新前的旧表述,现以本文档与 README 的描述为准。 | 项 | README 描述(更新前) | 当前源码 | |---|---|---| | 满圈判据 | 当前方位波位号 < 上一帧波位号 | 按体制区分(3e6763c):**相扫**当前波位号 ≤ 上一帧波位号(等价于原判据)、**机扫**方位波位号 == 0(7d5a56f,适应机扫转台反转) | | 点-航迹头判据 | 按距离分段收紧速度门限(半速、1/2~1/3 速) | 该分支注释停用;改为统一速度区间 **+ 两条多普勒-几何一致性约束**(7d5a56f) | | 起始输出历史点 | "临时航迹的全部 L 个点" | 实际输出**前 `track_start_point_num` 个点** | | 起始输入过滤 | "track_init 跳过 Use_Flag==1 的点" | 上游 `track_asso_process()` 结束前已把 `Use_Flag==1` 的点迹从 `point_recv` 删除;`track_init` 入口(L59-70)也会再剔除一次 `Use_Flag==1` 的点,两道处理叠加,效果一致 | | 日志开关 | "RDP_LOG_ENABLE 默认开启" | `parameters.h` 中该宏当前为**注释状态**(不落盘,日志进控制台) | | 起始步骤顺序 | "航迹头(1 点)→ 点-航迹头关联(2 点)→ 点-临时航迹关联(≥3 点)→ 起批" | 每圈实际顺序为**点 × ≥2 点临时航迹关联 → 点 × 1 点航迹头关联 → 剩余点转新航迹头 → 长度达标的临时航迹起批**,消亡最后执行(`track_init.cpp` L49-126,见第 6 节) | > 后续:README 与 `track_init_readme.md`(航迹起始专项说明)已按上表结论同步(见 CHANGELOG 对应版本的记录);流程落地实现仍以本文为准。 > > 补充修订(本次):起始流程的**步骤顺序**原先在本文档(第 0、6 节)与 README(第 2、5.2、8.3、9.3 节)中都写作「航迹头 → 2 点 → ≥3 点 → 起批」,与源码每圈「点 × 临时航迹关联 → 点 × 航迹头关联 → 剩余点转航迹头 → 达标者起批」的顺序相反,现已按源码修正,并补充说明两个关联阶段互不排斥、均不做一对一分配。