主要内容

用于汽车安全应用的履带对履带融合

这个例子展示了如何融合两辆车的轨迹,以提供比每辆车所能看到的更全面的环境评估。该示例演示了轨迹级fuser和对象轨迹数据格式的使用。在本例中,您将使用自动驾驶工具箱™中的驾驶场景和视觉检测生成器,雷达工具箱™中的雷达数据生成器,以及传感器融合和跟踪工具箱™中的跟踪和跟踪融合模型。

动机

汽车安全应用依赖于车辆上不同传感器系统的数据融合。单个车辆通过使用集中跟踪器或采用更分散的方法和融合单个传感器产生的轨迹来融合传感器检测。除了车辆数据融合外,多车数据融合还提供了额外的好处,包括更好的覆盖范围、态势感知和安全性[1].这种车辆间传感器融合方法利用了传感器的多样性,为每辆车提供了更好的覆盖范围,因为它使用了该地区其他车辆上的传感器更新的数据。政府和汽车制造商早就认识到,为了提高汽车安全性,需要在车辆之间共享信息。例如,V2X协议和蜂窝通信链路正在开发中。

虽然多辆汽车的传感器融合是有益的,但大多数汽车都需要满足一定的安全要求,即使只有内部传感器可用。因此,车辆可能配备一个跟踪器,一个跟踪器,或两者兼有。这些跟踪算法提供了单车水平的态势感知。因此,在这个例子中,假设车辆通过广播轨道和执行轨道对轨道融合来共享态势感知。

这个例子演示了融合两辆车履带的好处,以增强态势感知和安全性。这个例子没有模拟通信系统。相反,该示例假设通信系统提供了在两辆车之间传输轨道所需的带宽。

跟踪到跟踪体系结构

以下框图描述了两辆车的主要功能,其中:

  • 车辆1有两个传感器,每个传感器为本地车辆跟踪器提供检测。跟踪器利用来自局部传感器的检测来跟踪目标,并将这些局部轨迹输出到车辆轨迹fuser。

  • 车辆2有一个单一传感器,它是一个跟踪雷达。跟踪雷达输出跟踪,并作为车辆2的本地跟踪器。跟踪雷达的跟踪是车辆2上车辆跟踪定影器的输入。

  • 每辆车上的履带熔断器将本地车辆履带与从另一辆车辆履带熔断器接收的履带熔断。每次更新后,每辆车上的履带熔断器都会广播它的融合履带,并将其反馈到另一辆车上的履带熔断器的下一次更新中。

在本例中,使用trackerJPDA对象来定义车辆1跟踪器。

为车辆1创建跟踪器v1Tracker = trackerJPDA (“TrackerIndex”,1,“DeletionThreshold”(4 - 4),“AssignmentThreshold”, 100年正);%车辆1跟踪器posSelector = [1 0 0 0 0 0;0 0 1 0 0 0];

在这种架构中,来自一辆车的保险丝轨迹更新另一辆车上的保险丝轨迹。这些保险丝轨道然后广播回第一辆车。为了避免谣言的传播,请注意如何从另一辆车履带更新履带fuser。

考虑下面的谣言传播示例:在某个更新步骤,车辆1使用其内部传感器跟踪对象。然后车辆1融合目标轨迹并将其传送给车辆2,车辆2将目标轨迹与自己的轨迹融合并感知目标。到目前为止,这正是轨道对轨道融合的目标:用车辆1的信息增强车辆2的态势感知。因为车辆2现在知道了这个物体,它也开始广播轨道,也许是为了让另一辆车(在示例中没有显示)受益。

然而,车辆1现在从车辆2接收到只有车辆1真正跟踪的对象的轨迹信息。因此,车辆1上的轨迹跟踪器必须意识到它从车辆2获得的这个物体的轨迹实际上并不包含任何由独立来源更新的新信息。要区分包含新信息的轨道和只重复信息的轨道,必须将车辆2定义为外部来源至车辆1上的履带定影器。同样,必须将车辆1定义为车辆2上轨道定影器的外部源。此外,您需要仅定义由轨迹融合器根据来自内部源的信息更新的轨迹,如自我报告.通过这样做,每辆车的轨道熔断器忽略来自轨道的更新,在轨道熔断器之间来回反弹,没有任何新的信息。

