Отслеживайте слияние для приложений безопасности автомобилей

Этот пример показывает, как сплавить дорожки от двух транспортных средств, чтобы предоставить более полную оценку окружения, которую может видеть каждое транспортное средство. Пример демонстрирует использование фузера уровня дорожки и формата данных дорожки объекта. В этом примере вы используете сценарий вождения и генератор обнаружения зрения от Automated Driving Toolbox™, генератор радиолокационных данных от Radar Toolbox™, и модели слияния отслеживания и отслеживания от Sensor Fusion and Tracking Toolbox™.

Мотивация

Приложения безопасности автомобиля полагаются на слияние данных из различных сенсорных систем, установленных на транспортном средстве. Отдельные транспортные средства взрывают обнаружения датчиков при помощи либо централизованного трекера, либо путем более децентрализованного подхода и сплавления треков, производимых отдельными датчиками. В дополнение к слиянию интравехикальных данных слияние данных из нескольких транспортных средств дает дополнительные преимущества, которые включают более высокий охват, ситуационную осведомленность и безопасность [1]. Этот подход к слиянию датчиков межтранспортного средства использует преимущества разнообразия датчиков и обеспечивает лучшее покрытие для каждого автомобиля, потому что он использует данные, обновленные датчиками на других транспортных средствах в этой области. Правительства и производители транспортных средств давно признают необходимость обмена информацией между автотранспортными средствами в целях повышения безопасности автомобилей. Для примера разрабатываются V2X протоколы и ссылки сотовой связи.

Хотя слияние датчиков между несколькими транспортными средствами выгодно, большинство транспортных средств должны соответствовать определенным требованиям безопасности, даже если доступны только внутренние датчики. Поэтому трансп, вероятно, будет оснащаемо трекером, трековым фузером или тем и другим. Эти алгоритмы отслеживания обеспечивают ситуационную осведомленность на уровне одного транспортного средства. В результате, предположение, сделанное в этом примере, заключается в том, что транспортные средства разделяют ситуационную осведомленность путем широковещательной передачи дорожек и выполнения слияния трека с дорожкой.

Этот пример демонстрирует преимущества сплавления дорожек с двух транспортных средств для повышения ситуационной осведомленности и безопасности. Этот пример не моделирует коммуникационных систем. Вместо этого пример принимает, что коммуникационная система обеспечивает полосу пропускания, необходимую для передачи дорожек между двумя транспортными средствами.

Архитектура Track-to-Track

Следующий блок изображает основные функции в двух транспортных средствах, где:

  • Транспортное средство 1 имеет два датчика, каждый из которых обеспечивает обнаружения локальному транспортному средству трекеру. Трекер использует обнаружения от локальных датчиков, чтобы отслеживать объекты и выводит эти локальные дорожки в фузер трека транспортного средства.

  • Транспортное средство 2 имеет один датчик, который является радаром слежения. Радар слежения выводит пути и служит локальным трекером для транспортного средства 2. Дорожки от радара слежения являются входами к путевому фюзеру транспортного средства на транспортном средстве 2.

  • Трековый фюзер на каждом транспортном средстве запирает локальные дорожки транспортного средства с дорожками, полученными от трекового фюзера другого транспортного средства. После каждого обновления трек-фьюзер на каждом транспортном средстве транслирует свои слитые дорожки, которые поступают в следующее обновление трека-фьюзера на другом транспортном средстве.

В этом примере вы используете trackerJPDA (Sensor Fusion and Tracking Toolbox), чтобы определить трекер транспортного средства 1.

% Create the tracker for vehicle 1
v1Tracker = trackerJPDA('TrackerIndex',1, 'DeletionThreshold', [4 4], 'AssignmentThreshold', [100 inf]); % Vehicle 1 tracker
posSelector = [1 0 0 0 0 0; 0 0 1 0 0 0];

