主要内容

为具有异构源履带的履带熔断器生成代码

这个示例展示了如何在一个场景中为航迹级融合算法生成代码,其中航迹来自具有不同状态定义的异构源。这个例子是基于雷达与激光雷达数据的航迹级融合例如,激光雷达和雷达源产生的轨迹状态空间不同。

为代码生成定义跟踪融合器

您可以为类生成代码trackFuser使用MATLAB®Coder™。为此,您必须修改您的代码以符合以下限制:

代码生成入口函数

按照说明使用系统对象在MATLAB代码生成(MATLAB编码器).对于代码生成,必须首先定义一个入门级函数,在其中定义对象。此外,该函数不能使用对象数组作为输入或输出。在本例中,将入门级函数定义为heterogeneousInputsFuser函数。在为函数生成代码时,该函数必须位于路径上。因此,它不能是这个实时脚本的一部分,并在本示例中附加。该函数接受本地音轨和当前时间作为输入和输出中央音轨。

为了在调用函数之间保持fuser的状态,可以将fuser定义为持续的变量。在第一次调用时,必须定义fuser变量,因为它是空的。下面代码的其余部分执行trackFuser然后返回融合的轨迹。

函数tracks = heterogeneousinputtsfuser (localTracks,time)% # codegen持续的熔化炉如果isempty(熔化炉)%定义雷达源配置radarConfig = fusersourcecconfiguration (“SourceIndex”,1,“IsInitializingCentralTracks”,真的,“CentralToLocalTransformFcn”@central2local,“LocalToCentralTransformFcn”, @local2central);%定义激光雷达源配置lidarConfig = fusersourcecconfiguration ()“SourceIndex”,2,“IsInitializingCentralTracks”,真的,“CentralToLocalTransformFcn”@central2local,“LocalToCentralTransformFcn”, @local2central);创建一个trackFuser对象fuser = trackFuser“MaxNumSources”2,“SourceConfigurations”{radarConfig; lidarConfig},“StateTransitionFcn”@helperctcuboid,“StateTransitionJacobianFcn”@helperctcuboidjac,“ProcessNoise”,diag([1 31 1]),“HasAdditiveProcessNoise”假的,“AssignmentThreshold”, 250年正无穷,“ConfirmationThreshold”[3 - 5],“DeletionThreshold”, 5 [5],“StateFusion”“自定义”“CustomStateFusionFcn”, @helperRadarLidarFusionFcn);结束tracks = fuser(localTracks, time);结束

同构源配置

在本例中,您定义的雷达和激光雷达源配置与原始配置不同雷达与激光雷达数据的航迹级融合的例子。在最初的例子中,CentralToLocalTransformFcnLocalToCentralTransformFcn两个源配置的属性不同,因为它们使用不同的函数句柄。这使得源配置成为异构单元阵列。这样的定义在MATLAB中执行是正确有效的。但是,在代码生成中,所有源配置必须使用相同的函数句柄。为了避免不同的函数句柄,定义一个函数将音轨从中心(fuser)定义转换为本地(源)定义,定义一个函数将音轨从本地转换为中心。这些函数中的每一个都在原始示例中为单个源定义的转换函数之间切换。两个函数都是heterogeneousInputsFuser函数。

的代码local2central函数,它使用SourceIndex属性来确定要使用的正确函数。由于两种类型的局部轨道转换为相同的中央轨道定义,因此无需预先定义中央轨道。

函数中央轨道= local2central(localTrack)开关localTrack。SourceIndex情况下1%的雷达centralTrack = radar2central(localTrack);否则%激光雷达centralTrack = lidar2central(localTrack);结束结束

这个函数central2local将中央航迹转换成雷达航迹SourceIndex我是否进入了激光雷达跟踪SourceIndex是2。由于这两种轨道有不同的定义状态StateCovariance,TrackLogicState,必须首先预定义输出。下面是该函数的代码片段:

函数localTrack = central2local(centralTrack)状态= 0;stateCov = 1;coder.varsize (“状态”, [10,1], [10 0]);coder.varsize (“stateCov”, [10 10], [11 11]);localTrack = objectTrack(“状态”、州、“StateCovariance”, stateCov);开关centralTrack。SourceIndex情况下1 localTrack = central2radar(centralTrack);情况下2 localTrack = central2lidar(centralTrack);否则永远不会到达此分支,但强制执行代码是必需的使用预定义的localTrack。结束结束

