# 雷达数据处理流程与关键逻辑说明
> 适用对象:本仓库 `data_process_class_dll`(X256 雷达数据处理动态链接库)
---
## 0. 一页速览
| 环节 | 输入 | 处理 | 输出 |
|---|---|---|---|
| ① 前处理 | 一帧原始点迹(TWS 或 TAS) | 单位换算、缓存、判圈 | 处理模式码 0/1/2/3 |
| ② 调度 | 模式码 | 分流到 TWS / TAS 通道 | — |
| ③ 凝聚 | 单 CPI 或相邻两 CPI 点迹 | 同类点合并(保幅度大者) | 凝聚点迹表 |
| ④ 关联 | 凝聚点迹 + 已有航迹 | IMM 交互 → 波门筛选 → 最近邻一对一 → EKF 更新 | 更新航迹 + 剩余点迹 |
| ⑤ 起始 | 剩余(未关联)点迹 | 逻辑法:航迹头 → 2 点 → ≥3 点 → 起批 | 新可靠航迹 |
| ⑥ 外推/消亡 | 未关联航迹 | 按数据率预测一帧;超限则消亡 | 补点航迹 / 消亡批号 |
| ⑦ 波束控制 | TAS 队列 + 航迹 | 数据率门控 + 队列调度 → 位置外推 | 跟踪波束指令 |
**贯穿全流程的三条主线**
1. **时间主线**:所有时间戳为 64 位毫秒(CPI/GNSS),参与运算时除 1000 转秒;ΔT = 点迹时间 − 航迹时间,ΔT 的正负决定"有效更新 / 只消费不更新 / 跳过"。
2. **状态主线**:每条可靠航迹维护一套 IMM(3 个 Singer 模型)状态 [x, vx, ax, y, vy, ay],x/y 两轴解耦,量测为「距离-方位-径向速度」三维 EKF。
3. **生命周期主线**:可靠航迹靠"外推轮数"消亡;临时航迹靠"缓存圈数 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 == 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:无效数据,丢弃"]
```
**要点**
- 判圈条件由"波位号由大变小"改为 **波位号为 0**(7d5a56f),避免机扫转台反转时误判一圈完成(代码中保留了旧判断的注释)。
- 波位号 0 是每圈的起始波位,因此**每圈恰好触发一次 model=1**。
- 清空(`track_clear_all`)后圈状态复位,下一次调用必然判为"满一圈"。
- 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{"波门判定
距离分段 + 距离门限 d_r + 俯仰门限 d_p"}
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)按数据率外推"]
M --> N["输出全部航迹(更新行 + 补点行)"]
```
### 4.2 波门(三步都通过才算候选)
**(1)统计距离波门**——按航迹距离分段收紧高机动模型:
| 航迹距离 r_track | 模型 1 / 2 | 模型 3 |
|---|---|---|
| ≤ 500 m | d² < 9 | d² < 9/1000(≈ 关闭,抑制近程高机动模型的乱关联) |
| 500 ~ 1000 m | d² < 9 | d² < 9/100(收紧) |
| ≥ 1000 m | d² < 9 | d² < 9 |
> ⚠ **门限语义**:代码里 d 已经是马氏距离平方,判据又写作 `d*d < 9`,等效于 **d < 3**(约对应 3 自由度卡方分布 95% 分位的量级)。调整 ASSO_THORD 时务必记住这一层"二次方"。
**(2)距离门限 d_r**——抑制远距离突跳。用航迹-点迹弦距 R 与航迹位移 VT = v_track·ΔT 判断:
```
VT < 100 且 R > 300 → 拒绝(慢速目标不允许 300 m 以上的跳变)
100 ≤ VT ≤ 300 且 R/VT > 3 → 拒绝(允许的跳变与速度位移成比例)
VT > 300 且 R > 1200 → 拒绝(高速目标给固定 1200 m 上限)
```
**(3)俯仰门限 d_p**:分距离段 7°/5°/10° 的逻辑当前被注释停用,**恒为通过**。
### 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、俯仰波位、十字星数据刷新;
5. **高度维平滑**(见 4.6);
6. `Extrapolate_round = 0`、`point_flag = 1`、`associate_point_number += 1`。
### 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 被消费的情形):
- 推算步长取运行时数据率:`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`(输出为补点/虚点)。
---
## 5. IMM + EKF 关键逻辑
### 5.1 IMM 框架
```mermaid
flowchart LR
A["上一拍三模型状态/协方差 + 模型概率 u"] --> B["交互 mix:算归一化常数 c̄j 与混合概率"]
B --> C["得到三个混合初值 X0j / P0j"]
C --> D["各子模型独立预测(Singer F 和 Qj)"]
D --> E["各子模型 EKF 量测更新 → 新息协方差 Sj、马氏距离 dj"]
E --> F["似然 Λj = N(dj; 0, Sj),模型概率 μj' ∝ Λj·c̄j"]
F --> G["融合输出:X̂ = Σμj'X̂j
P = Σμj'[Pj + (X̂j−X̂)(X̂j−X̂)ᵀ]"]
```
- 状态布局 `[x, vx, ax, y, vy, ay]`,x/y 两轴解耦;
- 模型转移概率矩阵固定:
```
Pt = [ 0.8 0.15 0.05
0.3 0.4 0.3
0.05 0.15 0.8 ]
```
- 机动相关时间常数 α = 0.2;
- 数值保护:归一化常数 c̄j ≤ 1e-12 时钳位;似然分母(det S)≤ 1e-12 时该模型似然置 0;概率分母异常时**保持上一拍模型概率**;EKF 似然用 3×3 新息协方差(保证与量测维数一致)。
### 5.2 三个 Singer 模型的过程噪声强度分档
按航迹速度 v_track 切换 q 值(模型 1 恒用 slow):
| 模型 | TWS 通道 | TAS 通道 |
|---|---|---|
| 模型 1(低机动) | `Model1_Q_slow`(恒定) | 同左 |
| 模型 2(中机动) | v≤5:slow/20;530:fast | v≤5:slow/20;50100:10·fast | v≤5:slow/20;50 语义:低速目标按"低机动"处理(把中/高机动模型噪声压到极小,避免噪声被当成机动),速度越高逐步放大高机动模型的过程噪声。`Model1_Q_fast` 字段不参与计算。
### 5.3 量测与残差修正(EKF)
量测向量 Z = [r, θ, v_r],量测函数由预测状态给出:
```
h(X) = [ √(x²+y²), atan2(y,x) 归一化到 [0,2π), −(x·vx + y·vy)/√(x²+y²) ]
```
在预测点处线性化得到雅可比 H(3×6),量测噪声 R = diag(σr², σa², σv²)(10 m / 0.02 rad / 2 m/s),S = H·P·Hᵀ + R。
**两处残差修正(关键)**
1. **方位环绕**:νθ 归一到 [−π, π),避免 0°/360° 附近的假大残差;
2. **多普勒盲速折叠**:`νv ← νv − round(νv / v_bind) · v_bind`,其中
```
v_bind = 150000 / (f_GHz · PRI_µs), f_GHz = 9.2 + 0.02 · 频点号
```
PRI ≤ 0 或频率非法时返回安全值 1.0(接口约定 PRI 单位 µs 且不允许为 0)。
判据(关联)与模型似然共用同一个 `d = νᵀS⁻¹ν`,且滤波函数把 3×3 新息协方差 S 一并回传给似然使用。
### 5.4 航迹初始化
| 场景 | 维数 | 做法 |
|---|---|---|
| 两点(航迹头 + 1 点,临时航迹) | 4 维 [x, vx, y, vy] | 位置取末点,速度取两点差分;协方差按 Z1 处的**转换量测协方差** R 填充,速度项按 R/T、2R/T² 传播 |
| 三点(起批,可靠航迹) | 6 维 | 位置取末点、速度取末两点差分、加速度取两段速度差分;协方差按 R0/R1/R2 误差传播构造 |
| 起批时 IMM 初始化 | — | 三个子模型用同一状态/协方差,模型概率 u = [1/3, 1/3, 1/3] |
**转换量测协方差**(极坐标量测转直角坐标时的等效噪声,含方位非线性引起的附加项,由 σr=10 m、σa=0.02 rad 决定)用于上述初始化与临时航迹统计距离计算。
> 约束:两点/三点初始化对时间差 T 无除零保护,因此**起批路径要求时间戳严格递增、不允许重复**。
---
## 6. 航迹起始(逻辑法)
### 6.1 状态机
```mermaid
flowchart TD
A["本圈未被可靠航迹关联的点迹"] --> B["全部转成'航迹头'(1 点,buff_round=1)"]
B --> C{"下一圈的点迹"}
C --> D["点-航迹头关联(两点起始)
速度区间 + 多普勒一致性"]
D -->|命中| E["两点卡尔曼初始化 → 2 点临时航迹"]
D -->|未命中| B
E --> F{"后续圈的点迹"}
F --> G["点-临时航迹关联(三点及以上)
EKF 统计距离 + 折角 + 多普勒同号"]
G -->|命中| H["航迹延长(复制原航迹 + 追加新点)"]
G -->|未命中| F
H --> I{"长度 ≥ 起批点数
且不在起批屏蔽区?"}
I -- 是 --> J["同源去重(保留末点 d 更小者)"]
J --> K["三点卡尔曼初始化 → 分配航迹号 1~500
IMM 三模型同状态,u=1/3"]
K --> L["输出该航迹的历史点(前 N 个点)"]
I -- 否 --> F
F --> M{"末点 buff_round > 2
或长度 ≥ 10 ?"}
M -- 是 --> N["临时航迹消亡(不对外输出)"]
```
### 6.2 关联判据汇总
**阶段一:点 ↔ 航迹头(两点起始)**
用航迹头位置与点迹的平面距离 `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),**实际不做距离分段**。
**阶段二:点 ↔ ≥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 ≤ 8。
### 6.3 临时航迹的"圈数"生命周期
`buff_round` 只在起始流程里自增,并且**每次调用(= 每圈)先把所有临时航迹所有点的 buff_round +1,再做关联**:
| 动作 | 效果 |
|---|---|
| 新点加入 | buff_round = 1 |
| 关联资格 | 只看**末点**,要求 buff_round ≥ 2 → **上一圈加入的点本圈才能被延续**,同一航迹每圈最多吸收一个点 |
| 消亡条件 | 末点 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 圈;生命周期完全由"圈数"驱动,与绝对时间无关。
### 6.4 航迹分裂与去重
- 关联阶段**不做一对一分配**:一个点满足多条临时航迹条件时,每条都各自复制出一条新航迹;多条点命中同一条航迹时也各自复制 → 同一圈会产生大量同源临时航迹;
- 起批前做**同源去重**:比较两条候选航迹的**前三个点**,只要有任一点的"时间 T + 距离 r"完全相同即判为同源,保留末点统计距离 d 更小者;
- 这样既保证不漏关联(允许分裂试探),又不会让同一批点重复起批。
### 6.5 起批与输出
| 条件 | 说明 |
|---|---|
| 长度 | `track_start_point_num ≤ L ≤ 10`(接口层校验 3~9,典型 3 或 4) |
| 位置 | 末点不落在**起批屏蔽区**(距离-方位矩形,最多 30 个,用严格不等号判断) |
| 容量 | 可靠航迹数 < 500 且能分配到一个未占用航迹号 |
| 初始化 | 用**最后三个点**做三点卡尔曼初始化 → 6 维状态;三模型同状态、u=1/3 |
| 输出 | 该航迹的**前 N 个点**(N = 起批点数)作为历史点一次性输出,每条航迹最多 10 个历史点 |
> 达到长度即当圈起批,没有"连续 M 圈确认"的环节;若被屏蔽区拦住,航迹会继续在临时航迹表里增长,直到离开屏蔽区(此时长度已大于起批点数)或长度达到 10 被判消亡。
---
## 7. 外推、消亡与航迹号管理
### 7.1 消亡条件
| 通道 | 条件(满足其一即消亡) |
|---|---|
| TWS 航迹 | `Track_Mode==0` 且 `Extrapolate_round ≥ 4` |
| TAS 航迹 | `Track_Mode==1` 且 `Extrapolate_round ≥ TRACK_DIE_ROUND_TAS`(相扫 5 / 机扫 96) |
| 手动删除 | `manual_delete_flag == 1`(两种通道通用,由外部删除接口置位) |
消亡时把批号写入消亡输出数组并从航迹表删除;**临时航迹消亡不对外输出**(起批失败的中间态对宿主不可见)。
### 7.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:全满,本候选不起批"]
```
特点:**优先顺序递增分配**(便于人工按批号识别新老),只有走到表尾才回绕复用早期空号。
---
## 8. TAS 通道(model=3)
### 8.1 与 TWS 通道的差异
| 项 | TWS | TAS |
|---|---|---|
| 凝聚 | 相邻两帧滑窗,近程多速度维约束 | 单帧,恒有速度维约束 |
| 处理对象 | 全部可靠航迹 × 全部点 | **仅指定批号**的这一条航迹 × 全部点 |
| 俯仰/高度门限 | 俯仰门限当前恒通过 | **高度门限生效**(按距离分段) |
| ΔT ≤ 0 | 参与选取但只消费点迹、不更新 | **直接跳过该点**(并记告警日志) |
| 外推时间 | 按 work_mode 数据率固定步长 | 按 `最新时间戳 − 航迹时间` |
| 输出 | 全部航迹 | 仅该批号航迹 |
### 8.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² < 9(任一模型)且高度门限通过?"}
F -- 是 --> G["记入候选表"]
F -- 否 --> H["丢弃"]
G --> I["取 d_min 最小的一点"]
I --> J["三模型 EKF 更新 → 概率更新 → 融合
刷新时间/点信息/高度平滑"]
J --> K["输出该批号航迹"]
E --> L{"候选表为空?"}
L -- 是 --> M["按 ΔT = 最新时间戳 − 航迹时间 外推一帧
(ΔT ≤ 0 则跳过)"]
M --> K
```
**高度门限**(|h_航迹 − h_点迹| 上限,按航迹距离分段):
| 航迹距离 | 门限 |
|---|---|
| ≤ 1000 m | 150 m |
| 1000 ~ 2000 m | 200 m |
| 2000 ~ 3000 m | 200 m |
| 3000 ~ 5000 m | 300 m |
| > 5000 m | 不约束 |
**TAS 后续处理**:外推不受 work_mode 数据率约束,而是直接推进到"本帧最新时间戳",保证 TAS 航迹时间与波束调度时刻同步。
---
## 9. TAS 波束控制(外部接口 Beam_Ctrl)
### 9.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 的逻辑(按距离/速度/高度阈值)已全部注释停用,**只支持手动**。
### 9.2 波束输出调度(关键)
```mermaid
flowchart TD
A["遍历 TAS 队列"] --> B["按批号在航迹表中找到该航迹"]
B --> C{"距上次波束输出 > DATA_RATE_TAS 秒
且 最新时间戳 − 航迹时间 > DATA_RATE_TAS 秒?"}
C -- 否 --> A
C -- 是 --> D["在合格目标中选 CPI 时间最早者"]
D --> E["位置外推: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(其余字段保持旧值)"]
```
**要点**
- 门控用**两个条件**:距上次输出的时间、航迹时间与最新时间戳之差都要大于 `DATA_RATE_TAS` 秒(单位是秒,由宿主经参数初始化传入,须为 > 0 的有效值)→ 保证 TAS 目标的数据率**不随 Beam_Ctrl 的调用频率变化**;
- 多目标时选**队列中 CPI 时间最早**的目标,等价于"按最久未更新者优先"的轮转;
- 原来的"每次调用整队循环移位"已停用;
- 俯仰用航迹高度直接算(叠加雷达平台高度的处理只影响对外输出的 z,不参与波束俯仰)。
---
## 10. 参数脉络(决定行为的旋钮)
### 10.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` | 3 | 同左 | 关联波门(d² < 9,等效 d < 3) |
| `TRACK_DIE_ROUND` | 4 | 4 | TWS 消亡外推轮数 |
| `TRACK_DIE_ROUND_TAS` | 5 | 96 | TAS 消亡外推轮数 |
| `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` | — | — | 日志落盘开关与目录 |
### 10.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` 三个字段**当前未被实现读取**,实际门限来自编译期宏。
---
## 11. 关键约定与注意事项
**时序与时间戳**
- 时间戳为 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 组数组定义,配置数量未做上限校验;
- 高度平滑缓存只增不减,长时运行下每条航迹的内存占用会持续增长。
**未启用**
- 引导跟踪(direct tracking)、手动打跟踪波束接口为空实现;
- TAS 自动开启/退出逻辑停用,只支持手动转/停 TAS;
- `tracking_stop` 后,队列项要等到下一次 `Beam_Ctrl` 才真正移除。
---
## 附录:与现有 `README.md` 的差异提示
现有 README 的 7.2 / 8.3 / 9.3 节**滞后于当前源码**,落地实现以本文为准:
| 项 | README 描述 | 当前源码 |
|---|---|---|
| 满圈判据 | 当前方位波位号 < 上一帧波位号 | **方位波位号 == 0**(7d5a56f,适应机扫转台反转) |
| 点-航迹头判据 | 按距离分段收紧速度门限(半速、1/2~1/3 速) | 该分支注释停用;改为统一速度区间 **+ 两条多普勒-几何一致性约束**(7d5a56f) |
| 起始输出历史点 | "临时航迹的全部 L 个点" | 实际输出**前 `track_start_point_num` 个点** |
| 起始输入过滤 | "track_init 跳过 Use_Flag==1 的点" | 上游关联已删除已用点,起始流程内部不再按 Use_Flag 过滤输入 |
| 日志开关 | "RDP_LOG_ENABLE 默认开启" | `parameters.h` 中该宏当前为**注释状态**(不落盘,日志进控制台) |
> 建议:README 与 `track_init_readme.md`(航迹起始专项说明,内容与当前源码一致)可择机对齐到本文的流程描述。