☰
多目标跟踪数据关联:NNDA、PDA、JPDA与IMM的MATLAB实现对比
2026/11/5 4:13:25 网站建设 项目流程

简介:面向雷达、传感器网络与多目标跟踪学习者的MATLAB算法实现包,聚焦NNDA、PDA、JPDA与IMM四类数据关联方法的代码复现与仿真验证。rar压缩包共7个文件,均为.m脚本,整体约16KB,涵盖最近邻关联、概率数据关联、联合概率数据关联及交互多模型测试等模块,便于在MATLAB中直接运行、对照状态估计与观测模型。内容可用于理解几何距离关联、贝叶斯关联概率更新、多目标联合处理以及多运动模型动态切换的基本流程,并通过仿真测试观察不同噪声、目标接近或机动场景下的跟踪表现。已有2334人学习下载,适合信号处理、目标跟踪课程学习者及需要快速搭建算法验证框架的工程师参考,可在现有代码基础上调整参数、扩展滤波器设计并开展性能对比。

1. 从航迹交叉说起:NNDA、PDA、JPDA、IMM 到底解决哪一层问题

两架目标在屏幕上交叉的那几秒,量测点糊成一团,最近邻一交叠就互换标签,这是多目标跟踪里最典型的翻车现场——问题不在滤波器,在数据关联。这套 MATLAB 代码把 NNDA、PDA、JPDA 三种关联算法和 IMM 交互式多模型放在同一套框架里,用同一份仿真场景做横向对比:NNDA 做硬判决、PDA 在杂波里做概率加权、JPDA 处理多目标联合关联、IMM 负责机动段的多模型切换。

适合正在做雷达或光电跟踪方向课题、需要复现关联算法效果、或者要把关联模块嵌进自己工程里做二次开发的开发者。代码是纯 MATLAB 实现,不依赖额外工具箱,跑起来对照真值图就能判断关联到底有没有做对,而不是只看轨迹画得好不好看。

2. 工程结构:四种关联算法如何共用一套主循环

拿到一个算法包,我一般先不看算法本体,先看主循环和目录划分。因为关联算法的对错往往不取决于公式,而取决于「预测什么时候做、关联结果怎么回写、航迹管理什么时候介入」这三件事的顺序。这个包里四种算法能互换,靠的就是主循环把这三步拆得很干净。

2.1 目录划分与函数职责

典型的目录长这样,函数按职责分层,assoc/下面一个算法一个文件,互不调用:

tracking_demo/ ├── main.m 主脚本:场景生成、循环调度、结果绘图 ├── config/ │ └── cfg_default.m 所有参数集中在这里,不散落在各函数里 ├── scenario/ │ ├── gen_truth.m 真值航迹生成(CV / CA / 转弯段拼接) │ └── gen_measurement.m 量测生成:加噪、漏检、杂波 ├── assoc/ │ ├── gate_mahalanobis.m 马氏距离波门,三种算法共用 │ ├── assoc_nnda.m 最近邻 │ ├── assoc_pda.m 概率数据关联 │ └── assoc_jpda.m 联合概率数据关联 ├── filter/ │ ├── kf_predict.m 状态预测 │ └── kf_update.m 状态更新(含似然输出,给 IMM 用) ├── imm/ │ ├── imm_init.m 模型集初始化 │ └── imm_step.m 混合、条件滤波、概率更新、融合 └── utils/ ├── track_manage.m 航迹起始、维持、删除 └── plot_result.m 真值/量测/估计叠图
目录职责改动频率
config/参数与场景开关高,调参都在这
scenario/仿真数据生成低,换场景时才动
assoc/关联算法中,换算法或加新算法
filter/预测与更新低,除非换滤波器
imm/多模型交互低,模型集变化时动
utils/航迹管理与绘图中,航迹逻辑常调

这样分层的好处是:想对比 NNDA 和 JPDA 的关联正确率,只改cfg.assoc_type一个字段,场景、滤波器、评价脚本全都不用动。血泪经验是,很多人写算法验证脚本时把参数硬编码在各函数里,跑第二组对比实验时改漏一处,结果两组数据根本不可比。

2.2 主循环:从真值到航迹更新的调用链

主循环是全包的骨架,读懂了它,后面每个函数都只是插件:

