Filtro PHD com Múltiplos Modelos de Manobra para Rastreamento de Alvos

Fundamentação Teórica e Arquitetura

O filtro de densidade hipotética de probabilidade (PHD) integrado a múltiplos modelos de manobra constitui uma abordagem robusta para cenários onde alvos executam movimantos não lineares e transitórios. A estrutura híbrida combina a flexibilidade do Interacting Multiple Model (IMM) com a capacidade do filtro PHD de lidar com número variável de alvos.

Diferenciais arquiteturais:

  • Associação partícula-modelo: Cada amostra de estado carrega um identificador de modelo cinemático, permitindo transições probabilísticas entre dinâmicas distintas
  • Matriz de transição adaptativa: Probabilidades de troca antre modelos são recalculadas iterativamente conforme a qualiddae de ajuste das observações
  • Mitigação de empobrecimento amostral: Estratégias de reamostragem seletivas preservam a diversidade populacional, com extensão para filtro CPHD quando necessária estimativa conjunta de cardinalidade

Fluxo Computacional

1. Configuração de Modelos Cinemáticos

% Conjunto de dinâmicas de movimento (exemplo: modelo de velocidade constante vs. aceleração constante)
motionSet = {
    struct('A', [1 dt; 0 1], 'W', diag([sigma_v^2, sigma_v^2/dt^2])),      % CV
    struct('A', [1 dt dt^2/2; 0 1 dt; 0 0 1], 'W', diag([sigma_a^2*dt^4/4, sigma_a^2*dt^2, sigma_a^2]))  % CA
};

% Instanciação do filtro
tracker = GaussianMixturePHD();
tracker.MotionModels = motionSet;
tracker.BirthIntensity = struct('gamma', 30, 'birthProb', 0.08);
tracker.ClutterRate = 10;

2. Propagação Temporal com Seleção de Modelo

function [cloud, modelWeights] = temporalPropagate(cloud, motionSet, deltaT)
    numSamples = length(cloud.samples);
    modelWeights = zeros(length(motionSet), 1);
    
    for idx = 1:numSamples
        % Amostragem do modelo ativo baseada em probabilidades de mistura
        activeModel = discreternd(1, cloud.samples(idx).modelProbs);
        dynamics = motionSet{activeModel};
        
        % Evolução do estado com ruído de processo
        processNoise = chol(dynamics.W)' * randn(size(dynamics.A, 1), 1);
        cloud.samples(idx).x = dynamics.A * cloud.samples(idx).x + processNoise;
        
        % Atualização de peso por probabilidade de sobrevivência
        cloud.samples(idx).w = cloud.samples(idx).w * cloud.samples(idx).Ps;
        
        % Acumulação para estatísticas de modelo
        modelWeights(activeModel) = modelWeights(activeModel) + cloud.samples(idx).w;
    end
    
    % Normalização das probabilidades de modelo
    modelWeights = modelWeights / sum(modelWeights);
end

3. Correção por Observações e Atualização de Modelos

