Отследите цели точек в плотном загромождении с помощью GM-PHD Tracker

В этом примере показано, как отслеживать точки цели в плотном загромождении с помощью Гауссова гипотезы о вероятности смеси (GM-PHD) трекер с использованием модели постоянной скорости.

Setup

Сценарий, используемый в этом примере, создается с помощью trackingScenario. Сценарий состоит из пяти точечных целей, движущихся с постоянной скоростью. Цели перемещаются в пределах поля зрения статического 2-D радарного датчика. Вы используете monostaticRadarSensor для симуляции датчика 2-D и монтажа его на статической платформе. Вы используете FalseAlarmRate свойство датчика контролировать плотность загромождения. Значение FalseAlarmRate свойство представляет вероятность генерации ложного предупреждения в одной камере разрешения датчика. На основе частоты ложных предупреждений 10-3и разрешение датчика, заданное в этом примере, составляет приблизительно 48 ложных предупреждений, сгенерированных на шаг.

% Reproducible target locations
rng(2022);

% Create a trackingScenario object
scene = trackingScenario('UpdateRate',10,'StopTime',10);
numTgts = 5;

% Initialize position and velocity of each target
x = 100*(2*rand(numTgts,1) - 1);
y = 100*(2*rand(numTgts,1) - 1);
z = zeros(numTgts,1);
vx = 5*randn(numTgts,1);
vy = 5*randn(numTgts,1);
vz = zeros(numTgts,1);

% Add platforms to scenario with given positions and velocities.
for i = 1:numTgts
    thisTgt = platform(scene);
    thisTgt.Trajectory.Position = [x(i) y(i) z(i)];
    thisTgt.Trajectory.Velocity = [vx(i) vy(i) vz(i)];
end

% Add a detecting platform to the scene.
detectingPlatform = platform(scene);
detectingPlatform.Trajectory.Position = [-200 0 0];

% Simulate 2-D radar using a monostaticRadarSensor.
radar = monostaticRadarSensor(1,...
    'UpdateRate',scene.UpdateRate,...
    'DetectionProbability',0.9,...% Pd
    'FalseAlarmRate',1e-3,...% Pfa
    'FieldOfView',[120 1],...
    'ScanMode','No Scanning',...
    'DetectionCoordinates','scenario',...% Report in scenario frame
    'HasINS',true,...                    % Enable INS to report in scenario frame
    'ReferenceRange',300,...             % Short-range
    'ReferenceRCS',10,...                % Default RCS of platforms
    'MaxUnambiguousRange',400,...        % Short-range
    'RangeResolution',1,...
    'AzimuthResolution',1,...
    'HasFalseAlarms',true);              % Reports false alarms

% Mount the radar on the detecting platform.
detectingPlatform.Sensors = radar;

Настройте трекер и метрики

Шпион

Вы используете трекер объектов точек GM-PHD для отслеживания целей. Первым шагом к настройке PHD-трекера является настройка строения датчика. Вы определяете строение с помощью trackingSensorConfiguration объект.

The SensorIndex строения устанавливается равным 1, чтобы соответствовать конфигурации моделируемого датчика. Поскольку датчик является датчиком объекта точки, который выводит самое большее одно обнаружение на объект в каждом скане, вы устанавливаете MaxNumDetsPerObject свойство строения, равное 1.

The SensorTransformFcn, SensorTransformParameters, и SensorLimits вместе позволяют вам задать область, в которой дорожки могут быть обнаружены датчиком. The SensorTransformFcn определяет преобразование состояния дорожки (xtrack) в промежуточное пространство, используемое датчиком (xsensor) для определения обнаруживаемости дорожек. Общий расчет для вычисления вероятности обнаружения показан ниже:

xsensor=SensorTransformFcn(xtrack,SensorTransformParameters)

Pd=