% main.m 主循环骨架 cfg = cfg_default(); % 参数集中加载 truth = gen_truth(cfg); % 真值,cell{T},每帧 ny x Nt meas = gen_measurement(truth, cfg); % 量测,cell{T},每帧 [x;y] x M tracks = struct('id', {}, 'x', {}, 'P', {}, 'hit', {}, 'miss', {}); for k = 1:cfg.T Z = meas{k}; % 当前帧量测,2 x M % 步骤 1:所有航迹先预测到当前时刻 for i = 1:numel(tracks) [tracks(i).x, tracks(i).P] = kf_predict(tracks(i).x, tracks(i).P, ... cfg.F, cfg.Q); end % 步骤 2:按配置选关联算法,输出「航迹-量测」配对 switch cfg.assoc_type case 'nnda', [pairs, beta] = assoc_nnda(tracks, Z, cfg); case 'pda', [pairs, beta] = assoc_pda(tracks, Z, cfg); case 'jpda', [pairs, beta] = assoc_jpda(tracks, Z, cfg); end % 步骤 3:按配对结果更新状态,PDA/JPDA 用加权新息 tracks = apply_update(tracks, pairs, beta, Z, cfg); % 步骤 4:航迹管理,先更新命中/丢失计数,再起始或删除 tracks = track_manage(tracks, Z, cfg); % 步骤 5:记录本帧结果,供后面算 RMSE 和关联正确率 log{k} = tracks; end

逻辑说明:预测必须在关联之前,因为波门是以预测位置和新息协方差为基准算的;如果先关联再预测,用的就是上一帧的协方差,门限会偏大,杂波容易混进来。apply_update是个薄封装,对 NNDA 是直接把配对的量测丢进kf_update,对 PDA/JPDA 则是先算组合新息再更新,这样三种算法在主循环里长得一样。

参数说明:cfg.F是状态转移矩阵,二维 CV 模型下是 4×4;cfg.Q是过程噪声协方差,它直接决定波门大小,Q给大了门限宽、给小了漏关联,是调参时第一个该动的量;cfg.T是总帧数,一般设 100 到 200 帧就能看出交叉场景下的关联差异。

2.3 公共数据结构:状态、协方差与航迹表

四种算法共用同一套结构体,字段不多但每个都有用:

字段维度含义谁在改
x4×1[px; py; vx; vy]预测与更新
P4×4状态协方差预测与更新
id1×1航迹编号,用于算标签正确率起始时分配
hit1×1连续关联成功帧数航迹管理
miss1×1连续丢失帧数航迹管理
model_p3×1IMM 三个模型的概率IMM 步

量测用 cell 存而不是矩阵,原因是每帧的杂波数量不一样,M 是变的。Z统一成 2×M 的数值矩阵,列是[x; y],这样gate_mahalanobis里一句Z - H*x_pred就能广播出所有新息,不用写循环。新手容易在这里踩坑:把量测存成结构体数组,结果每次算马氏距离都要cell2mat,几十帧跑下来慢得离谱。其实真正拖慢速度的往往不是算法本身,是这些数据搬运。

3. NNDA 与 PDA:波门内的硬选择与软加权

这两种算法解决的是同一类问题——单航迹面对多个候选量测时怎么取。区别只在「取一个」还是「按概率摊到所有点上」。代码里它们共用一个波门函数,差异集中在关联概率那十几行。

3.1 波门与马氏距离:关联前的第一道筛子

波门不是可选项,它是把无穷多的杂波先砍掉九成的过滤器。用马氏距离而不是欧氏距离,是因为各方向上的预测不确定度不一样,椭圆门比圆门更贴合实际:

function [in_gate, d2] = gate_mahalanobis(x_pred, P_pred, Z, H, R, gate_thr) % 输入: % x_pred, P_pred 航迹的预测状态与协方差 % Z 当前帧量测,ny x M % H, R 观测矩阵与观测噪声协方差 % gate_thr 卡方门限,2 维量测 99% 置信对应 9.21 % 输出: % in_gate 1 x M 逻辑向量,true 表示落在门内 % d2 1 x M 马氏距离平方 S = H * P_pred * H' + R; % 新息协方差,反映预测的不确定度 Sinv = inv(S); nu = Z - H * x_pred; % 新息,ny x M d2 = sum(nu .* (Sinv * nu), 1); in_gate = d2 < gate_thr; end

逻辑说明:S由两部分组成——预测协方差投影到观测空间的部分,加上观测噪声。目标机动越剧烈,P_pred越大,S越大,门就越宽,这是自适应的。d2是按列算的,nu .* (Sinv*nu)里Sinv*nu是 ny×M,逐元素乘nu再按列求和,正好得到每个量测的马氏距离平方,半天写不对的话,多半是矩阵维度搞反了。