每个车辆的局部跟踪器跟踪相对于车辆参考帧(称为ego帧)的对象。轨迹到轨迹的融合在场景帧(即全局级别的帧)上完成。助手egoToScenario函数将轨迹从自我框架转换到场景框架。同样地,函数场景托戈将轨迹从情景框架转换到任何自我框架。两种转换都依赖于StateParameters财产的objectTrack对象。当trackFuser对象计算场景帧中的中心轨道到任意帧中的局部轨道的距离,它使用StateParameters对局部轨迹进行坐标变换。

要实现前面描述的功能trackFuser定义,将下列来源定义为熔丝源配置对象。

定义每辆车的来源v1TrackerConfiguration = fuserSourceConfiguration (“SourceIndex”,1,“iInternalSource”,真的,...% v1Tracker是v1Fuser的内部“CentralToLocalTransformFcn”@scenarioToEgo,“LocalToCentralTransferorMFCN”,@egotosecenario);%坐标变换v2FuserConfiguration = fuserSourceConfiguration (“SourceIndex”,4,“iInternalSource”、假);% v2Fuser在v2Fuser之外v1Sources = {v1TrackerConfiguration;v2FuserConfiguration};v2TrackerConfiguration = fuserSourceConfiguration (“SourceIndex”,2,“iInternalSource”,真的,...% v2Tracker是v2Fuser的内部“CentralToLocalTransformFcn”@scenarioToEgo,“LocalToCentralTransferorMFCN”,@egotosecenario);%坐标变换v1FuserConfiguration = fuserSourceConfiguration (“SourceIndex”3,“iInternalSource”、假);%v1Fuser位于v2Fuser的外部v2Sources = {v2TrackerConfiguration;v1FuserConfiguration};

您现在可以定义每个车辆履带fuser为trackFuser对象。

stateParams =结构(“帧”,“矩形”,“位置”(0 0 0),“速度”, 0 0 0);v1Fuser = trackFuser (“FuserIndex”3,...“AssignmentThreshold”, 100年正无穷,...“MaxNumSources”,2,“SourceConfigurations”v1Sources,...“StateFusion”,“十字路口”,“DeletionThreshold”,[3 3],...“状态参数”,stateParams);v2Fuser=跟踪定影器(“FuserIndex”,4,...“AssignmentThreshold”, 100年正无穷,...“MaxNumSources”,2,“SourceConfigurations”v2Sources,“StateFusion”,...“十字路口”,“DeletionThreshold”,[3 3],...“状态参数”,stateParams);%初始化以下变量fusedTracks1 = objectTrack.empty (0,1);fusedTracks2 = objectTrack.empty (0,1);wasFuser1Updated = false;wasFuser2Updated = false;

定义场景

下面的场景显示了两辆车在街道上行驶。车辆1是先导车辆,配备了两个前视传感器:一个近程雷达传感器和一个视觉传感器。2号车与1号车相距10米,装有远程雷达。街道的右侧停放着车辆。一个行人站在车辆之间。这条行人以一个点的形式显示在X = 60米处。

由于车辆2与车辆1距离较近,车辆2雷达传感器覆盖范围大部分被车辆1遮挡。因此,车辆2上的轨道fuser维护的大部分轨道首先由车辆1广播的轨道初始化。

%创建drivingScenario对象和两辆车[scenario, vehicle1, vehicle2] = createDrivingScenario;%创建所有传感器[sensors, numSensors, attachdvehicle] = createSensors(scenario);%创建显示[f,绘图仪]= createV2VDisplay(场景,传感器,附属车辆);

下面的追逐情节是从第二辆车的角度来看的。箭头表示行人几乎完全被停放的车辆和第一辆车辆遮挡的位置。

将每辆车定义为一个参与者、传感器、跟踪器和绘图仪的组合v1=结构(“演员”{vehicle1},“传感器”,{传感器(attachedVehicle = = 1)},“追踪”,{v1Tracker},“DetPlotter”{plotters.veh1DetPlotter},“TrkPlotter”,{plotters.veh1TrkPlotter});v2=struct(“演员”{vehicle2},“传感器”,{传感器(attachedVehicle = = 2)},“追踪”{{}},“DetPlotter”{{}},“TrkPlotter”, {plotters.veh2TrkPlotter});%车辆2上没有侦测到或追踪器