В этой архитектуре слитые дорожки от одного транспортного средства обновляют слитые дорожки от другого транспортного средства. Эти слитые дорожки затем транслируются обратно на первое транспортное средство. Чтобы избежать распространения слухов, будьте осторожны, как треки из другого транспортного средства обновляют фузер трека.

Рассмотрим следующий пример распространения слухов: на некотором шаге обновления транспортное средство 1 отслеживает объект с помощью его внутренних датчиков. Транспортное средство 1 затем сплавляет дорожку объекта и передает ее транспортному средству 2, которое теперь сплавляет дорожку со своими собственными дорожками и становится известно об объекте. До этого момента это как раз и является целью слияния треков в трек: повысить ситуационную осведомленность транспортного средства 2 с помощью информации от транспортного средства 1. Поскольку транспортное средство 2 теперь знает об объекте, оно также начинает транслировать дорожку, возможно, в интересах другого транспортного средства (не показано в примере).

Однако теперь транспортное средство 1 принимает информацию о дорожке от транспортного средства 2 о объекте, который фактически отслеживает только транспортное средство 1. Таким образом, трек-фюзер на транспортном средстве 1 должен знать, что дорожки этого объекта, которые он получает от транспортного средства 2, на самом деле не содержат никакой новой информации, обновленной независимым источником. Чтобы сделать различие между треками, которые содержат новую информацию, и треками, которые просто повторяют информацию, вы должны определить транспортное средство 2 как внешний источник для слежения за фюзером на транспортном средстве 1. Точно так же транспортное средство 1 должно быть определено как внешний источник для трекового фюзера на транспортном средстве 2. Кроме того, вы должны задать только треки, которые обновляются фузером трека на основе информации от внутреннего источника как самоотчетные. При этом трековый фьюзер в каждом транспортном средстве игнорирует обновления из треков, которые прыгают назад и вперед между трековыми фьюзерами без какой-либо новой информации в них.

Локальный трекер каждого транспортного средства отслеживает объекты относительно исходной системы координат транспортного средства, называемой ego-системой координат. Слияние дорожки и дорожки выполняется в системе координат сценария, который является системой координат глобального уровня. Вспомогательный egoToScenario функция преобразует треки из системы координат ego в систему координат сценария. Точно так же функция scenarioToEgo преобразует дорожки из системы координат сценария в любой из системы координат. Оба преобразования полагаются на StateParameters свойство objectTrack (Sensor Fusion and Tracking Toolbox) объекты. Когда trackFuser объект вычисляет расстояние между центральной дорожкой в системе координат сценария и локальной дорожкой в любой системе координат, он использует StateParameters локальной дорожки для выполнения преобразования координат.

Для достижения ранее описанных trackFuser определения, задайте следующие источники как fuserSourceConfiguration (Sensor Fusion and Tracking Toolbox) объект.

% Define sources for each vehicle
v1TrackerConfiguration = fuserSourceConfiguration('SourceIndex',1,'IsInternalSource',true, ...   % v1Tracker is internal to v1Fuser
    "CentralToLocalTransformFcn", @scenarioToEgo, 'LocalToCentralTransformFcn', @egoToScenario); % Coordinate transformation
v2FuserConfiguration = fuserSourceConfiguration('SourceIndex',4,'IsInternalSource',false);       % v2Fuser is external to v2Fuser
v1Sources = {v1TrackerConfiguration; v2FuserConfiguration};
v2TrackerConfiguration = fuserSourceConfiguration('SourceIndex',2,'IsInternalSource',true, ...   % v2Tracker is internal to v2Fuser
    "CentralToLocalTransformFcn", @scenarioToEgo, 'LocalToCentralTransformFcn', @egoToScenario); % Coordinate transformation
v1FuserConfiguration = fuserSourceConfiguration('SourceIndex',3,'IsInternalSource',false);       % v1Fuser is external to v2Fuser
v2Sources = {v2TrackerConfiguration; v1FuserConfiguration};

