SolutionCloseness#
- class SolutionCloseness#
Bases:
objectStatistical distance between orbit determination solutions.
Two OD solutions of the same object rarely agree exactly, and the useful question is not how far apart the estimates are but whether they are consistent: whether the difference is small compared with the uncertainty each solution claims. Comparing state differences alone answers neither — a 10 km difference is nothing for a solution with a 100 km covariance and damning for one with a 1 km covariance.
The measure of Bhaskaran & Rush [1] answers it directly. Around each solution \(S_i = (c_i, P_i)\) grow the \(t\)-sigma ellipsoid
\[(x - c_i)^T P_i^{-1} (x - c_i) = t^2\]and let both grow together. The closeness \(d(S_1, S_2)\) is the smallest \(t\) at which they first touch. It reads directly as a number of sigma: solutions that touch below \(1\sigma\) overlap comfortably, while a value of several sigma means the two cannot both be right.
The measure is symmetric, scale free, and reduces to the intuitive answers in the simple cases — for equal covariances it is exactly half the Mahalanobis distance between the centres, and for isotropic covariances \(a^2 I\) and \(b^2 I\) it is \(\|c_2 - c_1\| / (a + b)\).
Solutions come either as
SolutionODobjects, which are read for their state estimate and covariance at a chosen epoch, or as plain(mean, covariance)pairs.Methods
between(first, second[, index, covariance, ...])Closeness between two OD solutions, in sigma.
matrix(solutions, **kwargs)Pairwise closeness between every solution in a set.
plot_matrix(solutions[, labels, scheme, ...])Plot the pairwise closeness of a family of solutions.
See also
scarabaeus.SolutionODSolution object read by
between().
Notes
The tangency point satisfies \(\Lambda_1 (x - c_1) = -\alpha \Lambda_2 (x - c_2)\), so it lies at
\[x(\alpha) = (\Lambda_1 + \alpha \Lambda_2)^{-1} (\Lambda_1 c_1 + \alpha \Lambda_2 c_2)\]for a single unknown \(\alpha > 0\), fixed by requiring the two Mahalanobis distances at that point to be equal. That difference runs monotonically from negative to positive as \(\alpha\) sweeps \(0 \to \infty\) (the point slides from \(c_1\) to \(c_2\)), so the root is unique and bracketing finds it without a search grid.
Both solutions must be expressed in the same frame and units; nothing here can detect otherwise, and comparing a J2000 solution against a body-fixed one produces a plausible number that means nothing.
References
[1]Bhaskaran, S., & Rush, J. (2004). Navigation performance measures for orbit determination solution comparison. AIAA/AAS Astrodynamics Specialist Conference, AIAA 2004-4982.
Examples
# two filter solutions of the same arc result = SolutionCloseness.between(solution_a, solution_b) print(f"{result['d']:.2f} sigma apart") # position only, at the first epoch instead of the last result = SolutionCloseness.between( solution_a, solution_b, index=0, states=slice(0, 3) ) # a whole family at once D = SolutionCloseness.matrix([sol_a, sol_b, sol_c], labels=["A", "B", "C"])
- classmethod between(first, second, index: int = -1, covariance: str = 'est', states=None, max_alpha: float = 1000000000000.0) dict#
Closeness between two OD solutions, in sigma.
- Parameters:
- first, secondSolutionOD or tuple
The two solutions. Either
SolutionODobjects, or(mean, covariance)pairs with the mean shaped(n,)and the covariance(n, n).- indexint, optional
Epoch row to compare at, for
SolutionODinputs. Defaults to-1, the final estimate;0is the first epoch.- covariancestr, optional
Which stored covariance to read:
'est'(default),'smooth'or'consider'.- statesslice or sequence of int, optional
Which state components to compare. Defaults to all of them; pass
slice(0, 3)to compare position alone, which is often what a navigation team actually cares about.- max_alphafloat, optional
Bracketing limit for the tangency parameter. Only reached for solutions many orders of magnitude apart in scale.
- Returns:
- dict
dthe closeness in sigma,t_sqits square,alphathe tangency parameter,x_tangthe touching point, andmahalanobisthe pair of distances from each centre to that point — equal todon both sides, which is the check that the solve converged.
- Raises:
- SolutionClosenessError
If the shapes disagree, a covariance is singular, or the requested history is not stored on the solution.
- classmethod matrix(solutions, **kwargs) ndarray#
Pairwise closeness between every solution in a set.
The off-diagonal entries are what tell a family of solutions apart: a tight block means the solutions agree within their own uncertainty, while an isolated row is a solution that disagrees with all the others.
- classmethod plot_matrix(solutions, labels=None, scheme: str = 'sigma', title: str = 'OD solution consistency', show_values: bool = True, distances=None, **kwargs)#
Plot the pairwise closeness of a family of solutions.
- Parameters:
- solutionssequence
Solutions in any form
between()accepts.- labelssequence of str, optional
Axis labels; defaults to
S1 ... SN.- schemestr, optional
Colour banding:
'sigma'(1/2/3-sigma bands, the default),'binary'(consistent or not, split at 0.8), or'continuous'for a smooth colour bar.- titlestr, optional
Figure title.
- show_valuesbool, optional
Print each value in its cell. Defaults to
True.- distancesnp.ndarray, optional
A previously computed matrix, to avoid recomputing it.
- **kwargs
Passed through to
matrix().
- Returns:
- distances, fignp.ndarray and matplotlib.figure.Figure
- exception SolutionClosenessError#
Bases:
ValueErrorRaised when two solutions cannot be compared as posed.