的函数radar2centralcentral2radar是否与原始示例相同,但从现场脚本移动到heterogeneousInputsFuser函数。你还可以添加lidar2centralcentral2lidar函数heterogeneousInputsFuser函数。这两个函数将融合器使用的航迹定义转换为激光雷达航迹定义。

在MATLAB中运行示例

在生成代码之前,请确保在对fuser进行了所有更改之后,示例仍在运行。该文件lidarRadarData.mat包含与原始示例相同的场景。它还包含一组雷达和激光雷达跟踪记录在每一步的例子。您还可以使用类似的显示来可视化示例并定义相同的显示trackGOSPAMetric对象来评估跟踪性能。

%加载场景和录制的本地音轨负载(“lidarRadarData.mat”“场景”“localTracksCollection”) display = helperTrackFusionCodegenDisplay(“FollowActorID”3);showLegend(显示、场景);%雷达GOSPAgospaRadar = trackGOSPAMetric(“距离”“自定义”“DistanceFcn”@helperRadarDistance,“CutoffDistance”25);%激光雷达GOSPAtrackgospalidar =“距离”“自定义”“DistanceFcn”@helperLidarDistance,“CutoffDistance”25);%中央/融合GOSPAgospaCentral = trackGOSPAMetric(“距离”“自定义”“DistanceFcn”@helperLidarDistance,%状态空间与激光雷达相同“CutoffDistance”25);Gospa = 0 (3,0);missedTargets = 0 (3,0);falseTracks = 0 (3,0);指标的基本真实值。该变量在每个时间步更新%自动,因为它是actor的句柄。groundTruth = scenario.Actors(2:end);fusersteps = false;fusedTracks = objectTrack.empty;Idx = 1;清晰的heterogeneousInputsFuseradvance(scenario) time = scenario. simulationtime;localTracks = localTracksCollection{idx};如果~isempty(localTracks) || fusersteps fusedTracks = heterogeneousinputtsfuser (localTracks,time);fusersteps = true;结束radarTracks = localTracks([localTracks. sourceindex]==1);lidarTracks = localTracks([localTracks. sourceindex]==2);%捕获所有跟踪器的GOSPA及其组件[gospa(1,idx),~,~,~,missedTargets(1,idx),falseTracks(1,idx)] = gospaRadar(radarTracks, groundTruth);[gospa(2,idx),~,~,~,missedTargets(2,idx),falseTracks(2,idx)] = gospaLidar(lidarTracks, groundTruth);[gospa(3,idx),~,~,~,missedTargets(3,idx),falseTracks(3,idx)] = gospaCentral(fusedTracks, groundTruth);更新显示显示器(radarTracks场景、[][],[],[],[],[], [], lidarTracks, fusedTracks);Idx = Idx + 1;结束

Figure包含了uipanel类型的对象。

为跟踪融合器生成代码

要生成代码,必须为雷达和激光雷达轨迹以及时间戳定义输入类型。在原始脚本和上一节中,雷达和激光雷达轨迹被定义为数组objectTrack对象。在代码生成中,入门级函数不能使用对象数组。相反,您定义了一个结构数组。

使用结构体oneLocalTrack定义来自雷达和激光雷达轨迹的输入。在代码生成中,结构体中每个字段的特定数据类型必须与为录制轨道中的相应属性定义的类型完全相同。此外,必须正确定义每个字段的大小。你可以使用coder.typeof(MATLAB编码器)函数来指定具有可变大小的字段:状态StateCovariance,TrackLogicState.你定义localTracks输入oneLocalTrack结构和coder.typeof函数,因为每一步的输入轨道数从0到8不等。你使用这个函数codegen(MATLAB编码器)来生成代码。

注:

  1. 如果输入轨道使用不同的类型状态StateCovariance属性时,您必须决定使用哪种类型,是double还是single。在本例中,所有轨道都使用双精度,因此不需要执行此步骤。

  2. 如果输入轨道使用不同的定义StateParameters,首先必须创建所有元素的超集StateParameters然后用那个超集StateParameters字段。类似的过程必须完成ObjectAttributes字段。在本例中,所有轨道都使用相同的定义StateParametersObjectAttributes