{Configuration.DetectionProbabilitySensorLimits(:,1)xsensorSensorLimits(:,2)Configuration.MinDetectionProbabilityotherwise

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

Заметьте, что подпись SensorTransformFcn аналогичен типовой модели измерения. Поэтому можно использовать такие функции, как cvmeas, cameas как SensorTransformFcn. В этом примере вы предполагаете, что все дорожки являются обнаруживаемыми. Поэтому SensorTransformFcn определяется как @(x,params)x и SensorLimits определяются как [-inf inf] для всех состояний.

% Transform function and limits
sensorTransformFcn = @(x,params)x;
sensorTransformParameters = struct;
sensorLimits = [-inf inf].*ones(6,1);

% Detection probability for sensor configuration
Pd = radar.DetectionProbability;

config = trackingSensorConfiguration('SensorIndex',1,...
    'IsValidTime',true,...% Update every step
    'MaxNumDetsPerObject',1,...
    'SensorTransformFcn',sensorTransformFcn,...
    'SensorTransformParameters',sensorTransformParameters,...
    'SensorLimits',sensorLimits,...
    'DetectionProbability',Pd);

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

% Sensor Parameters to calculate Volume of the resolution bin
Rm = radar.MaxUnambiguousRange/2; % mean -range
dTheta = radar.ElevationResolution;
% Bias fractions reduce the "effective" resolution size
dPhi = radar.AzimuthBiasFraction*radar.AzimuthResolution;
dR = radar.RangeBiasFraction*radar.RangeResolution;

% Cell volume
VCell = 2*((Rm+dR)^3 - Rm^3)/3*(sind(dTheta/2))*deg2rad(dPhi);

% False alarm rate 
Pfa = radar.FalseAlarmRate;

% Define clutter density
config.ClutterDensity = Pfa/VCell;

Вы также задаете FilterInitializationFcn для определения типа фильтра и распределения компонентов в фильтре, инициализированных этим датчиком. В этом примере вы устанавливаете FilterInitializationFcn на initcvgmphd, который создает фильтр GM-PHD с постоянной скоростью и добавляет 1 компонент на обнаружение низкой вероятности от трекера. The initcvgmphd не добавляет компонент при вызове без обнаружения. Это означает, что при этом строении компоненты рождения добавляются к фильтру только тогда, когда обнаружения выпадают из AssignmentThreshold multi-target filer. См. A ssignmentThresholdсвойство trackerPHDдля получения дополнительной информации.

config.FilterInitializationFcn = @initcvgmphd;

Далее вы создаете трекер с помощью этого строения с помощью trackerPHD Системные object™. При конфигурировании трекера вы задаете BirthRate свойство для определения количества целевых объектов, появляющихся в поле зрения, за модуль времени. The FilterInitializationFcn используемый с строением, добавляет по одному компоненту на неназначенное обнаружение. На каждом временном шаге можно ожидать, что количество компонентов будет примерно равно количеству ложных предупреждений и новых целей. Трекер распределяет BirthRate ко всем этим компонентам равномерно.

% Use number of radar cells to compute number of false alarms per unit time.
NCells = radar.MaxUnambiguousRange/radar.RangeResolution*radar.FieldOfView(1)/radar.AzimuthResolution;
numFalse = Pfa*NCells;

% Choose an initial weight of 0.05 for each new component. As number of new
% targets is not known, new number of components are simply used as number
% of false alarms. 0.1 is the update rate.
birthRate = 0.05*(numFalse)/0.1;

% Create a tracker with the defined sensor configuration.
tracker = trackerPHD('BirthRate',birthRate,...
    'SensorConfigurations', config);

Метрики

Чтобы оценить эффективность трекера, вы также настроили метрику для оценки эффективности. В этом примере вы используете метрику Обобщённый оптимальный подшаблон (GOSPA). Метрика GOSPA призвана оценить эффективность трекера путем присвоения ему единого значения затрат. Чем лучше эффективность отслеживания, тем меньше стоимость GOSPA. Значение нуля представляет идеальное отслеживание.

% Create gospa metric object.
gospa = trackGOSPAMetric;

% Initialize variable for storing metric at each step.
gospaMetric = zeros(0,1);
loc = zeros(0,1);
mt = zeros(0,1);
ft = zeros(0,1);

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

Далее вы продвигаете сценарий, собираете обнаружения из сценария и запускаете PHD-трекер на моделируемых обнаружениях.

% Create a display
display = helperClutterTrackingDisplay(scene);

count = 1; % Counter for storing metric data
rng(2018); % Reproducible run

while advance(scene)
    % Current time
    time = scene.SimulationTime;
    
    % Current detections
    detections = detect(scene);
    
    % Tracks
    tracks = tracker(detections, time);
    
    % Update display
    display(scene, detections, tracks);
    
    % Compute GOSPA. getTruth function is defined below.
    truths = getTruth(scene);
    [~,gospaMetric(count),~,loc(count),mt(count),ft(count)] = gospa(tracks, truths);
    count = count + 1;
end

Можно визуализировать, что все цели были отслежены трекером PHD в этом сценарии. Это также может быть количественно оценено с использованием метрики GOSPA и связанных компонентов. На рисунке ниже заметьте, что метрика GOSPA снижается через несколько шагов. Начальное значение метрики GOSPA выше из-за задержки установления для каждой дорожки.

figure('Units','normalized','Position',[0.1 0.1 0.8 0.8])
subplot(2,2,[1 2]); plot(gospaMetric,'LineWidth',2); title('Total GOSPA');
ylabel('GOSPA Metric'); xlabel('Time step'); grid on;
subplot(2,2,3); plot(mt,'LineWidth',2); title('Missed Target GOSPA');
ylabel('Missed Target Metric'); xlabel('Time step'); grid on;
subplot(2,2,4); plot(ft,'LineWidth',2); title('False Track GOSPA');
ylabel('False Target Metric'); xlabel('Time step'); grid on;

Анализ эффективности

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

В этом разделе вы запускаете различные реализации сценария и трекера с различными частотой ложных предупреждений и вычисляете среднее значение GOSPA системы для каждой реализации. Процесс запуска сценария и вычисления среднего значения GOSPA для системы заворачивается внутрь вспомогательной функции helperRunMonteCarloAnalysis .Чтобы ускорить симуляции Монте-Карло, можно сгенерировать код для monostaticRadarSensor модель, а также trackerPHD использование MATLAB ® Coder™ Toolbox. Процесс генерации кода переносится внутрь вспомогательной функции helperGenerateCode. Чтобы сгенерировать код для алгоритма, вы собираете код в автономную функцию. Эта функция названа clutterSimTracker_kernel в этом примере. The clutterSimTracker_kernel функция записывается для поддержки четырех частот ложных предупреждений. Для регенерации кода с различными скоростями ложных предупреждений можно использовать следующую команду.

Pfas = 10.^(-4,-3,4); % Choose your false alarm settings
helperGenerateCode(scene, Pfas); % Generate code

Чтобы перегенерировать код для дополнительных настроек ложных предупреждений, можно изменить функции, включив в них более постоянные переменные. Для получения дополнительной информации о том, как сгенерировать код для System objects™, смотрите пример Как сгенерировать код С для трекера.

The helperRunMonteCarloAnalysis функция использует parfor чтобы выполнить каждый запуск Монте-Карло. Если у вас есть лицензия Parallel Computing Toolbox™, запуски Monte Carlo могут быть распределены между несколькими работниками, чтобы еще больше ускорить симуляции.

% Turn on flag to run Monte Carlo Simulations
Pfas = 10.^linspace(-4,-3,4);
runMonteCarlo = false;
if runMonteCarlo
    numRunsPerPfa = 50; %#ok<UNRCH> 
    gospaMCs = zeros(4,numRunsPerPfa,4);
    for i = 1:4
        gospaMCs(i,:,:) = helperRunMonteCarloAnalysis(scene, Pfas, Pfas(i), numRunsPerPfa);
    end
    save clutterTrackingMCRuns.mat gospaMCs;
else 
    % Reload results from last run
    load('clutterTrackingMCRuns.mat','gospaMCs');
end

% Plot results
figure('Units','normalized','Position',[0.1 0.1 0.8 0.8])
subplot(2,2,[1 2]); plot(gospaMCs(:,:,1)','LineWidth',2); title('GOSPA');
legend(strcat('Pfa = ',string(Pfas)),'Orientation','horizontal','Location','NorthOutside');
ylabel('Average GOSPA Metric'); xlabel('Monte Carlo Run'); grid on;
subplot(2,2,3); plot(gospaMCs(:,:,3)','LineWidth',2); title('Missed Target GOSPA');
ylabel('Average Missed Target Metric'); xlabel('Monte Carlo Run'); grid on;
subplot(2,2,4); plot(gospaMCs(:,:,4)','LineWidth',2); title('False Track GOSPA');
ylabel('Average False Track Metric'); xlabel('Monte Carlo Run'); grid on;

Графики выше показывают эффективность трекера в этом сценарии, запустив 50 реализаций Монте-Карло для каждой частоты ложных предупреждений. Когда частота ложных предупреждений увеличивается, вероятность генерации ложного трека увеличивается. Эта вероятность даже выше в окрестностях датчика, где плотность камер разрешения намного выше. Поскольку ложные предупреждения тесно разнесены и часто появляются в этой области, они могут быть неправильно классифицированы как низкоскоростная ложная дорожка. Такое поведение трекера можно наблюдать в усредненном «False Track Component» метрики GOSPA на запуск сценария. Заметьте, что когда частота ложных предупреждений увеличивается, количество peaks на графике также увеличивается. Это также вызывает увеличение общей метрики GOSPA. «Пропущенный целевой компонент» равен нулю для всех, кроме одного запуска. Этот тип события вызван множественными промахами цели датчиком.

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

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

Служебные функции

helperRunMonteCarloAnalysis

function gospaMC = helperRunMonteCarloAnalysis(scene, Pfas, Pfai, numRuns)

clear clutterSimTracker_kernel;

% Compute which tracker to run based on provided Pfa
settingToRun = find(Pfas == Pfai,1,'first');

% Initialize ospa for each Monte Carlo run
gospaMC = zeros(numRuns,4);

% Use parfor for parallel simulations
parfor i = 1:numRuns
    rng(i, 'twister');
    
    % Restart scenario before each run
    restart(scene);
    
    % metrics vs time in this scenario
    gospaMetric = zeros(0,4);
    
    % Counter
    count = 0;
    
    % Advance scene and run
    while advance(scene)
        count = count + 1;
        
        % Use radar sensor using targetPoses function
        own = scene.Platforms{end};
        tgtPoses = targetPoses(own,'rotmat');
        insPose = pose(own);
        poses = platformPoses(scene,'rotmat');
        truths = poses(1:end-1);
        time = scene.SimulationTime;
        
        % Reset tracker at the end of step so at the next call tracker is
        % reset to time 0.
        systemToReset = settingToRun*(abs(time - scene.StopTime) < 1e-3);
        
        % Store ospa metric. Tracks and detections can be outputted to run
        % scenario in code generation without needing Monte Carlo runs.
        [~,~,gospaMetric(count,:)] = clutterSimTracker_kernel(Pfas, tgtPoses, insPose, truths, time, settingToRun, systemToReset);
    end
    
    % Compute average of GOSPA in this run
    % Start from time step 20 to allow track establishment.
    gospaMC(i,:) = mean(gospaMetric(20:end,:));
end

end

helperGenerateCode

function helperGenerateCode(scene,Pfas) %#ok<DEFNU>

% Generate sample pose using platformPoses
poses = platformPoses(scene,'rotmat');

% Generate sample inputs for the kernel function
%
% Pfas must be compile-time constant and they cannot change with time
Pfas = coder.Constant(Pfas);

% Target poses as a variable size arrray of max 20 elements
tgtPoses = coder.typeof(poses(1),[20 1],[1 0]);

% Scalar ins pose
insPose = pose(scene.Platforms{1},'true');

% Truth information with maximum 20 targets
truths = coder.typeof(poses(1),[20 1],[1 0]);

% Time
time = 0;

% Which false-alarm setting to run and which to reset. Reset is necessary
% after each run to reinitialize the tracker
systemToRun = 1;
systemToReset = 1;

inputs = {Pfas, tgtPoses, insPose, truths, time, systemToRun, systemToReset}; %#ok<NASGU>

% Same name as MATLAB file allows to shadow the MATLAB function when
% MEX file is available and execute code in MEX automatically.
codegen clutterSimTracker_kernel -args inputs -o clutterSimTracker_kernel;

end

getTruth

function truths = getTruth(scenario)
platPoses = platformPoses(scenario); % True Information
truths = platPoses(1:end-1); % Last object is ownship
end

clutterSimTracker_kernel

Эта функция определяется во внешнем файле с именем clutterSimTracker_kernel, доступный в той же рабочей папке, что и этот скрипт.

function [detections, tracks, ospaMetric] = clutterSimTracker_kernel(Pfas, tgtPoses, insPose, truths, time, systemToRun, systemToReset)

assert(numel(Pfas) == 4,'Only 4 false alarm settings supported. Rewrite more persistent variables to add more settings');

persistent tracker1 tracker2 tracker3 tracker4 ...
    radar1 radar2 radar3 radar4 ....
    reset1 reset2 reset3 reset4 ....
    gospa

if isempty(gospa) || isempty(reset1) || isempty(reset2) || isempty(reset3) || isempty(reset4)
    gospa = trackGOSPAMetric('CutoffDistance',50);
end

if isempty(tracker1) || isempty(radar1) || isempty(reset1)
    tracker1 = setupTracker(Pfas(1));
    radar1 = setupRadar(Pfas(1));
    reset1 = zeros(1,1);
end

if isempty(tracker2) || isempty(radar2) || isempty(reset2)
    tracker2 = setupTracker(Pfas(2));
    radar2 = setupRadar(Pfas(2));
    reset2 = zeros(1,1);
end

if isempty(tracker3) || isempty(radar3) || isempty(reset3)
    tracker3 = setupTracker(Pfas(3));
    radar3 = setupRadar(Pfas(3));
    reset3 = zeros(1,1);
end

if isempty(tracker4) || isempty(radar4) || isempty(reset4)
    tracker4 = setupTracker(Pfas(4));
    radar4 = setupRadar(Pfas(4));
    reset4 = zeros(1,1);
end

switch systemToRun
    case 1
        detections = radar1(tgtPoses, insPose, time);
        tracks = tracker1(detections, time);
    case 2
        detections = radar2(tgtPoses, insPose, time);
        tracks = tracker2(detections, time);
    case 3
        detections = radar3(tgtPoses, insPose, time);
        tracks = tracker3(detections, time);
    case 4
        detections = radar4(tgtPoses, insPose, time);
        tracks = tracker4(detections, time);
    otherwise
        error('Idx out of bounds');
end

[~,gp,~,loc,mT,fT] = gospa(tracks, truths);

ospaMetric = [gp loc mT fT];

switch systemToReset
    case 1
        reset1 = zeros(0,1);
    case 2
        reset2 = zeros(0,1);
    case 3
        reset3 = zeros(0,1);
    case 4
        reset4 = zeros(0,1);
end

end

function tracker = setupTracker(Pfa)
Pd = 0.9;
VCell = 0.0609; % Inlined value of cell volume;
Kc = Pfa/VCell; % Clutter density

% Birth rate
birthRate = 0.05*(5 + Pfa*48000)/0.1;

% Transform function and limits
sensorTransformFcn = @(x,params)x;
sensorTransformParameters = struct;
sensorLimits = bsxfun(@times,[-inf inf],ones(6,1));

% Assemble information into a trackingSensorConfiguration
config = trackingSensorConfiguration('SensorIndex',1,...
    'IsValidTime',true,...% Update every step
    'DetectionProbability',Pd,...% Detection Probability of detectable states
    'ClutterDensity',Kc,...% Clutter Density
    'SensorTransformFcn',sensorTransformFcn,...
    'SensorTransformParameters',sensorTransformParameters,...
    'SensorLimits',sensorLimits,...
    'MaxNumDetsPerObject',1,...
    'FilterInitializationFcn',@initcvgmphd);

tracker = trackerPHD('SensorConfigurations', config,...
    'BirthRate',birthRate);

end

function radar = setupRadar(Pfa)
Pd = 0.9;
radar = monostaticRadarSensor(1,...
    'UpdateRate',10,...
    'DetectionProbability',Pd,...
    'FalseAlarmRate',Pfa,...
    'FieldOfView',[120 1],...
    'ScanMode','No Scanning',...
    'DetectionCoordinates','Scenario',...% Report in scenario frame
    'HasINS',true,...% Enable INS to report in scenario frame
    'ReferenceRange',300,...% Short-range
    'ReferenceRCS',10,...
    'MaxUnambiguousRange',400,...% Short-range
    'RangeResolution',1,...
    'AzimuthResolution',1,...
    'HasFalseAlarms',true);
end