参数说明:gate_thr在二维量测下,90% 对应 4.61,95% 对应 5.99,99% 对应 9.21。工程上我一般先用 9.21,等确认关联逻辑没问题再往下压到 5.99,压得太狠会出现目标机动时整帧无量测进门的现象。

3.2 NNDA:取最小统计距离的那一个点

NNDA 最简单,也最容易出问题,因为它隐含假设「门内最近的那个点一定是目标的」:

function [assign, d2_all] = assoc_nnda(tracks, Z, cfg) % 每条航迹独立挑选波门内统计距离最小的量测 nT = numel(tracks); nM = size(Z, 2); assign = zeros(nT, 1); % 0 表示该航迹本帧无关联 d2_all = inf(nT, nM); for i = 1:nT [in_gate, d2] = gate_mahalanobis(tracks(i).x, tracks(i).P, ... Z, cfg.H, cfg.R, cfg.gate_thr); d2(~in_gate) = inf; % 门外的直接判死刑 [dmin, j] = min(d2); if isfinite(dmin) assign(i) = j; % 记录量测列号 end end end

逻辑说明:这段代码只解决「每条航迹各自挑谁」,没有解决「两条航迹挑中同一个量测怎么办」。真实的 NNDA 实现里必须加一层冲突消解,最简单的做法是全局贪心:把所有(航迹, 量测, 距离)三元组按距离升序排,依次分配,已被占用的量测跳过。不加这一步,交叉场景下两条航迹会一起扑向中间那个点,然后状态被拉飞,画出来的轨迹会有个明显的尖刺。

参数说明:assign的长度等于航迹数,值域是[0, nM],0 是「本帧没关联上」,航迹管理会据此累加miss。d2_all保留下来是为了画关联距离直方图,如果某个航迹的关联距离长期贴着门限,说明Q给得太乐观了。

3.3 PDA:把波门内所有点按概率揉成一个等效新息

PDA 的核心是把「到底哪个点是真的」这个离散问题变成加权求和:

function [x_upd, P_upd, beta] = assoc_pda(x_pred, P_pred, Z, cfg) H = cfg.H; R = cfg.R; S = H * P_pred * H' + R; Sinv = inv(S); nu = Z - H * x_pred; d2 = sum(nu .* (Sinv * nu), 1); in_gate = d2 < cfg.gate_thr; nu = nu(:, in_gate); d2 = d2(in_gate); m = size(nu, 2); % 杂波项:把「没有一个是真目标」这种情况也纳入分母 b = cfg.lambda * (2*pi)^(size(H,1)/2) * sqrt(det(S)) * ... (1 - cfg.Pd) / cfg.Pd; e = exp(-0.5 * d2); % 每个量测的似然(去掉公共常数) den = b + sum(e); if den <= 0 % 全部门外且杂波项为零,直接退化为预测 beta = zeros(m,1); x_upd = x_pred; P_upd = P_pred; return; end beta = e(:) / den; % 各量测的关联概率 beta0 = b / den; % 无量测关联的概率 nu_c = nu * beta; % 组合新息 K = P_pred * H' * Sinv; x_upd = x_pred + K * nu_c; % 协方差要加「新息扩散项」,否则会低估不确定度 Pc = P_pred - K * H * P_pred; P_spread = K * (nu * diag(beta) * nu' - nu_c * nu_c') * K'; P_upd = beta0 * P_pred + (1 - beta0) * Pc + P_spread; end

逻辑说明:b这一项是 PDA 里最容易被抄漏的。它代表「波门内一个真量测都没有」的似然,由杂波密度lambda、检测概率Pd和新息协方差的行列式共同决定。漏掉它,beta会被强行归一化到量测上,连续漏检时航迹会被杂波拖着走,而且协方差不会膨胀,后面越来越难拉回来。P_spread那一项是血泪教训——很多简化实现只写P_pred - K*H*P_pred,跑几十帧后协方差缩得极小,门限跟着收紧,然后整条航迹就锁死在某个杂波点上了。

参数说明:cfg.lambda是每帧每平方单位的期望杂波数,仿真里按场景面积乘密度算;cfg.Pd一般设 0.9,它同时出现在b和后面 JPDA 的联合事件概率里,两边必须用同一个值,不然对比实验没意义。注意量测维数出现在(2*pi)^(ny/2)里,换三维量测时这里不改会整体偏一个常数,虽然不影响beta的相对大小,但会影响beta0。