运行仿真

下面的代码运行这个模拟。

运行=真;%对于可重复的结果,设置随机数种子s=rng;rng(2019)快照时间=[0.5,2.8,4.4,6.3,inf];快照=单元(numel(快照时间,1));i=1;f.可见=“开”;运行&& ishhandle (f) time = scenario.SimulationTime;%检测和跟踪车辆水平[tracks1, wasTracker1Updated] = detectAndTrack (v1、时间posSelector);[tracks2, wasTracker2Updated] = detectAndTrack (v2、时间posSelector);%保留以前fuser更新的轨道oldFusedTracks1=fusedTracks1;oldFusedTracks2=fusedTracks2;%更新熔断器如果WasTracker1更新| | WasFuser 2更新的tracksToFuse1=[tracks1;oldFusedTracks2];如果isLocked(v1Fuser) || ~isempty(tracksToFuse1) [fusedTracks1,~,~,info1] = v1Fuser(tracksToFuse1,time);wasFuser1Updated = true;pos = getTrackPositions (fusedTracks1 posSelector);字符串id = ((fusedTracks1.TrackID) ');plotTrack (plotters.veh1FusePlotter、pos、ids);其他的wasFuser1Updated=false;fusedTracks1=objectTrack.empty(0,1);终止其他的wasFuser1Updated=false;fusedTracks1=objectTrack.empty(0,1);终止如果wasstracker2updated || wasFuser1Updated tracksToFuse2 = [tracks2;oldFusedTracks1];如果isLocked(v2Fuser)| | ~isempty(tracksToFuse2)[fusedTracks2,~,~,info2]=v2Fuser(tracksToFuse2,time);wasFuser2Updated=true;pos=getTrackPositions(fusedTracks2,posSelector);id=string([fusedTracks2.TrackID]);plotrack(plotters.veh2FusePlotter,pos,ids);其他的wasFuser2Updated = false;fusedTracks2 = objectTrack.empty (0,1);终止其他的wasFuser2Updated = false;fusedTracks2 = objectTrack.empty (0,1);终止%更新显示updateV2VDisplay(绘图仪,场景,传感器,附属车辆)%将场景向前推进一步,如果场景完成,则退出循环运行=进步(场景);%在指定时间捕获帧的图像如果Time >= snaptimes(i) snaps{i} = takesnap(f);I = I + 1;终止终止

图中包含2个轴对象和其他类型的uipanel对象。axis对象1包含11个类型为patch, line, text的对象。这些目标代表雷达,视觉,探测,局部轨迹,Fuser轨迹。axis对象2包含8个类型为patch, line, text的对象。这些物体代表雷达,局部轨迹,Fuser轨迹。

图中显示了场景和场景结束时的跟踪结果。本示例的后续部分将在关键时刻分析跟踪结果。

在仿真开始时分析跟踪

当模拟开始时,车辆1检测到停在街道右侧的车辆。然后,车辆追踪器确认与停放车辆相关的轨迹。此时,车辆2跟踪器检测和跟踪的唯一对象是车辆1,它就在它的正前方。一旦车辆轨道熔断器确认轨道,它广播它们,车辆轨道熔断器熔断它们。因此,车辆2在自己检测到停车车辆之前就会意识到它们。

showsnap(四合扣,1)

图Snap #1包含2个轴对象和其他类型的uipanel对象。axis对象1包含9个类型为patch, line, text的对象。这些目标代表雷达,视觉,探测,局部轨迹,Fuser轨迹。axis对象2包含7个类型为patch, line, text的对象。这些物体代表雷达,局部轨迹,Fuser轨迹。

分析路边行人的跟踪

随着模拟的继续,车辆2也能够检测和跟踪停在旁边的车辆,并将它们与车辆1的轨道融合。车辆2在仿真过程中大约4秒就能检测和跟踪行人,而车辆2在仿真过程中大约4.4秒就能融合行人相关的轨迹(见快照2)。车辆需要大约两秒钟的时间才能通过自己的传感器检测和跟踪行人(见快照3)。提前两秒钟检测到街上的行人可以显著提高安全性。

showsnap(四合扣,2)

图Snap #2包含2个轴对象和其他类型的uipanel对象。axis对象1包含11个类型为patch, line, text的对象。这些目标代表雷达,视觉,探测,局部轨迹,Fuser轨迹。axis对象2包含9个类型为patch, line, text的对象。这些物体代表雷达,局部轨迹,Fuser轨迹。

showsnap(四合扣,3)

图Snap #3包含2个轴对象和其他类型的uipanel对象。axis对象1包含13个类型为patch, line, text的对象。这些目标代表雷达,视觉,探测,局部轨迹,Fuser轨迹。axis对象2包含12个类型为patch, line, text的对象。这些物体代表雷达,局部轨迹,Fuser轨迹。

避免谣言传播

当两辆车相互通信轨道时,存在着这样的风险,即它们将通过重复另一辆车通信的内容,继续通信它们不再检测到的对象的信息。这种情况叫做谣言传播。

当车辆经过这些物体,并且这些物体离开其视野时,两个跟踪器都会丢弃与这些物体相关联的融合轨迹(参见快照4)。丢弃轨迹表明,在两个车辆之间来回广播的融合轨迹不用于传播谣言。

showsnap(断了,4)

图Snap #4包含2个轴对象和其他类型的uipanel对象。axis对象1包含11个类型为patch, line, text的对象。这些目标代表雷达,视觉,探测,局部轨迹,Fuser轨迹。axis对象2包含8个类型为patch, line, text的对象。这些物体代表雷达,局部轨迹,Fuser轨迹。

%重新启动驱动场景,使角色返回到初始位置重启(场景);释放所有的传感器对象,这样它们可以再次使用对于sensorIndex = 1:numSensors release(sensors{sensorIndex});终止%将随机种子返回到其以前的值rng (s)

总结

在本例中,您看到了轨道对轨道融合如何增强态势感知,并提高汽车应用中的安全性。你看到了如何建立trackFuser来执行轨迹对轨迹的融合,以及如何定义源是内部的还是外部的熔丝源配置对象。通过这样做,您可以避免谣言的传播,并且只保留每辆车真正观察到的融合轨迹。

参考文献

[1] Duraisamy, B., T. Schwarz和C. Wohler。“用于汽车安全应用的轨道水平融合算法”。在2013年信号处理、图像处理和模式识别国际会议, 179–84, 2013.https://doi.org/10.1109/ICSIPR.2013.6497983

金宝app支持功能

createDrivingScenario

创建一个驱动场景驾驶场景设计师应用程序。

函数[scenario, egoVehicle, secondVehicle] = createDrivingScenario%构造一个驱动场景对象场景= drivingScenario (“SampleTime”, 0.1);%添加所有路段道路中心= [50.8 0.5 0;253.4 - 1.5 0);roadWidth = 12;路(场景、roadCenters roadWidth);道路中心= [100.7 -100.6 0;100.7 - 103.7 0);路(场景,roadCenters);道路中心= [201.1 -99.2 0;199.7 - 99.5 0);路(场景,roadCenters);添加自我载体egoVehicle =车辆(场景中,“ClassID”, 1“位置”, [65.1 -0.9 0],“PlotColor”, [0 0.7410 0.4470]);路径点= [71 -0.5 0;148.7 - -0.5 0);速度= 12;轨迹(egoVehicle、锚点、速度);%添加第二辆车第二辆车=车辆(场景,“ClassID”, 1“位置”, [55.1 -0.9 0]);路径点= [61 -0.5 0;138.7 - -0.5 0);速度= 12;轨迹(secondVehicle、锚点、速度);把停着的车加起来车辆(场景中,“ClassID”, 1“位置”, [111.0 -3.6 0]);车辆(场景中,“ClassID”, 1“位置”, [140.6 -3.6 0]);车辆(场景中,“ClassID”, 1“位置”,[182.6-3.6 0]);车辆(场景,“ClassID”, 1“位置”, [211.3 -4.1 0]);%增加行人演员(场景中,“ClassID”4“长度”, 0.5,“宽度”, 0.5,...“高度”, 1.7,“位置”, [130.3 -2.7 0],“RCSPattern”, [-8 -8]);%添加停放的卡车车辆(场景中,“ClassID”2,“长度”, 8.2,“宽度”, 2.5,...“高度”, 3.5,“位置”, [117.5 -3.5 0]);终止

创建传感器

创建场景中使用的传感器,并列出它们与车辆的附件。

函数[sensors,numSensors,attachedVehicle]=创建传感器(场景)%createSensors返回所有传感器对象以生成检测%在createssensors和createDrivingScenario中使用的单位%距离/位置-米%速度-米/秒角-度% RCS模式- dBsm%为每个传感器分配所有参与者的物理和雷达剖面概要文件= actorProfiles(场景);%车辆1雷达报告集群检测传感器{1}= radarDataGenerator (“没有扫描”,“SensorIndex”, 1“UpdateRate”10...“MountingLocation”, [3.7 0 0.2],“RangeLimits”, [0 50],“FieldOfView”, [60 5],...“RangeResolution”, 2.5,“AzimuthResolution”4...“配置文件”配置文件,“HasOcclusion”,真的,“HasFalseAlarms”假的,...“TargetReportFormat”,“集群检测”);车辆2雷达跟踪传感器{2}=雷达数据发生器(“没有扫描”,“SensorIndex”2,“UpdateRate”10...“MountingLocation”, [3.7 0 0.2],“RangeLimits”, [0 120],“FieldOfView”30 [5],...“RangeResolution”, 2.5,“AzimuthResolution”4...“配置文件”配置文件,“HasOcclusion”,真的,“HasFalseAlarms”假的,...“TargetReportFormat”,“轨道”,“DeletionThreshold”3 [3]);%车辆1视觉传感器报告检测到传感器{3}= visionDetectionGenerator (“SensorIndex”3,...“MaxRange”, 100,“SensorLocation”, [1.9 0],“DetectorOutput”,“只将对象”,...“ActorProfiles”,概要文件);attachedVehicle = [1, 2, 1];numSensors =元素个数(传感器);终止

场景托戈

执行从场景到自我坐标的坐标转换。

trackInScenarioStateParameters定义以将其从场景坐标转换为自我坐标。

该状态采用恒定速度模型[x;vx;y;vy;z;vz]。

函数trackInEgo=scenarioToEgo(trackInScenario)egoPosInScenario=trackInScenario.StateParameters.OriginPosition;egoVelInScenario=trackInScenario.StateParameters.OriginVelocity;stateInScenario=trackInScenario.State;stateShift=[egoPosInScenario(1);egoVelInScenario(1);egoPosInScenario(2);egoVelInScenario(2);egoPosInScenario)(3) ];stateInEgo=stateInScenario-stateShift;trackInEgo=objectTrack(“UpdateTime”, trackInScenario。UpdateTime,“状态”,stateInEgo,“StateCovariance”, trackInScenario。StateCovariance,“状态参数”, trackInScenario.StateParameters);终止

