主要内容

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

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

为代码生成定义一个跟踪Fuser

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

代码生成入口函数

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

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

函数tracks = heterogeneousInputsFuser(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 = helptrackfusioncodegendisplay (“FollowActorID”3);showLegend(显示、场景);%雷达GOSPAgospaRadar = trackGOSPAMetric(“距离”“自定义”...“DistanceFcn”@helperRadarDistance,...“CutoffDistance”25);激光雷达gospaLidar = trackGOSPAMetric(“距离”“自定义”...“DistanceFcn”@helperLidarDistance,...“CutoffDistance”25);%中央/熔融GOSPAgospaCentral = trackGOSPAMetric(“距离”“自定义”...“DistanceFcn”@helperLidarDistance,...%状态空间与激光雷达相同“CutoffDistance”25);Gospa = 0 (3,0);missedTargets = 0 (3,0);falseTracks = 0 (3,0);度量的基本真理。这个变量在每个时间步都更新%,因为它是参与者的句柄。groundTruth =场景。演员(2:结束);fuserstepping = false;fusedTracks = objectTrack.empty;Idx = 1;清晰的heterogeneousInputsFuseradvance(scenario) time = scenario. simulationtime;localTracks = localTracksCollection{idx};如果~isempty(localTracks) || fuserstepping fusedTracks = heterogeneousInputsFuser(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;结束

图包含uipanel类型的对象。

为履带熔断器生成代码

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

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

注:

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

  2. 如果输入轨道使用不同的定义StateParameters,您必须首先创建所有的超集StateParameters然后用这个超集StateParameters字段。必须对ObjectAttributes字段。在本例中,所有曲目使用相同的定义StateParameters而且ObjectAttributes

定义用于代码生成的fuserHeterogeneousInputs的输入onlocaltrack = 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], [1 1]),...“StateParameters”、结构、...“ObjectClassID”、双(0)...“TrackLogic”“历史”...“TrackLogicState”编码器。Typeof (false, [1 10], [0 1]),...“IsConfirmed”假的,...“IsCoasted”假的,...“IsSelfReported”假的,...“ObjectAttributes”、结构);localTracks =编码器。typeof(onlocaltrack, [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);谬误trackscg = 0 (3,0);Idx = 1;清晰的heterogeneousInputsFuser_mex重置(显示);重置(gospaRadar);重置(gospaLidar);重置(gospaCentral);重启(场景);advance(scenario) time = scenario. simulationtime;localTracks = localTracksCollection{idx};如果~isempty(localTracks) || fuserstepping fusedTracks = heterogeneousInputsFuser_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;结束

图包含uipanel类型的对象。

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

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

总结

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

金宝app支持功能

GOSPA度量使用以下函数。

helperLidarDistance

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

函数dist = helperLidarDistance(跟踪,真相)计算跟踪器估计的状态的实际值%中心与原点不同,跟踪器估计中心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 =真理。偏航;%实际尺寸。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 =√(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(跟踪,true)计算跟踪器估计的状态的实际值%中心与原点不同,跟踪器估计中心rOriginToCenter = -truth.OriginOffset(:) + [0;0;truth.Height/2];腐=四元数偏航真理。球场上的真理。卷),“eulerd”“ZYX股票”“帧”);actPos = true . position (:) + rotatepoint(rot,rOriginToCenter')';actPos = actPos(1:2);%仅2-D%实际速度actVel =范数(truth.Velocity(1:2));%实际偏航actYaw =真理。偏航;%实际尺寸。雷达只有二维actDim = [truth.Length;truth.Width];%实际偏航率actYawRate = truth.AngularVelocity(3);的“需求”加权计算每个估计的误差%的系统。用马氏距离在各个方面指定的距离%的估计,其中协方差由“需求”定义。这%有助于避免倾斜距离时,轨道低于/超过报告他们的%由于状态/测量模型不准确而产生的不确定性。%位置错误estPos = track。状态([1 - 2]);reqPosCov = 0.1*eye(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 = eye(2);e = estDim - actDim;d5 =根号(e'/reqDimCov*e);总距离%Dist = d1 + d2 + d3 + d4 + d5;%不测量三维状态的恒定惩罚Dist = Dist + 3;结束