3.4 参数整定:检测概率、杂波密度与门限的联动

三个参数不是独立的,动一个另外两个的最优值就变:

参数典型值调大后的效果调小后的效果
Pd0.85 ~ 0.95更信任量测,beta0变小漏检时更依赖预测
lambda1e-4 ~ 1e-2更不信任量测,抗杂波强容易把杂波当真目标
gate_thr5.99 ~ 13.8门内候选变多,PDA 计算量上升机动时容易整帧无量测

我的习惯是先固定gate_thr = 9.21,用 NNDA 跑一遍看关联正确率,再换 PDA 对比;如果 PDA 反而更差,八成是lambda设得太小或Pd设得太高,让杂波项的权重被压没了。

4. JPDA 与 IMM:联合事件枚举和多模型交互怎么落到代码

JPDA 和 IMM 是这套代码里计算量最大的两块,也是新手最容易「跑得动但结果不对」的地方。前者错在事件枚举的边界条件,后者错在转移矩阵的方向。

4.1 确认矩阵:把「谁可能属于谁」写成 0/1 矩阵

JPDA 的第一步不是算概率,是把所有航迹和所有量测的波门关系铺成一张表:

function [Omega, g] = build_confirmation(tracks, Z, cfg) % Omega(i,j)=1 表示量测 j 落在航迹 i 的波门内 nT = numel(tracks); nM = size(Z, 2); Omega = zeros(nT, nM); g = zeros(nT, nM); % 预存似然,避免枚举时重复计算 for i = 1:nT S = cfg.H * tracks(i).P * cfg.H' + cfg.R; Sinv = inv(S); nu = Z - cfg.H * tracks(i).x; d2 = sum(nu .* (Sinv * nu), 1); in = d2 < cfg.gate_thr; Omega(i, in) = 1; g(i, in) = exp(-0.5 * d2(in)) / sqrt(det(2*pi*S)); end end

逻辑说明:g提前算好是关键优化。枚举阶段每个航迹可能被访问几十次,如果每次都重算inv(S)和det(S),跑 5 个目标就慢得不能忍。g里门外的位置保持 0,后面枚举时直接乘,天然把非法关联排除掉。

参数说明:Omega的行是航迹、列是量测,和常见文献里行列反过来写的习惯不同,代码里统一按这个方向,读的时候留意一下,混着看很容易把索引写反。

4.2 联合事件枚举与边缘关联概率

联合事件要满足两个约束:每个量测最多属于一条航迹,每条航迹最多用一个量测。枚举用深度优先,逐航迹决定「不用」还是「用第 j 个还没被占的量测」:

function events = enum_events(Omega) % 输出 events:Ne x nT,每行是一个可行联合事件,0 表示该航迹无关联 nT = size(Omega, 1); events = zeros(0, nT); stack = {zeros(1, nT), 1, false(1, size(Omega,2))}; % 当前分配、航迹号、量测占用 while ~isempty(stack) [cur, i, used] = stack{end}; stack(end) = []; if i > nT events(end+1, :) = cur; %#ok<AGROW> 枚举规模可控时这样写够用 continue; end stack{end+1} = {cur, i+1, used}; % 分支一:该航迹不用量测 for j = find(Omega(i,:) & ~used) nxt = cur; nxt(i) = j; nxt_used = used; nxt_used(j) = true; stack{end+1} = {nxt, i+1, nxt_used}; % 分支二:用第 j 个量测 end end end

assoc_jpda拿到events后算每个事件的联合概率,再按航迹边缘化:

L = zeros(size(events,1), 1); for e = 1:size(events,1) a = events(e,:); p = 1; for i = 1:nT if a(i) == 0 p = p * (1 - cfg.Pd); else p = p * cfg.Pd * g(i, a(i)); end end L(e) = p * cfg.lambda^(nM - nnz(a)) * exp(-cfg.lambda); end L = L / sum(L); % 归一化成事件后验 beta = zeros(nT, nM); for e = 1:size(events,1) a = events(e,:); idx = find(a > 0); beta(sub2ind(size(beta), idx, a(idx))) = ... beta(sub2ind(size(beta), idx, a(idx))) + L(e); end