egoToScenario

执行从自我到场景坐标的坐标转换。

trackInEgoStateParameters定义为将其从自我坐标转换为场景坐标。

该状态采用恒定速度模型[x;vx;y;vy;z;vz]。

函数trackInScenario = egoToScenario(trackInEgo) egoPosInScenario = trackInEgo. stateparameters . originposition;egoVelInScenario = trackInEgo.StateParameters.OriginVelocity;stateInScenario = trackInEgo.State;stateShift = [egoPosInScenario (1); egoVelInScenario (1); egoPosInScenario (2); egoVelInScenario (2); egoPosInScenario (3); egoVelInScenario (3)];statinego = statinscenario + statshift;trackInScenario = objectTrack (“UpdateTime”, trackInEgo。UpdateTime,“状态”,stateInEgo,“StateCovariance”, trackInEgo。StateCovariance,“状态参数”, trackInEgo.StateParameters);终止

探测轨道

此功能用于收集一辆车中传感器的所有检测结果,并用它们更新跟踪器。

代理是一种结构,它包含参与者信息和传感器、跟踪器和绘图仪,用于绘制检测和车辆轨迹。

函数[追踪,wasTrackerUpdated] = detectAndTrack(代理,时间,posSelector)%从车辆中创建检测姿势=目标姿势(agent.Actor);[detections,isValid]=车辆检测(agent.Actor.Position,agent.Sensors,poses,time,agent.DetPlotter);%更新跟踪器,从报告检测的传感器获取轨迹如果isValid agent.Tracker.StateParameters = struct(...“帧”,“矩形”,...“OriginPosition”agent.Actor.Position,...“OriginVelocity”,agent.Actor.Velocity);tracks=agent.Tracker(检测,时间);tracksInScenario=tracks;对于i = 1:numel(tracks) tracksInScenario(i) = egoToScenario(tracks(i));终止pos = getTrackPositions (tracksInScenario posSelector);plotTrack(agent.TrkPlotter,pos) wasstrackerupdated = true;其他的跟踪= objectTrack.empty (0,1);wasTrackerUpdated = false;终止%从跟踪传感器获取其他轨迹[sensorTracks, wasSensorTrackerUpdated] = vehicleTracks (agent.Actor agent.Sensors,姿势、时间agent.TrkPlotter);跟踪= vertcat(跟踪、sensorTracks);wasstrackerupdated = wasstrackerupdated || wasSensorTrackerUpdated;终止