Теперь можно задать каждое транспортное средство track fuser как trackFuser (Sensor Fusion and Tracking Toolbox) объект.

stateParams = struct('Frame','Rectangular','Position',[0 0 0],'Velocity',[0 0 0]);
v1Fuser = trackFuser('FuserIndex',3,...
    'AssignmentThreshold', [100 inf], ...
    'MaxNumSources',2,'SourceConfigurations',v1Sources,...
    'StateFusion','Intersection','DeletionThreshold',[3 3],...
    'StateParameters',stateParams);
v2Fuser = trackFuser('FuserIndex',4,...
    'AssignmentThreshold', [100 inf], ...
    'MaxNumSources',2,'SourceConfigurations',v2Sources,'StateFusion',...
    'Intersection','DeletionThreshold',[3 3],...
    'StateParameters',stateParams);

% Initialize the following variables
fusedTracks1 = objectTrack.empty(0,1);
fusedTracks2 = objectTrack.empty(0,1);
wasFuser1Updated = false;
wasFuser2Updated = false;

Определение сценария

В следующем сценарии показаны два транспортных средств, движущиеся по улице. Машина 1 является ведущим транспортным средством и оснащена двумя датчиками дальнего видения: датчиком радара малой дальности и датчиком зрения. Транспортное средство 2, движущаяся на 10 метров позади транспортного средства 1, оснащено радаром большой дальности. Правая сторона улицы содержит припаркованные транспортные средства. Между транспортными средствами стоит пешехода. Этот велосипед показан в виде точки примерно на X = 60 метрах.

Из-за короткого расстояния между транспортным средством 2 и транспортным средством 1 большая часть покрытия радарного датчика транспортного средства 2 перекрывается транспортным средством 1. В результате большинство дорожек, которые поддерживает трек-фьюзер на транспортном средстве 2, сначала инициализируются дорожками, транслируемыми из транспортного средства 1.

% Create the drivingScenario object and the two vehicles
[scenario, vehicle1, vehicle2] = createDrivingScenario;

% Create all the sensors
[sensors, numSensors, attachedVehicle] = createSensors(scenario);

% Create display
[f,plotters] = createV2VDisplay(scenario, sensors, attachedVehicle);

Следующий график погони рассматривается с точки зрения второго транспортного средства. В стреле указывается положение пешехода, который почти полностью закрыт припаркованными транспортными средствами и первым транспортным средством.

% Define each vehicle as a combination of an actor, sensors, a tracker, and plotters
v1 = struct('Actor', {vehicle1}, 'Sensors', {sensors(attachedVehicle==1)}, 'Tracker', {v1Tracker}, 'DetPlotter', {plotters.veh1DetPlotter}, 'TrkPlotter', {plotters.veh1TrkPlotter});
v2 = struct('Actor', {vehicle2}, 'Sensors', {sensors(attachedVehicle==2)}, 'Tracker', {{}}, 'DetPlotter', {{}}, 'TrkPlotter', {plotters.veh2TrkPlotter}); % No detections or tracker on Vehicle 2

Выполняйте симуляцию

Следующий код запускает симуляцию.

running = true;

