Mahalanobis Distance
Overview
The Mahalanobis distance is a statistical metric that measures the distance between a measurement and an object track while considering their uncertainties. Unlike Euclidean distance, it accounts for scaling, correlations, and variances of different dimensions, making it well-suited for probabilistic tracking and association tasks.
It is computed as:
where \(\pmb{x_a}\) and \(\pmb{x_b}\) are two states (e.g., a track position and a measurement), and \(\pmb{P}_{ab}\) is the combined covariance matrix:
where \(\pmb{P}_a\) and \(\pmb{P}_b\) are the individual covariances, and \(\pmb{P}_{a,b}\) is the cross-covariance.
Warning
The function assumes \(\pmb{P}_{ab}\) is invertible. If numerical instability occurs, a pseudo-inverse or regularization may be used. This can lead to higher and sometimes inconsistent computation times.
Limitations
Requires an invertible covariance matrix.
Computational heavy.
Selection Note
The Mahalanobis distance is a good choice for applications where uncertainty and correlations matter, and slower computation is acceptable. This distance calculation requires heavy matrix computation, including regularization for stability, and may not produce a result if the covariance matrices are badly conditioned.
Code Documentation
The Mahalanobis distance is implemented in Ufil as part of its association process. It is used to create a cost matrix that helps in optimal measurement-to-track assignments. The function is located in hypothesizer_functions.hpp.
Function Definition
namespace ufil
{
namespace association
{
template<typename TrackType>
void mahalanobis(
const TrackType & track, const typename TrackType::MeasurementType & measurement,
ufil::type::Scalar & distance)
{
const auto & state = track.currentState();
const auto H = ufil::generateMeasurmentMatrix<typename TrackType::MeasurementType,
typename TrackType::StateType>();
// Compute the average covariance
const ufil::type::SquareMatrix<TrackType::MeasurementType::Size> covariance =
0.5 * (H * state.covariance() * H.transpose() + measurement.covariance());
// Check if the covariance matrix is invertible using a small threshold
if (covariance.determinant() < 1e-6) {
distance = ufil::scalar::ScalarMax; // use a max distance value to indicate a problem
return;
}
// Compute the difference vector
const auto difference =
ufil::difference<typename TrackType::MeasurementType,
typename TrackType::StateType>(measurement, state);
// Compute Mahalanobis distance
// Invert covariance using Eigenvalue decomposition for better stability
Eigen::SelfAdjointEigenSolver<ufil::type::DynamicMatrix> solver(covariance);
if (solver.info() != Eigen::Success) {
// If decomposition fails, return a max distance
distance = ufil::scalar::ScalarMax;
return;
}
// Calculate the Mahalanobis distance: sqrt(difference^T * inv(covariance) * difference)
const ufil::type::DynamicMatrix inv_covariance =
solver.eigenvectors() * solver.eigenvalues().cwiseInverse().asDiagonal() *
solver.eigenvectors().transpose();
distance = std::sqrt(difference.transpose() * inv_covariance * difference);
}
} // namespace association
} // namespace ufil
Example Usage
#include <iostream>
#include <ufil_object_tracking/ufil_object_tracking.hpp>
// Get track and measurement
ufil::type::Scalar distance;
ufil::association::mahalanobis(track, measurement, distance);
std::cout << "Mahalanobis Distance: " << distance << std::endl;
Parameters
track: The track containing the estimated state.
measurement: The measurement to compare against the track’s state.
distance: Output parameter storing the computed Mahalanobis distance.