逻辑说明:L里同时出现Pd和(1-Pd),含义是「关联上的航迹贡献检测概率,没关联上的贡献漏检概率」,杂波项按未分配量测数做幂次。归一化前如果sum(L)是 0 或极小,说明所有事件的概率都下溢了,常见于目标数多、lambda又设得很小的情况。解决办法是在取指数前减最大值,或者干脆对数域算完再exp。

参数说明:枚举规模的上界是(nM+1)^nT,实际受波门稀疏性约束会小很多,但 6 个目标以上仍然可能上万。工程上超过这个量级就该考虑简化 JPDA 或者只保留每个航迹的前 k 个候选量测。

4.3 IMM 四步:混合、条件滤波、概率更新、融合

IMM 的代码骨架不长,但每一步的矩阵方向都不能错:

function [x_est, P_est, mu] = imm_step(models, mu_prev, PI, Z, cfg) nM = numel(models); % 1) 混合:先算预测模型概率 cbar,再算混合权重 mu_mix(j,i) cbar = PI' * mu_prev; mu_mix = zeros(nM); for i = 1:nM mu_mix(:,i) = PI(:,i) .* mu_prev / cbar(i); end x0 = cell(nM,1); P0 = cell(nM,1); for i = 1:nM x0{i} = zeros(size(models{1}.x)); for j = 1:nM, x0{i} = x0{i} + mu_mix(j,i) * models{j}.x; end P0{i} = zeros(size(models{1}.P)); for j = 1:nM dx = models{j}.x - x0{i}; P0{i} = P0{i} + mu_mix(j,i) * (models{j}.P + dx*dx'); end end % 2) 各模型独立预测与更新,记录似然 loglik = zeros(nM,1); for i = 1:nM [xp, Pp] = kf_predict(x0{i}, P0{i}, models{i}.F, models{i}.Q); [models{i}.x, models{i}.P, loglik(i)] = kf_update(xp, Pp, Z, ... models{i}.H, models{i}.R); end % 3) 模型概率更新,减最大值防下溢 lik = exp(loglik - max(loglik)); mu = lik .* cbar; mu = mu / sum(mu); % 4) 加权融合 x_est = zeros(size(models{1}.x)); P_est = zeros(size(models{1}.P)); for i = 1:nM, x_est = x_est + mu(i) * models{i}.x; end for i = 1:nM dx = models{i}.x - x_est; P_est = P_est + mu(i) * (models{i}.P + dx*dx'); end end

逻辑说明:PI是马尔可夫转移矩阵,PI(j,i)表示从模型 j 跳到模型 i 的概率,列和必须为 1。cbar = PI' * mu_prev得到的是混合前的预测模型概率,后面mu = lik .* cbar再归一化才是后验。融合那一步别漏了dx*dx',只加权P会低估总协方差,表现出来就是估计轨迹比真值更「自信」,门限越来越紧。

参数说明:三个模型一般配 CV、CA 和转弯模型,F和Q各自不同;PI对角元 0.95 左右、非对角均分,意味着模型切换不频繁,机动段若切换不及时可以把对角元降到 0.9 试试。

4.4 关联与滤波的耦合顺序:先关联后 IMM 还是反过来

这是个容易被忽略但影响很大的选择。顺序 A 是「先用混合后的预测做关联,把等效新息分发给各模型各自更新」;顺序 B 是「各模型分别关联、分别更新,最后融合」。A 的计算量小,因为只做一次关联;B 更严谨,但每条航迹要做 nM 次关联,JPDA 下开销直接翻三倍。

工程上我一般用 A,代价是波门要用混合后的P来算,混合协方差比单模型大,门限偏宽,杂波多的时候会放进更多候选。如果发现杂波环境下 PDA 的beta0长期偏高,可以考虑改用主模型的S做门限,也就是挑当前概率最大的那个模型来定波门,这算是个折中。

5. 排查清单:航迹跳变、概率下溢与协方差非正定的五类现场

算法跑通不等于跑对。下面这五个现象我基本每次换场景都会撞上一两个,按「现象 → 原因 → 解决」记下来,比盲改参数快得多。

5.1 现象:交叉区两条航迹标签互换

原因:NNDA 各自独立取最近邻,没有全局互斥,交叉时两条航迹同时扑向中间那个量测,谁先更新谁就把它占了,另一条拿到次近的杂波点,一次交换之后再也换不回来。PDA 单独用也有类似问题,因为它对每条航迹独立算beta,不考虑别的航迹。

解决:换成 JPDA,让关联概率在联合事件层面互相排斥;或者保留 NNDA 但加全局贪心分配,把所有(i,j,d2)排序后依次占用。我倾向后者做快速验证,前者做最终方案,因为全局贪心在三个目标以上时仍然会退化。

5.2 现象:连续几帧漏检后,航迹被一个杂波点拽走

原因:PDA 的b项算错或干脆没写,导致beta全部归一到门内量测上,beta0恒为 0。漏检帧里门内只剩杂波,等效新息直接把状态拉过去,协方差还不膨胀。

解决:检查b的表达式里(1-Pd)/Pd有没有漏,以及sqrt(det(S))用的是不是新息协方差;再确认cfg.lambda的单位和场景面积匹配。改完打印beta0的时间序列,正常应该在 0.1 到 0.5 之间波动,恒为 0 就是没生效。

5.3 现象:JPDA 算出的beta全是 NaN,或者某帧突然全是 0

原因:联合事件概率在归一化前全部下溢成 0,0/0出 NaN;或者枚举函数在某个航迹门内没有任何量测时提前返回空事件集,sum(L)为 0。

解决:在L归一化前加一句if sum(L) < eps, beta = zeros(nT,nM); return; end,同时在对数域累加事件概率,最后统一exp并减最大值。另外确认enum_events对「整行全零」的航迹也能正确产生「该航迹不用量测」的分支,不能直接跳过。

5.4 现象:跑几十帧后chol报「矩阵必须为正定」

原因:协方差更新写成P = P - K*H*P的原始形式,浮点误差累积让P失去对称性或出现负特征值;PDA 里漏了P_spread项也会让协方差过度收缩,数值上更容易出问题。

解决:每次更新后强制P = (P + P')/2;预测和更新都用 Joseph 形式P = (I-K*H)*P*(I-K*H)' + K*R*K',数值稳定性好很多。这两句加上之后,我基本没再见过正定性报错。

5.5 现象:IMM 的模型概率锁死在某一个模型上,机动段完全不切换

原因:PI的行列写反了,PI' * mu_prev实际算的是另一个方向,混合权重全跑到一个模型上;或者似然loglik没减最大值,exp后除了最大项全是 0。

解决:检查PI的列和是否为 1,PI(j,i)的下标含义要跟混合公式对得上;在lik = exp(loglik - max(loglik))之后打印mu,正常场景下平稳段主模型概率 0.9 以上,机动开始后 10 帧内应该能看到概率转移,转移不了就是转移矩阵太「粘」,把对角元从 0.98 降到 0.9。

6. 二次开发:换观测方程、扩状态维和验证闭环

这套代码最容易改的地方是观测模型。默认H = [1 0 0 0; 0 1 0 0],量测是笛卡尔位置。如果换成雷达的距离-方位量测,H就不再是线性的,得在kf_predict/kf_update外面包一层 EKF:预测照旧,更新时先算雅可比Hk,再用Hk替换H参与新息协方差和增益计算。改动点集中在filter/和assoc/gate_mahalanobis.m的入参上,关联算法本身不用动,因为它们只依赖「新息、新息协方差、门限」这三样,跟观测是不是线性无关。

状态维扩展是第二个常见需求。从二维 CV 扩到三维,x变成 6×1,F和Q按块对角拼,model_p和航迹管理逻辑一行不用改。真正的坑在P的初始化和Q的量纲:高度方向的過程噪声通常比水平方向小一个量级,Q直接复制水平块会让高度估计抖得厉害,我一般给高度块乘 0.1 作为起点再调。

第三个是验证闭环。只看轨迹图很容易自欺欺人,我的做法是固定随机种子跑 50 次蒙特卡洛,统计三个量:位置 RMSE、航迹标签正确率、以及关联错误帧占比。标签正确率要基于真值与估计的最近邻匹配算,不能靠id直接比,因为航迹起始顺序每次都不一样。这三个指标一起看,能区分「滤波器调得好但关联错了」和「关联对了但滤波器发散」两种完全不同的失败。

最后提一个具体技巧:JPDA 慢的时候,先别急着上并行。把build_confirmation里的inv(S)换成S \ eye(ny),再把枚举里重复的g查表改成预分配数组,通常能快一倍以上,因为这些函数在循环里被调用的次数远超想象。真正需要改算法规模的场景其实不多。

从那以后我每次改关联模块,都强制先用固定种子跑一遍 NNDA 基线、再换算法对比同一份量测,不然改完根本说不清是算法变好了还是随机种子碰巧友好了。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询