主要内容

为具有异构源跟踪的跟踪融合器生成代码

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

定义一个用于代码生成的跟踪Fuser

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

代码生成入口函数

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

为了在调用函数之间保留fuser的状态,可以将fuser定义为持续的变量。在第一次调用时,必须定义fuser变量,因为它是空的。以下代码的其余部分步骤trackFuser并返回融合履带。

函数tracks = heteroousinputsfuser (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 3 1]),...“HasAdditiveProcessNoise”假的,...“AssignmentThreshold”, 250年正无穷,...“ConfirmationThreshold”[3 - 5],...“DeletionThreshold”, 5 [5],...“StateFusion”“自定义”...“CustomStateFusionFcn”, @helperRadarLidarFusionFcn);结束tracks = fuser(localTracks, time);结束

同质源配置

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

这是代码local2central函数,该函数使用SourceIndex属性来确定要使用的正确函数。由于两种本地航迹转换为相同的中心航迹定义,因此不需要预先定义中心航迹。

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

这个函数central2local将中心轨迹转换为雷达轨迹SourceIndex是1还是进入激光雷达轨道如果SourceIndex是2。因为这两个轨道有不同的定义状态StateCovariance,TrackLogicState,您必须首先预定义输出。下面是函数的代码片段:

函数localTrack = central2local(centralTrack) state = 0;stateCov = 1;coder.varsize (“状态”, [10, 1], [10 0]);coder.varsize (“stateCov”, [10 10], [1 1]);localTrack = objectTrack(“状态”、州、“StateCovariance”, stateCov);开关centralTrack。SourceIndex情况下1 localTrack = central2radar(centralTrack);情况下2 localTrack = central2lidar(centralTrack);否则此分支从未到达,但强制代码必须到达。%生成来使用预定义的localTrack。结束结束

的函数radar2central而且central2radar与原始示例相同,但从实时脚本转移到heterogeneousInputsFuser函数。您还可以添加lidar2central而且central2lidar的函数heterogeneousInputsFuser函数。这两个函数从融合器使用的航迹定义转换为激光雷达的航迹定义。

在MATLAB中运行示例

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

加载场景和记录的本地轨迹负载(“lidarRadarData.mat”“场景”“localTracksCollection”) display = helperTrackFusionCodegenDisplay(“FollowActorID”3);showLegend(显示、场景);%雷达GOSPAgospaRadar = trackGOSPAMetric(“距离”“自定义”...“DistanceFcn”@helperRadarDistance,...“CutoffDistance”25);激光雷达= trackGOSPAMetric(“距离”“自定义”...“DistanceFcn”@helperLidarDistance,...“CutoffDistance”25);中央/熔融GOSPAgospaCentral = trackGOSPAMetric(“距离”“自定义”...“DistanceFcn”@helperLidarDistance,...%状态空间与激光雷达相同“CutoffDistance”25);Gospa = 0 (3,0);missedTargets = 0 (3,0);falseTracks = 0 (3,0);%度量的基本真理。这个变量在每次时间步中都会更新%自动,因为它是给演员的句柄。groundTruth = scenario.Actors(2:end);fuserstepping = false;fusedTracks = objectTrack.empty;Idx = 1;清晰的heterogeneousInputsFuseradvance(scenario) time = scenario. simulationtime;localTracks = localTracksCollection{idx};如果~isempty(localTracks) || fusersteps fusedTracks =异质性inputsfuser (localTracks,time);fuserstepping = 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;结束

{

为跟踪Fuser生成代码

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

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

注:

  1. 的输入轨道使用不同的类型状态而且StateCovariance属性,您必须决定使用哪种类型,双类型还是单类型。在这个例子中,所有的轨道都使用双精度,没有必要执行这个步骤。

  2. 如果输入轨道使用不同的定义StateParameters,您必须首先创建所有的超集StateParameters用那个超集StateParameters字段。也必须执行类似的过程ObjectAttributes字段。在本例中,所有曲目使用相同的定义StateParameters而且ObjectAttributes

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

使用生成的代码运行示例

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

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

注:

  1. 方法使用不同的数据类型状态而且StateCovariance属性,请确保转换为状态而且StateCovariance对象时选择的数据类型的所有音轨的oneLocalTrack上面的结构。

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

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

使用生成的代码重新运行场景fuserstepping = 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) || fusersteps fusedTracks = heteroousinputsfuser_mex (toStruct(localTracks),time);fuserstepping = 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;结束

{

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

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

总结

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

万博1manbetx支持功能

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 = true . yaw;%实际尺寸。actDim = [true . length; width; true . height];%实际偏航速率actYawRate = true . angularvelocity (3);%计算误差在每个估计加权的“需求”%的系统。用马氏距离在各个方面指定的距离%的估计,其中协方差由“需求”定义。这%有助于避免偏离距离时,航迹低于/超过报告他们%不确定度,因为状态/测量模型不准确。位置错误。estPos = track。状态([1 2 6]); reqPosCov = 0.1*eye(3); e = estPos - actPos; d1 = sqrt(e'/reqPosCov*e);%速度误差estVel = track。状态(7 [3]);reqVelCov = 5*眼(2);e = estVel - actVel;d2 =√(e'/reqVelCov*e);%偏航误差estYaw = track.State(4);reqYawCov = 5;e = estYaw - actYaw;d3 =√(e'/reqYawCov*e);%偏航速率错误estYawRate = track.State(5);reqYawRateCov = 1;e = estYawRate - actYawRate;d4 =根号(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 = true . yaw;%实际尺寸。雷达只有二维actDim = [true . length; true . width];%实际偏航速率actYawRate = true . angularvelocity (3);%计算误差在每个估计加权的“需求”%的系统。用马氏距离在各个方面指定的距离%的估计,其中协方差由“需求”定义。这%有助于避免偏离距离时,航迹低于/超过报告他们%不确定度,因为状态/测量模型不准确。%位置错误estPos = track。状态([1 - 2]);reqPosCov = 0.1*眼睛(2);e = estPos - actPos;d1 =√(e'/reqPosCov*e);%速度错误estVel = track.State(3);reqVelCov = 5;e = estVel - actVel;d2 =√(e'/reqVelCov*e);%偏航误差estYaw = track.State(4);reqYawCov = 5;e = estYaw - actYaw;d3 =√(e'/reqYawCov*e);%偏航速率错误estYawRate = track.State(5);reqYawRateCov = 1;e = estYawRate - actYawRate;d4 =根号(e'/reqYawRateCov*e);%尺寸误差estDim = track。状态(7 [6]);reqDimCov =眼睛(2);e = estDim - actDim;d5 =√(e'/reqDimCov*e);总距离%Dist = d1 + d2 + d3 + d4 + d5;不测量三维状态的恒定惩罚。Dist = Dist + 3;结束