% For repeatable results, set the random number seed
s = rng;
rng(2019)
snaptimes = [0.5, 2.8, 4.4, 6.3, inf];
snaps = cell(numel(snaptimes,1));
i = 1;
f.Visible = 'on';
while running && ishghandle(f)
    time  = scenario.SimulationTime;

    % Detect and track at the vehicle level
    [tracks1,wasTracker1Updated] = detectAndTrack(v1,time,posSelector);
    [tracks2,wasTracker2Updated] = detectAndTrack(v2,time,posSelector);

    % Keep the tracks from the previous fuser update
    oldFusedTracks1 = fusedTracks1;
    oldFusedTracks2 = fusedTracks2;

    % Update the fusers
    if wasTracker1Updated || wasFuser2Updated
        tracksToFuse1 = [tracks1;oldFusedTracks2];
        if isLocked(v1Fuser) || ~isempty(tracksToFuse1)
            [fusedTracks1,~,~,info1] = v1Fuser(tracksToFuse1,time);
            wasFuser1Updated = true;
            pos = getTrackPositions(fusedTracks1,posSelector);
            ids = string([fusedTracks1.TrackID]');
            plotTrack(plotters.veh1FusePlotter,pos,ids);
        else
            wasFuser1Updated = false;
            fusedTracks1 = objectTrack.empty(0,1);
        end
    else
        wasFuser1Updated = false;
        fusedTracks1 = objectTrack.empty(0,1);
    end
    if wasTracker2Updated || wasFuser1Updated
        tracksToFuse2 = [tracks2;oldFusedTracks1];
        if isLocked(v2Fuser) || ~isempty(tracksToFuse2)
            [fusedTracks2,~,~,info2] = v2Fuser(tracksToFuse2,time);
            wasFuser2Updated = true;
            pos = getTrackPositions(fusedTracks2,posSelector);
            ids = string([fusedTracks2.TrackID]');
            plotTrack(plotters.veh2FusePlotter,pos,ids);
        else
            wasFuser2Updated = false;
            fusedTracks2 = objectTrack.empty(0,1);
        end
    else
        wasFuser2Updated = false;
        fusedTracks2 = objectTrack.empty(0,1);
    end

    % Update the display
    updateV2VDisplay(plotters, scenario, sensors, attachedVehicle)

    % Advance the scenario one time-step and exit the loop if the scenario is complete
    running = advance(scenario);

    % Snap a shot at required times
    if time >= snaptimes(i)
        snaps{i} = getframe(f);
        i = i + 1;
    end
end

Figure contains 2 axes and other objects of type uipanel. Axes 1 contains 9 objects of type patch, line, text. These objects represent radar, vision, Detections, Local Tracks, Fuser Tracks. Axes 2 contains 7 objects of type patch, line, text. These objects represent radar, Local Tracks, Fuser Tracks.

Рисунок показывает сцену и результаты отслеживания в конце сценария. Последующие разделы этого примера анализируют результаты отслеживания в ключевые моменты времени.

Анализируйте отслеживание в начале симуляции

Когда симуляция начинается, транспортное средство 1 обнаруживает транспортные средства, припаркованный на правой стороне улицы. Затем трекер автомобиля 1 подтверждает дорожки, сопоставленные с припаркованными транспортными средствами и. В это время единственным объектом, обнаруженным и отслеживаемым трекером транспортного средства 2, является транспортное средство 1, которая находится непосредственно перед ней. Как только транспортное средство автомобиля 1 подтверждает дорожки, он транслирует их, и трек- фьюзер транспортного средства 2 запирает их. В результате транспортному средству 2 становится известно о припаркованных транспортных средствах, прежде чем он сможет обнаружить их самостоятельно.

showsnap(snaps, 1)

Figure Snap #1 contains an axes. The axes contains an object of type image.

Анализ отслеживания пешеходов на стороне улицы

Когда симуляция продолжается, транспортное средство 2 способно также обнаруживать и отслеживать транспортные средства, припаркованные у борта, и сплавлять их с дорожками, поступающими из транспортного средства 1. Транспортное средство 2 способно обнаруживать и отслеживать пешехода около 4 секунд в симуляции, а транспортное средство 2 запирает дорожку, связанную с пешеходом, около 4,4 секунд в симуляции (см. Снимок 2). Однако транспортное средство 2 занимает около двух секунд, прежде чем он сможет обнаружить и отследить пешехода с помощью собственных датчиков (см. Снимок 3). Эти две секунды могут оказать огромное влияние на безопасность пешехода, если он начнет пересекать улицу.

showsnap(snaps, 2)

Figure Snap #2 contains an axes. The axes contains an object of type image.

showsnap(snaps, 3)

Figure Snap #3 contains an axes. The axes contains an object of type image.

Избегание распространения слухов

Когда транспортные средства передают объекты, и эти объекты выходят из поля зрения, сросшиеся дорожки, связанные с этими объектами, отбрасываются обоими трекерами (см. Снимок 4). Падение дорожек демонстрирует, что слитые дорожки, транслируемые туда и обратно между двумя транспортными средствами, не используются для распространения слухов.

showsnap(snaps, 4)

Figure Snap #4 contains an axes. The axes contains an object of type image.

% Restart the driving scenario to return the actors to their initial positions.
restart(scenario);

% Release all the sensor objects so they can be used again.
for sensorIndex = 1:numSensors
    release(sensors{sensorIndex});
end

% Return the random seed to its previous value
rng(s)

Сводные данные

В этом примере вы увидели, как слияние треков в трек может улучшить ситуационную осведомленность и повысить безопасность в автомобильных приложениях. Вы видели, как настроить trackFuser выполнить слияние трека-трека и как определить источники как внутренние или внешние при помощи fuserSourceConfiguration объект. Делая это, вы избегаете распространения слухов и сохраняете только слитые дорожки, которые действительно наблюдаются каждым транспортным средством, чтобы быть обеспеченным.

Ссылки

[1] Bharanidhar Duraisamy, Tilo Schwartz, and Christian Wohler, «Track level fusion algoritms for automotive safety applications», 2013 International Conference on Signal Processing, Image Processing & Patticle Recognition, ionition, ience, iul.

Вспомогательные функции

createDrivingScenario

Создает сценарий вождения, заданный в приложении Driving Scenario Designer.

function [scenario, egoVehicle, secondVehicle] = createDrivingScenario
% Construct a drivingScenario object.
scenario = drivingScenario('SampleTime', 0.1);

% Add all road segments
roadCenters = [50.8 0.5 0; 253.4 1.5 0];
roadWidth = 12;
road(scenario, roadCenters, roadWidth);

roadCenters = [100.7 -100.6 0; 100.7 103.7 0];
road(scenario, roadCenters);

roadCenters = [201.1 -99.2 0; 199.7 99.5 0];
road(scenario, roadCenters);

% Add the ego vehicle
egoVehicle = vehicle(scenario, 'ClassID', 1, 'Position', [65.1 -0.9 0], 'PlotColor', [0 0.7410 0.4470]);
waypoints = [71 -0.5 0; 148.7 -0.5 0];
speed = 12;
trajectory(egoVehicle, waypoints, speed);

% Add the second vehicle
secondVehicle = vehicle(scenario, 'ClassID', 1, 'Position', [55.1 -0.9 0]);
waypoints = [61 -0.5 0; 138.7 -0.5 0];
speed = 12;
trajectory(secondVehicle, waypoints, speed);

% Add the parked cars
vehicle(scenario, 'ClassID', 1, 'Position', [111.0 -3.6 0]);
vehicle(scenario, 'ClassID', 1, 'Position', [140.6 -3.6 0]);
vehicle(scenario, 'ClassID', 1, 'Position', [182.6 -3.6 0]);
vehicle(scenario, 'ClassID', 1, 'Position', [211.3 -4.1 0]);

% Add pedestrian
actor(scenario, 'ClassID', 4, 'Length', 0.5, 'Width', 0.5, ...
    'Height', 1.7, 'Position', [130.3 -2.7 0], 'RCSPattern', [-8 -8;-8 -8]);

% Add parked truck
vehicle(scenario, 'ClassID', 2, 'Length', 8.2, 'Width', 2.5, ...
    'Height', 3.5, 'Position', [117.5 -3.5 0]);
end

createSensors

Создает датчики, используемые в сценарии, и приводит их вложения к транспортным средствам.

function [sensors, numSensors, attachedVehicle] = createSensors(scenario)
% createSensors Returns all sensor objects to generate detections
% Units used in createSensors and createDrivingScenario
% Distance/Position - meters
% Speed             - meters/second
% Angles            - degrees
% RCS Pattern       - dBsm

% Assign into each sensor the physical and radar profiles for all actors
profiles = actorProfiles(scenario);

% Vehicle 1 radar reports clustered detections
sensors{1} = radarDataGenerator('No scanning', 'SensorIndex', 1, 'UpdateRate', 10, ...
    'MountingLocation', [3.7 0 0.2], 'RangeLimits', [0 50], 'FieldOfView', [60 5], ...
    'RangeResolution', 2.5, 'AzimuthResolution', 4, ...
    'Profiles', profiles, 'HasOcclusion', true, 'HasFalseAlarms', false, ...
    'TargetReportFormat', 'Clustered detections');

% Vehicle 2 radar reports tracks
sensors{2} = radarDataGenerator('No scanning', 'SensorIndex', 2, 'UpdateRate', 10, ...
    'MountingLocation', [3.7 0 0.2], 'RangeLimits', [0 120], 'FieldOfView', [30 5], ...
    'RangeResolution', 2.5, 'AzimuthResolution', 4, ...
    'Profiles', profiles, 'HasOcclusion', true, 'HasFalseAlarms', false, ...
    'TargetReportFormat', 'Tracks', 'DeletionThreshold', [3 3]);

% Vehicle 1 vision sensor reports detections
sensors{3} = visionDetectionGenerator('SensorIndex', 3, ...
    'MaxRange', 100, 'SensorLocation', [1.9 0], 'DetectorOutput', 'Objects only', ...
    'ActorProfiles', profiles);
attachedVehicle = [1;2;1];
numSensors = numel(sensors);
end

scenarioToEgo

Выполняет преобразование координат из сценария в координаты ego.

trackInScenario имеет StateParameters, заданный для преобразования его из координат сценария в координаты ego.

Состояние использует модель постоянной скорости: [x; vx; y; vy; z; vz].

function 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);egoVelInScenario(3)];
stateInEgo = stateInScenario - stateShift;
trackInEgo = objectTrack('UpdateTime',trackInScenario.UpdateTime,'State',stateInEgo,'StateCovariance',trackInScenario.StateCovariance,'StateParameters',trackInScenario.StateParameters);
end

