Управление воздушным движением

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

Сценарий управления воздушным движением

Симулируйте башню управления воздушным движением (УВД) и движущиеся цели в сценарии как платформы. Симуляция движения платформ в сценарии управляется trackingScenario.

Создайте trackingScenario и добавьте башню УВД к сценарию.

% Create tracking scenario
scenario = trackingScenario;

% Add a stationary platform to model the ATC tower
tower = platform(scenario);

Радар наблюдения за аэропортом

Добавьте радар наблюдения аэропорта (ASR) к башне УВД. Типичная башня УВД имеет установленный в 15 метрах над землей радар. Это радиолокационные обзоры механически по азимуту с фиксированной скоростью для обеспечения покрытия 360 степеней в непосредственной близости от башни УВД. Общие спецификации для ASR перечислены:

  • Чувствительность: 0 дБсм при 111 км

  • Механический скан: Только азимут

  • Скорость механического скана: 12.5 RPM

  • Электронный скан: Нет

  • Поле зрения: азимут 1,4 град, повышение 10 град

  • Азимут Разрешение: 1.4 град

  • Разрешение в области значений: 135 м

Моделируйте ASR с вышеописанными спецификациями, используя monostaticRadarSensor.

rpm = 12.5;
fov = [1.4;10];
scanrate = rpm*360/60;  % deg/s
updaterate = scanrate/fov(1); % Hz

radar = monostaticRadarSensor(1, 'Rotator', ...
    'UpdateRate', updaterate, ...           % Hz
    'FieldOfView', fov, ...                 % [az;el] deg
    'MaxMechanicalScanRate', scanrate, ...  % deg/sec
    'AzimuthResolution', fov(1), ...        % deg
    'ReferenceRange', 111e3, ...            % m
    'ReferenceRCS', 0, ...                  % dBsm
    'RangeResolution', 135, ...             % m
    'HasINS', true, ...
    'DetectionCoordinates', 'Scenario');

% Mount radar at the top of the tower
radar.MountingLocation = [0 0 -15];
tower.Sensors = radar;

Наклоните радар так, чтобы он исследовал область, начинающуюся на 2 степени над горизонтом. Для этого включите повышение и установите пределы механического скана, чтобы охватить поле зрения повышения, начиная с 2 степеней над горизонтом. Потому что trackingScenario использует координатную систему координат NED, отрицательные повышения соответствуют точкам над горизонтом.

% Enable elevation scanning
radar.HasElevation = true;

% Set mechanical elevation scan to begin at 2 degrees above the horizon
elFov = fov(2);
tilt = 2; % deg
radar.MechanicalScanLimits(2,:) = [-fov(2) 0]-tilt; % deg

Установите значение поля зрения по повышению немного больше, чем повышение, охватываемое пределами скана. Это препятствует растровому сканированию на повышении и наклоняет радар к точке в середине пределов скана повышения.

radar.FieldOfView(2) = elFov+1e-3;

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

Добавьте три лайнера в секторе управления УВД. Один лайнер приближается к УВД с большой области значений, другой отправляется, а третий летит тангенциально к башне. Моделируйте движение этих лайнеров на 60-секундном интервале.

trackingScenario использует координатную систему координат NED. При определении путевых точек для лайнеров ниже координата z соответствует понижению, поэтому высоты над землей устанавливаются на отрицательные значения.

% Duration of scenario
sceneDuration = 60; % s

% Inbound airliner
ht = 3e3;
spd = 900*1e3/3600; % m/s
wp = [-5e3 -40e3 -ht;-5e3 -40e3+spd*sceneDuration -ht];
traj = waypointTrajectory('Waypoints',wp,'TimeOfArrival',[0 sceneDuration]);
platform(scenario,'Trajectory', traj);

% Outbound airliner
ht = 4e3;
spd = 700*1e3/3600; % m/s
wp = [20e3 10e3 -ht;20e3+spd*sceneDuration 10e3 -ht];
traj = waypointTrajectory('Waypoints',wp,'TimeOfArrival',[0 sceneDuration]);
platform(scenario,'Trajectory', traj);

% Tangential airliner
ht = 4e3;
spd = 300*1e3/3600; % m/s
wp = [-20e3 -spd*sceneDuration/2 -ht;-20e3 spd*sceneDuration/2 -ht];
traj = waypointTrajectory('Waypoints',wp,'TimeOfArrival',[0 sceneDuration]);
platform(scenario,'Trajectory', traj);

GNN-трекер

Создайте trackerGNN для формирования дорожек от радиолокационных обнаружений, сгенерированных тремя лайнерами. Обновите трекер с обнаружениями, сгенерированными после завершения полного 360 степеней скана по азимуту.

Трекер использует initFilter поддерживающая функция для инициализации расширенного фильтра Калмана с постоянной скоростью для каждой новой дорожки. initFilter изменяет фильтр, возвращенный initcvekf для соответствия целевым скоростям и интервалу обновления трекера.