车辆检测

收集所有连接在车辆上的传感器的检测结果。

函数[objectDetections,isValid] = vehicleDetections(位置,传感器,姿势,时间,绘图仪)numSensors = nummel(传感器);objectDetections = {};isValidTime = false(1, numSensors);%为每个传感器生成检测对于sensorIndex = 1:numSensors sensor = sensors{sensorIndex};如果isa(传感器,“visionDetectionGenerator”) | | ~ strcmpi(传感器。TargetReportFormat,“轨道”) [objectDets, ~, sensorConfig] =传感器(姿势,时间);如果islogical(sensorConfig) isValidTime(sensorIndex) = sensorConfig;其他的isValidTime (sensorIndex) = sensorConfig.IsValidTime;终止setAtt(d), objectDets = cellfun(@(d))“UniformOutput”、假);numObjects =元素个数(objectDets);objectDetections = [objectDetections;objectDets (1: numObjects)];% #好< AGROW >终止终止isValid = (isValidTime);%绘制检测如果numel(objectDetections)>0 detPos = cellfun(@(d)d. measurement (1:2), objectDetections,“UniformOutput”、假);detPos = cell2mat(detPos')' + position(1:2);plotDetection(绘图仪,detPos);终止终止函数d=设定值(d)%设置属性为一个结构d、 ObjectAttributes=struct;%只保留位置测量和移除速度如果nummel (d.Measurement)==6;d.MeasurementNoise = d.MeasurementNoise (1:3, 1:3);d.MeasurementParameters{1}。HasVelocity = false;终止终止