egoToScenario

Выполняет преобразование координат из ego в координаты сценария.

trackInEgo имеет StateParameters, заданный для преобразования его из координат ego в координаты сценария.

Состояние использует модель постоянной скорости: [x; vx; y; vy; z; vz].

function 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)];
stateInEgo = stateInScenario + stateShift;
trackInScenario = objectTrack('UpdateTime',trackInEgo.UpdateTime,'State',stateInEgo,'StateCovariance',trackInEgo.StateCovariance,'StateParameters',trackInEgo.StateParameters);
end

detectAndTrack

Эта функция используется для сбора всех обнаружений с датчиков в одном транспортном средстве и обновления трекера с их помощью.

Агент является структурой, которая содержит информацию актёра и датчики, трекер и необходимый плоттер для построения графиков обнаружений и дорожек транспортного средства.

function [tracks,wasTrackerUpdated] = detectAndTrack(agent,time,posSelector)
% Create detections from the vehicle
poses = targetPoses(agent.Actor);
[detections,isValid] = vehicleDetections(agent.Actor.Position,agent.Sensors,poses,time,agent.DetPlotter);

% Update the tracker to get tracks from sensors that reported detections
if isValid
    agent.Tracker.StateParameters = struct(...
        'Frame','Rectangular', ...
        'OriginPosition', agent.Actor.Position, ...
        'OriginVelocity', agent.Actor.Velocity);
    tracks = agent.Tracker(detections,time);
    tracksInScenario = tracks;
    for i = 1:numel(tracks)
        tracksInScenario(i) = egoToScenario(tracks(i));
    end
    pos = getTrackPositions(tracksInScenario,posSelector);
    plotTrack(agent.TrkPlotter,pos)
    wasTrackerUpdated = true;