为代码生成定义fuserHeterogeneousInputs的输入oneLocalTrack = struct(“TrackID”uint32 (0)“BranchID”uint32 (0)“SourceIndex”uint32 (0)“UpdateTime”、双(0)“年龄”uint32 (0)“状态”编码器。Typeof (1, [10 1], [10 0]),“StateCovariance”编码器。Typeof (1, [10 10], [11 11]),“StateParameters”、结构、“ObjectClassID”、双(0)“TrackLogic”“历史”“TrackLogicState”编码器。Typeof (false, [1 10], [0 1]),“IsConfirmed”假的,“IsCoasted”假的,“IsSelfReported”假的,“ObjectAttributes”、结构);localTracks =编码器。typeof(oneLocalTrack, [81], [10]);fuserinputargarguments = {localTracks, time};codegenheterogeneousInputsFuserarg游戏fuserInputArguments
代码生成成功。

使用生成的代码运行示例

像运行MATLAB代码一样运行生成的代码,但首先必须重新初始化场景、GOSPA对象和显示。

你可以使用toStruct对象函数将输入轨迹转换为结构数组。

注:

  1. 的输入轨道使用不同的数据类型状态StateCovariance属性,确保强制转换状态StateCovariance类型所选择的数据类型的所有轨道的oneLocalTrack上面的结构。

  2. 如果输入轨道需要字段的超集结构StateParametersObjectAttributes方法之前,请确保正确填充这些结构墨西哥人文件。

你可以使用gospaCG变量来保存这次运行的GOSPA指标,以便您可以将它们与MATLAB运行的GOSPA值进行比较。

使用生成的代码重新运行场景fusersteps = false;fusedTracks = objectTrack.empty;gospaCG = 0 (3,0);missedTargetsCG = 0 (3,0);falseTracksCG = 0 (3,0);Idx = 1;清晰的heterogeneousInputsFuser_mex重置(显示);重置(gospaRadar);重置(gospaLidar);重置(gospaCentral);重启(场景);advance(scenario) time = scenario. simulationtime;localTracks = localTracksCollection{idx};如果~isempty(localTracks) || fuserstepping fusedTracks = heterogeneousinputtsfuser_mex (toStruct(localTracks),time);fusersteps = true;结束radarTracks = localTracks([localTracks. sourceindex]==1);lidarTracks = localTracks([localTracks. sourceindex]==2);%捕获所有跟踪器的GOSPA及其组件[gospaCG(1,idx),~,~,~,missedTargetsCG(1,idx),falseTracksCG(1,idx)] = gospaRadar(radarTracks, groundTruth);[gospaCG(2,idx),~,~,~,missedTargetsCG(2,idx),falseTracksCG(2,idx)] = gospaLidar(lidarTracks, groundTruth);[gospaCG(3,idx),~,~,~,missedTargetsCG(3,idx),falseTracksCG(3,idx)] = gospaCentral(fusedTracks, groundTruth);更新显示显示器(radarTracks场景、[][],[],[],[],[], [], lidarTracks, fusedTracks);Idx = Idx + 1;结束

Figure包含了uipanel类型的对象。

在运行结束时,您想要验证生成的代码是否提供了与MATLAB代码相同的结果。使用您在两次运行中收集的GOSPA指标,您可以在高层次上比较结果。由于数字四舍五入,生成的代码的结果相对于MATLAB代码可能有很小的差异。为了比较结果,您可以使用GOSPA值之间的绝对差值,并检查它们是否都小于1e-10。结果表明,两者的差异非常小。

比较MATLAB运行和生成代码的GOSPA值aregospalvaluesequal = all(abs(gospalvaluesg)<1e-10,“所有”);disp (" GOSPA值是否等于小数点后10位(true/false)? "+字符串(areGOSPAValuesEqual))
GOSPA值是否等于小数点后10位(true/false)?真正的

总结

在本例中,您了解了如何在输入音轨是异构的情况下为音轨级融合算法生成代码。你学会了如何定义trackFuser和它的SourceConfigurations属性以支持异构源。金宝app您还学习了如何在编译时定义输入,以及如何在运行时将其传递给mex文件。