车轨

从报告车辆轨迹的传感器收集所有轨迹。

函数[轨迹,wasTrackerUpdated]=车辆轨迹(演员、传感器、姿势、时间、绘图仪)%从车辆中创建检测numSensors =元素个数(传感器);跟踪= objectTrack.empty;isValidTime = false(1, numSensors);%为每个传感器生成检测对于sensorIndex = 1:numSensors sensor = sensors{sensorIndex};如果isa(传感器,“radarDataGenerator”) & & strcmpi(传感器。TargetReportFormat,“轨道”) [sensorTracks, ~, sensorConfig] =传感器(姿势,时间);如果islogical(sensorConfig) isValidTime(sensorIndex) = sensorConfig;其他的isValidTime (sensorIndex) = sensorConfig.IsValidTime;终止numObjects =元素个数(sensorTracks);跟踪=[跟踪;sensorTracks (1: numObjects)];% #好< AGROW >终止终止wasTrackerUpdated = (isValidTime);如果~ wasTrackerUpdated没有更新车辆跟踪传感器返回终止%将车辆位置和速度添加到跟踪状态参数对于i = 1:numel(tracks) tracks(i). stateparameters . ..StateParameters OriginPosition =歌曲(我)。OriginPosition + actor.Position ';跟踪.StateParameters(我)。.StateParameters OriginVelocity =歌曲(我)。OriginVelocity + actor.Velocity ';终止%的阴谋跟踪如果numel(tracks)>0 trPos = arrayfun(@(t)t. state ([1,3])), tracks,“UniformOutput”、假);trPos = cell2mat(trPos')' + actor.Position(1:2);plotTrack(绘图仪,trPos);终止终止