tracker = trackerGNN( ...
    'Assignment', 'Auction', ...
    'AssignmentThreshold',50, ...
    'FilterInitializationFcn',@initFilter);

Визуализация на карте

Вы используете helperATCMap для визуализации результатов на верхнюю часть отображения карты. Вы позиционируете источник локальной системы координат North-East-Down (NED), используемой радаром и трекером башни, на позиции аэропорта Логан в Бостоне. Источник расположен на 42.36306 широты и -71.00639 долготы и 50 метрах над уровнем моря. Помощник предоставляет необходимые утилиты для преобразования координат из NED в ориентированную на Землю координатную систему координат, используемую картой.

origin = [42.366978, -71.022362, 50];
mapViewer = helperATCMap('ReferenceLocation',origin);
setCamera(mapViewer, origin + [0 0 1e5]);
showScenario(mapViewer,scenario);
snap(mapViewer);

Моделирование и отслеживание лайнеров

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

% Set simulation to advance at the update rate of the radar
scenario.UpdateRate = radar.UpdateRate;

% Create a buffer to collect the detections from a full scan of the radar
scanBuffer = {};

% Initialize the track array
tracks = [];

% Save visualization snapshots for each scan
allsnaps = {};
scanCount = 0;

% Set random seed for repeatable results
s = rng;
rng(2020)

while advance(scenario)
    
    % Update airliner positions
    plotTarget(mapViewer, scenario.Platforms([2 3 4]));
    
    % Generate detections on targets in the radar's current field of view
    [dets,config] = detect(scenario);
    scanBuffer = [scanBuffer;dets]; %#ok<AGROW>
    % Plot beam and detections
    plotCoverage(mapViewer,coverageConfig(scenario))
    plotDetection(mapViewer,scanBuffer);
    
    
    % Update tracks when a 360 degree scan is complete
    simTime = scenario.SimulationTime;
    isScanDone = config.IsScanDone;
    if isScanDone
        scanCount = scanCount+1;
        % Update tracker
        [tracks,~,~,info] = tracker(scanBuffer,simTime);
        % Clear scan buffer for next scan
        scanBuffer = {};
    elseif isLocked(tracker)
        % Predict tracks to the current simulation time
        tracks = predictTracksToTime(tracker,'confirmed',simTime);
    end
    
    % Update map and take snapshots
    allsnaps = snapPlotTrack(mapViewer,tracks,isScanDone, scanCount, allsnaps);

end
allsnaps = [allsnaps, {snap(mapViewer)}];

Отображение первого снимка, сделанного по завершении второго скана радара.

figure
imshow(allsnaps{1});

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

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

figure
imshow(allsnaps{2});

figure
imshow(allsnaps{3});

Предыдущие рисунки показывают изображение дорожки до и сразу после обновления трекера после второго скана радара. Обнаружение на рисунке перед обновлением трекера используется для обновления и подтверждения инициализированной дорожки от обнаружения предыдущего скана для этого лайнера. Следующий рисунок показывает положение и скорость подтвержденного трека. Неопределенность оценки положения дорожки показана как серый эллипс. После всего двух обнаружений трекер установил точную оценку положения и скорости исходящего авиалайнера. Истинная высота лайнера составляет 4 км, и он движется на восток со скоростью 700 км/ч.

figure
imshow(allsnaps{4});

figure
imshow(allsnaps{5});

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

figure
imshow(allsnaps{6});

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

truthTrackTable = tabulateData(scenario, tracks) %#ok<NOPTS>
truthTrackTable=3×4 table
    TrackID        Altitude              Heading               Speed      
               True    Estimated    True    Estimated    True    Estimated
    _______    _________________    _________________    _________________

     "T1"      4000      3874        90         89       700        710   
     "T2"      4000      3977         0        358       300        293   
     "T3"      3000      3077         0          0       900        899   

Визуализируйте дорожки в 3D, чтобы получить лучшее представление о предполагаемых высотах.

% Reposition and orient the camera to show the 3-D nature of the map
camPosition = origin + [0.367, 0.495, 1.5e4];
camOrientation = [0, -17, 235]; %Looking south west, 17 degrees below the horizon
setCamera(mapViewer, camPosition, camOrientation);

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

Для получения различных видов сцены можно использовать следующие элементы управления на карте:

  • Чтобы панорамировать карту, вы левее кликните мышью и перетащите карту.

  • Чтобы повернуть карту, удерживая кнопку ctrl, вы левее кликните мышью и перетащите карту.

  • Чтобы масштабировать карту и уменьшить ее, вы используете колесо прокрутки мыши.

snap(mapViewer);

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

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

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

initFilter

Эта функция изменяет функцию initcvekf для обработки целей более высокой скорости, таких как лайнеры в сценарии УВД.