else
    tracks = objectTrack.empty(0,1);
    wasTrackerUpdated = false;
end

% Get additional tracks from tracking sensors
[sensorTracks,wasSensorTrackerUpdated] = vehicleTracks(agent.Actor,agent.Sensors,poses,time,agent.TrkPlotter);
tracks = vertcat(tracks,sensorTracks);
wasTrackerUpdated = wasTrackerUpdated || wasSensorTrackerUpdated;
end

vehicleDetections

Собирает обнаружения со всех датчиков, присоединенных к этому транспортному средству, которые возвращают обнаружения.

function [objectDetections,isValid] = vehicleDetections(position, sensors, poses, time, plotter)
numSensors = numel(sensors);
objectDetections = {};
isValidTime = false(1, numSensors);

% Generate detections for each sensor
for sensorIndex = 1:numSensors
    sensor = sensors{sensorIndex};
    if isa(sensor, 'visionDetectionGenerator') || ~strcmpi(sensor.TargetReportFormat,'Tracks')
        [objectDets, ~, sensorConfig] = sensor(poses, time);
        if islogical(sensorConfig)
            isValidTime(sensorIndex) = sensorConfig;
        else
            isValidTime(sensorIndex) = sensorConfig.IsValidTime;
        end
        objectDets = cellfun(@(d) setAtt(d), objectDets, 'UniformOutput', false);
        numObjects = numel(objectDets);
        objectDetections = [objectDetections; objectDets(1:numObjects)]; %#ok<AGROW>
    end