金宝app支持功能

GOSPA度量使用以下函数。

helperLidarDistance

函数用于计算雷达状态空间中航迹估计值与指定的地面真值之间的归一化距离。

函数dist = helperLidarDistance(track, truth)%计算跟踪器估计的状态的实际值%中心不同于原点,跟踪器估计中心rOriginToCenter = -truth.OriginOffset(:) + [0;0;truth.Height/2];四元数[真理]偏航真理。球场上的真理。卷),“eulerd”“ZYX股票”“帧”);actPos = true . position (:) + rotatepoint(rot,rOriginToCenter')';%实际速度和z速率actVel = [norm(truth.Velocity(1:2));truth.Velocity(3)];%实际偏航actYaw = truth.Yaw;%实际尺寸。actDim = [truth.Length;truth.Width;truth.Height];%实际偏航率actYawRate = truth.AngularVelocity(3);计算误差在每一个估计加权的“需求”%的系统。在每个方面使用马氏距离指定的距离其中协方差是由“需求”定义的。这%有助于避免轨道在其下方/上方报告时的倾斜距离由于状态/测量模型的不准确性导致的不确定性。%位置错误。estPos = track。状态([1 2 6]); reqPosCov = 0.1*eye(3); e = estPos - actPos; d1 = sqrt(e'/reqPosCov*e);%速度误差estVel =轨道。状态(7 [3]);reqVelCov = 5*eye(2);e = estVel - actVel;d2 = sqrt(e'/reqVelCov*e);偏航误差%estYaw = track.State(4);reqYawCov = 5;e = estYaw - actYaw;d3 = sqrt(e'/reqYawCov*e);%偏航率错误estYawRate = track.State(5);reqYawRateCov = 1;e = estYawRate - actYawRate;d4 = sqrt(e'/reqYawRateCov*e);%尺寸错误estDim = track。状态([8 9 10]); reqDimCov = eye(3); e = estDim - actDim; d5 = sqrt(e'/reqDimCov*e);总距离%Dist = d1 + d2 + d3 + d4 + d5;结束

helperRadarDistance

函数用于计算雷达状态空间中航迹估计值与指定的地面真值之间的归一化距离。

函数dist = helperRadarDistance(track, truth)%计算跟踪器估计的状态的实际值%中心不同于原点,跟踪器估计中心rOriginToCenter = -truth.OriginOffset(:) + [0;0;truth.Height/2];四元数[真理]偏航真理。球场上的真理。卷),“eulerd”“ZYX股票”“帧”);actPos = true . position (:) + rotatepoint(rot,rOriginToCenter')';actPos = actPos(1:2);%仅2-D%实际速度actVel = norm(truth.Velocity(1:2));%实际偏航actYaw = truth.Yaw;%实际尺寸。只有二维雷达actDim = [truth.Length;truth.Width];%实际偏航率actYawRate = truth.AngularVelocity(3);计算误差在每一个估计加权的“需求”%的系统。在每个方面使用马氏距离指定的距离其中协方差是由“需求”定义的。这%有助于避免轨道在其下方/上方报告时的倾斜距离由于状态/测量模型的不准确性导致的不确定性。%位置错误estPos = track。状态([1 - 2]);reqPosCov = 0.1*eye(2);e = estPos - actPos;d1 = sqrt(e'/reqPosCov*e);%速度错误estVel = track.State(3);reqVelCov = 5;e = estVel - actVel;d2 = sqrt(e'/reqVelCov*e);偏航误差%estYaw = track.State(4);reqYawCov = 5;e = estYaw - actYaw;d3 = sqrt(e'/reqYawCov*e);%偏航率错误estYawRate = track.State(5);reqYawRateCov = 1;e = estYawRate - actYawRate;d4 = sqrt(e'/reqYawRateCov*e);%尺寸错误estDim = track。状态(7 [6]);reqDimCov = eye(2);e = estDim - actDim;d5 = sqrt(e'/reqDimCov*e);总距离%Dist = d1 + d2 + d3 + d4 + d5;不测量三维状态的持续惩罚Dist = Dist + 3;结束