using CartographerSharp.Mapping; using RobotNet10.RobotApp.SLAM.Cartographer.Geometry; namespace RobotNet10.RobotApp.SLAM.Cartographer.Helpers; /// /// Helper class for calculating covariance from Cartographer constraints /// public static class CovarianceCalculator { /// /// Result of covariance calculation /// public record Result( Matrix3x3? Covariance, int ConstraintCount, double AverageConstraintQuality); /// /// Calculate covariance and quality metrics from constraints /// /// List of pose graph constraints /// Covariance calculation result public static Result Calculate(IList constraints) { if (constraints == null || constraints.Count == 0) { return new Result(null, 0, 0.0); } int constraintCount = constraints.Count; // Calculate average constraint weights var avgTranslationWeight = constraints.Average(c => c.ConstraintPose.TranslationWeight); var avgRotationWeight = constraints.Average(c => c.ConstraintPose.RotationWeight); // Calculate constraint quality score (0.0 - 1.0) var normalizedTranslationQuality = Math.Min(1.0, avgTranslationWeight / 100.0); var normalizedRotationQuality = Math.Min(1.0, avgRotationWeight / 100.0); var averageConstraintQuality = (normalizedTranslationQuality + normalizedRotationQuality) / 2.0; // Calculate covariance from constraint weights var translationWeightVariance = constraints .Select(c => c.ConstraintPose.TranslationWeight) .Select(w => Math.Pow(w - avgTranslationWeight, 2)) .Average(); var rotationWeightVariance = constraints .Select(c => c.ConstraintPose.RotationWeight) .Select(w => Math.Pow(w - avgRotationWeight, 2)) .Average(); // Convert weights to covariance (inverse relationship) var translationCovBase = 1.0 / (avgTranslationWeight + 1e-6); var rotationCovBase = 1.0 / (avgRotationWeight + 1e-6); // Adjust covariance based on variance var translationVarianceFactor = 1.0 + (translationWeightVariance / (avgTranslationWeight * avgTranslationWeight + 1e-6)); var rotationVarianceFactor = 1.0 + (rotationWeightVariance / (avgRotationWeight * avgRotationWeight + 1e-6)); var translationCov = translationCovBase * translationVarianceFactor; var rotationCov = rotationCovBase * rotationVarianceFactor; // Adjust covariance based on number of constraints var constraintCountFactor = 1.0 / (1.0 + Math.Log10(Math.Max(1, constraintCount))); translationCov *= constraintCountFactor; rotationCov *= constraintCountFactor; // Create covariance matrix for 2D pose (x, y, theta) var covariance = Matrix3x3.Covariance( xx: translationCov, yy: translationCov, tt: rotationCov, xy: 0.0, xt: 0.0, yt: 0.0 ); return new Result(covariance, constraintCount, averageConstraintQuality); } }