end
isValid = any(isValidTime);

% Plot detections
if numel(objectDetections)>0
    detPos = cellfun(@(d)d.Measurement(1:2), objectDetections, 'UniformOutput', false);
    detPos = cell2mat(detPos')' + position(1:2);
    plotDetection(plotter, detPos);
end
end

function d = setAtt(d)
% Set the attributes to be struct
d.ObjectAttributes = struct;
% Keep only the position measurement and remove velocity
if numel(d.Measurement)==6
    d.Measurement = d.Measurement(1:3);
    d.MeasurementNoise = d.MeasurementNoise(1:3,1:3);
    d.MeasurementParameters{1}.HasVelocity = false;
end
end

vehicleTracks

Собирает все дорожки с датчиков, которые сообщают о дорожках на транспортном средстве.

function [tracks,wasTrackerUpdated] = vehicleTracks(actor, sensors, poses, time, plotter)
% Create detections from the vehicle
numSensors = numel(sensors);
tracks = objectTrack.empty;
isValidTime = false(1, numSensors);

% Generate detections for each sensor
for sensorIndex = 1:numSensors
    sensor = sensors{sensorIndex};
    if isa(sensor, 'radarDataGenerator') && strcmpi(sensor.TargetReportFormat,'Tracks')
        [sensorTracks, ~, sensorConfig] = sensor(poses, time);
        if islogical(sensorConfig)
            isValidTime(sensorIndex) = sensorConfig;
        else
            isValidTime(sensorIndex) = sensorConfig.IsValidTime;
        end
        numObjects = numel(sensorTracks);
        tracks = [tracks; sensorTracks(1:numObjects)]; %#ok<AGROW>
    end
end
wasTrackerUpdated = any(isValidTime);

if ~wasTrackerUpdated % No vehicle tracking sensor udpated
    return
end

% Add vehicle position and velocity to track state parameters
for i = 1:numel(tracks)
    tracks(i).StateParameters.OriginPosition = tracks(i).StateParameters.OriginPosition + actor.Position';
    tracks(i).StateParameters.OriginVelocity = tracks(i).StateParameters.OriginVelocity + actor.Velocity';
end

% Plot tracks
if numel(tracks)>0
    trPos = arrayfun(@(t)t.State([1,3]), tracks, 'UniformOutput', false);
    trPos = cell2mat(trPos')' + actor.Position(1:2);
    plotTrack(plotter, trPos);
end
end