function filter = initFilter(detection)
filter = initcvekf(detection);
classToUse = class(filter.StateCovariance);

% Airliners can move at speeds around 900 km/h. The velocity is
% initialized to 0, but will need to be able to quickly adapt to
% aircraft moving at these speeds. Use 900 km/h as 1 standard deviation
% for the initialized track's velocity noise.
spd = 900*1e3/3600; % m/s
velCov = cast(spd^2,classToUse);
cov = filter.StateCovariance;
cov(2,2) = velCov;
cov(4,4) = velCov;
filter.StateCovariance = cov;

% Set filter's process noise to match filter's update rate
scaleAccelHorz = cast(1,classToUse);
scaleAccelVert = cast(1,classToUse);
Q = blkdiag(scaleAccelHorz^2, scaleAccelHorz^2, scaleAccelVert^2);
filter.ProcessNoise = Q;
end

tabulateData

Эта функция возвращает таблицу, сравнивающую основную истину и треки

function truthTrackTable = tabulateData(scenario, tracks)
% Process truth data
platforms = scenario.Platforms(2:end); % Platform 1 is the radar
numPlats = numel(platforms);
trueAlt = zeros(numPlats,1);
trueSpd = zeros(numPlats,1);
trueHea = zeros(numPlats,1);
for i = 1:numPlats
    traj = platforms{i}.Trajectory;
    waypoints = traj.Waypoints;
    times = traj.TimeOfArrival;
    trueAlt(i) = -waypoints(end,3);
    trueVel = (waypoints(end,:) - waypoints(end-1,:)) / (times(end)-times(end-1));
    trueSpd(i) = norm(trueVel) * 3600 / 1000; % Convert to km/h
    trueHea(i) = atan2d(trueVel(1),trueVel(2));
end
trueHea = mod(trueHea,360);

% Associate tracks with targets
atts = [tracks.ObjectAttributes];
tgtInds = [atts.TargetIndex];

% Process tracks assuming a constant velocity model
numTrks = numel(tracks);
estAlt = zeros(numTrks,1);
estSpd = zeros(numTrks,1);
estHea = zeros(numTrks,1);
truthTrack = zeros(numTrks,7);
for i = 1:numTrks
    estAlt(i) = -round(tracks(i).State(5));
    estSpd(i) = round(norm(tracks(i).State(2:2:6)) * 3600 / 1000); % Convert to km/h;
    estHea(i) = round(atan2d(tracks(i).State(2),tracks(i).State(4)));
    estHea(i) = mod(estHea(i),360);
    platID = tgtInds(i);
    platInd = platID - 1;
    truthTrack(i,:) = [tracks(i).TrackID, trueAlt(platInd), estAlt(i), trueHea(platInd), estHea(i), ...
        trueSpd(platInd), estSpd(i)];
end

% Organize the data in a table
names = {'TrackID','TrueAlt','EstimatedAlt','TrueHea','EstimatedHea','TrueSpd','EstimatedSpd'};
truthTrackTable = array2table(truthTrack,'VariableNames',names);
truthTrackTable = mergevars(truthTrackTable, (6:7), 'NewVariableName', 'Speed', 'MergeAsTable', true);
truthTrackTable.(6).Properties.VariableNames = {'True','Estimated'};
truthTrackTable = mergevars(truthTrackTable, (4:5), 'NewVariableName', 'Heading', 'MergeAsTable', true);
truthTrackTable.(4).Properties.VariableNames = {'True','Estimated'};
truthTrackTable = mergevars(truthTrackTable, (2:3), 'NewVariableName', 'Altitude', 'MergeAsTable', true);
truthTrackTable.(2).Properties.VariableNames = {'True','Estimated'};
truthTrackTable.TrackID = "T" + string(truthTrackTable.TrackID);
end

snapPlotTrack

Эта функция обрабатывает перемещение mapViewer фотоаппарат, создание соответствующих снимков и обновление треков визуализации.

function allsnaps = snapPlotTrack(mapViewer,tracks,isScanDone, scanCount,allsnaps)
% Save snapshots during first 4 scans
if isScanDone && any(scanCount == [2 3])
    allsnaps = [allsnaps, {snap(mapViewer)}];
    %move camera
    if scanCount == 2
        % Show the outbound airliner
        setCamera(mapViewer, [42.5650  -70.8990 7e3]);
        allsnaps = [allsnaps, {snap(mapViewer)}];
    end
    
end

% Update display with current track positions
plotTrack(mapViewer,tracks);

if isScanDone && any(scanCount == [2 3])
    % Take a snapshot of confirmed track
    allsnaps = [allsnaps, {snap(mapViewer)}];
    % Reset Camera view to full scene
    if scanCount == 3
        origin = [42.366978, -71.022362, 50];
        setCamera(mapViewer, origin + [0 0 1e5]);
    end
end
end