function cloud = measurementCorrect(cloud, obsSet, motionSet, sensorParams)
    numModels = length(motionSet);
    totalLikelihood = zeros(length(cloud.samples), numModels);
    
    % Avaliação de verossimilhança por modelo
    for mIdx = 1:numModels
        predictedObs = projectToMeasurement(cloud.samples, motionSet{mIdx}, sensorParams);
        innovation = bsxfun(@minus, obsSet', predictedObs);
        
        % Verossimilhança gaussiana ponderada
        totalLikelihood(:, mIdx) = gaussLikelihood(innovation, sensorParams.R);
    end
    
    % Fusão de verossimilhanças com pesos de modelo
    fusedLikelihood = totalLikelihood * cloud.modelProbs;
    
    % Atualização de pesos de partículas
    for idx = 1:length(cloud.samples)
        cloud.samples(idx).w = cloud.samples(idx).w * ...
            (cloud.clutterIntensity + sum(fusedLikelihood(idx, :)));
    end
    
    % Reamostragem estratificada para evitar degeneração
    cloud = systematicResample(cloud);
    
    % Atualização bayesiana das probabilidades de modelo
    cloud.modelProbs = updateModelProbabilities(cloud, totalLikelihood);
end

4. Extração de Estimativas de Estado

function [targetList, cardinalityEst] = extractEstimates(cloud, extractionThreshold)
    % Filtragem de componentes significativas
    significantIdx = find([cloud.samples.w] > extractionThreshold);
    if isempty(significantIdx)
        targetList = [];
        cardinalityEst = 0;
        return;
    end
    
    % Agrupamento por proximidade no espaço de estados
    stateMatrix = reshape([cloud.samples(significantIdx).x], [], length(significantIdx))';
    clusterIdx = dbscan(stateMatrix(:, 1:2), 0.4, 3);  % Posição espacial
    
    uniqueClusters = unique(clusterIdx(clusterIdx > 0));
    targetList = cell(length(uniqueClusters), 1);
    
    for cIdx = 1:length(uniqueClusters)
        members = significantIdx(clusterIdx == uniqueClusters(cIdx));
        weights = [cloud.samples(members).w];
        normalizedW = weights / sum(weights);
        
        % Estimativa de mínimo erro quadrático médio
        states = reshape([cloud.samples(members).x], [], length(members));
        targetList{cIdx}.state = states * normalizedW';
        targetList{cIdx}.covariance = weightedCovariance(states, normalizedW);
        targetList{cIdx}.existenceProb = sum(weights);
    end
    
    cardinalityEst = length(uniqueClusters);
end

Refinamentos e Extensões

Estimação Adaptativa de Transição entre Modelos

function transMatrix = adaptiveTransition(cloud, motionSet, windowSize)
    numModels = length(motionSet);
    transMatrix = eye(numModels) * 0.95 + ones(numModels) * 0.05/numModels;  % Prior
    
    if length(cloud.history) < windowSize
        return;
    end
    
    % Análise de frequência de transições recentes
    recentHistory = cloud.history(end-windowSize+1:end);
    transitionCounts = zeros(numModels);
    
    for t = 2:length(recentHistory)
        prevModels = recentHistory{t-1}.activeModels;
        currModels = recentHistory{t}.activeModels;
        
        for i = 1:length(prevModels)
            transitionCounts(prevModels(i), currModels(i)) = ...
                transitionCounts(prevModels(i), currModels(i)) + 1;
        end
    end
    
    % Suavização de Dirichlet para evitar zeros
    alpha = 1;
    transMatrix = (transitionCounts + alpha) ./ (sum(transitionCounts, 2) + alpha*numModels);
end

Integração com CPHD para Estimativa de Cardinalidade

function [posteriorCard, adjustedCloud] = cphdCardinalityUpdate(cloud, measurements, priorCardDist)
    % Predição de distribuição de cardinalidade
    predictedCard = conv(priorCardDist, poissonPMF(cloud.birthRate));
    predictedCard = predictedCard(1:length(priorCardDist));
    
    % Cálculo de fatores de correção por cardinalidade
    detectionProbs = [cloud.samples.Pd];
    missProbs = 1 - detectionProbs;
    
    % Atualização da distribuição de cardinalidade (equação CPHD)
    posteriorCard = zeros(size(predictedCard));
    for n = 0:length(predictedCard)-1
        for j = 0:min(n, length(measurements))
            % Termos combinatórios e de verossimilhança
            posteriorCard(n+1) = posteriorCard(n+1) + ...
                nchoosek(n,j) * (sum(missProbs)/length(missProbs))^(n-j) * ...
                measurementLikelihoodFactor(measurements, j, cloud);
        end
    end
    
    posteriorCard = posteriorCard / sum(posteriorCard);
    
    % Ajuste de pesos das partículas pela cardinalidade posterior
    expectedCard = sum((0:length(posteriorCard)-1) .* posteriorCard');
    scaleFactor = expectedCard / sum([cloud.samples.w]);
    for idx = 1:length(cloud.samples)
        adjustedCloud.samples(idx).w = cloud.samples(idx).w * scaleFactor;
    end
end

Aceleração por Computação Heterogênea

function cloud = parallelUpdate(cloud, measurements, motionSet)
    % Paralelização em CPU
    numWorkers = gcp('nocreate').NumWorkers;
    chunkSize = ceil(length(cloud.samples) / numWorkers);
    
    spmd
        localIdx = labindex:spmdSize:length(cloud.samples);
        localSamples = cloud.samples(localIdx);
        
        % Processamento local com redução de comunicação
        for i = 1:length(localSamples)
            localSamples(i) = processSample(localSamples(i), measurements, motionSet);
        end
    end
    
    % Reconstrução do conjunto global
    cloud.samples = vertcat(localSamples{:});
    
    % Fallback para GPU em volumes massivos
    if length(cloud.samples) > 1e5
        cloud = gpuAcceleratedUpdate(cloud, measurements);
    end
end

Cenário de Validação

%% Configuração do experimento
duracaoSim = 120;           % segundos
intervaloAmostragem = 0.05; % 20 Hz
numAlvos = 6;

%% Geração de cenário realista
cenarioVerdade = struct();
for alvoIdx = 1:numAlvos
    % Trajetória com múltiplas mudanças de dinâmica
    mudancasTempo = sort(rand(1, 3) * duracaoSim);
    perfilMovimento = gerarPerfilHibrido(motionSet, mudancasTempo);
    cenarioVerdade(alvoIdx).trajetoria = integrarEstados(perfilMovimento, intervaloAmostragem);
end

%% Execução do filtro
estimativas = cell(floor(duracaoSim/intervaloAmostragem), 1);
probabilidadesModelo = zeros(length(motionSet), length(estimativas));

for passo = 1:length(estimativas)
    instante = passo * intervaloAmostragem;
    
    % Geração de medições com detecção probabilística e clutter
    medicoes = gerarMedicoesRuidosas(cenarioVerdade, instante, sensor);
    
    % Ciclo completo do filtro
    [estimativas{passo}, probabilidadesModelo(:, passo)] = ...
        executarCicloPHD(tracker, medicoes, instante);
end

%% Métricas de desempenho
[ospaDist, locError, cardError] = calcularOSPA(cenarioVerdade, estimativas, 100, 2);

Tags: PHD filter IMM particle filter multi-target tracking nonlinear estimation

Publicado em 8-17 04:07