Ell (Ellipsoid Statistics)
Statistical ellipsoid and ellipse representations with lazy-loaded coordinate conversions and Mahalanobis distance calculations.
Overview
gri-ell provides the Ell class, which pairs a geodetic position (inherited from Pos) with a statistical uncertainty region -- an ellipsoid in 3D or ellipse in 2D. Internally, Ell can store covariance matrices, information matrices, or 2D ellipse parameters, and lazily converts between them as needed.
EllVel and EllAcc extend Ell with velocity and acceleration (via diamond inheritance with gri-pos's Vel/Acc), carrying full 6x6 or 9x9 covariance matrices with position-velocity-acceleration cross-terms.
The primary use cases are geolocation error analysis, ellipsoid convolution (via gri-convolve), Kalman filter output, and statistical distance calculations between position estimates.
Requires Python 3.12+.
Mathematical Background
Covariance and information matrices. An Ell object encapsulates two dual representations of the same uncertainty:
- Covariance matrix
C(ENU coordinates, m^2, 1-sigma): describes spread of the position estimate - Information matrix
I = R C^{-1} R^T(XYZ coordinates, 1/m^2, 1-sigma): the inverse covariance rotated into ECEF, used in fusion algorithms
where R is the ENU-to-XYZ rotation matrix at the position.
2D ellipse. The 2D ellipse is the East-North projection of the 3D ellipsoid, parameterized by semi-major axis (SMA), semi-minor axis (SMI), orientation angle (degrees clockwise from North), and altitude uncertainty. Ellipse parameters are reported at 95% confidence.
Mahalanobis distance. The statistical distance from a point x to an ellipsoid centered at mu with information matrix I:
d_M = sqrt((x - mu)^T I (x - mu))
This is unitless: 0 at the center, 1 on the ellipsoid surface, 2 at twice the ellipsoid boundary. It generalizes Euclidean distance to account for the shape and orientation of the uncertainty region.
Norm distance. Mahalanobis distance scaled to 95% confidence intervals by dividing by sqrt(SIG_TO_95). After scaling, a norm distance of 1.0 means the point lies on the 95% confidence boundary.
Scaling factors from the chi-squared distribution:
| Dimension | 1-sigma to 95% scale factor |
|---|---|
| 1D | 1.96 |
| 2D | 2.448 |
| 3D | 2.796 |
Reference: Mahalanobis, P.C. (1936). "On the generalized distance in statistics."
Documentation
The wheel ships its documentation inside the package, in gri_ell/docs/, so it
is available wherever the package is installed:
overview.md-- representations, scales, distances, and trapsapi_summary.md-- every public class, method, and signature (generated)
Print the directory with
python -c "import gri_ell, pathlib; print(pathlib.Path(gri_ell.__file__).parent / 'docs')".
Every example in those files is run by the test suite.
Installation
pip install gri-ell
For development:
git clone https://gitlab.com/geosol-foss/python/gri-ell.git
cd gri-ell
uv sync
Quick Start
from gri_ell import Ell
from gri_pos import Pos
# Create from 2D ellipse parameters (SMA, SMI, orientation in deg, all 95%)
ell = Ell.from_2d(Pos.LLA(40.0, -105.0, 1600), sma_95_m=100, smi_95_m=50, ori_deg=45)
# Access ellipse properties
print(ell.ellipse.sma_95) # 100.0 (semi-major axis, meters, 95%)
print(ell.ellipse.smi_95) # 50.0
print(ell.ellipse.ori_deg) # 45.0 (degrees clockwise from North)
# Statistical distance to another point
other = Pos.LLA(40.001, -105.001, 1610)
d = ell.dist_norm(other) # Normalized 95% distance
print(f"Norm distance: {d:.2f}")
Creating Ell Objects
Ell provides several static constructors. Choose based on what data you have:
| Constructor | Input format | When to use |
|---|---|---|
Ell.from_2d(pos, sma, smi, ori, alt) |
SMA/SMI/ORI at 95% | Human-readable ellipse parameters |
Ell.COV(pos, matrix) |
3x3 ENU, m^2, 1-sigma | Raw covariance from a filter or estimator |
Ell.CONF(pos, matrix) |
3x3 ENU, m^2, 95% | Pre-scaled 95% confidence matrix |
Ell.INFO(pos, matrix) |
3x3 XYZ, 1/m^2, 1-sigma | Information matrix from fusion algorithms |
Ell.Ellipse(pos, matrix) |
2x2 EN, m^2, 1-sigma | 2D covariance matrix directly |
import numpy as np
# From 2D parameters (most common)
ell = Ell.from_2d(pos, sma_95_m=100, smi_95_m=50, ori_deg=45)
# From a 3x3 covariance matrix (ENU, m^2, 1-sigma)
cov = np.array([[100, 10, 0], [10, 50, 0], [0, 0, 25]])
ell = Ell.COV(pos, cov)
# From an information matrix (XYZ, 1/m^2, 1-sigma)
info = np.linalg.inv(cov_xyz)
ell = Ell.INFO(pos, info)
Matrix Representations
Each Ell stores one representation and lazily computes the others on first access:
| Property | Coordinates | Units | Scale | Shape |
|---|---|---|---|---|
ell.cov |
ENU | m^2 | 1-sigma | 3x3 |
ell.conf |
ENU | m^2 | 95% | 3x3 |
ell.info |
XYZ (ECEF) | 1/m^2 | 1-sigma | 3x3 |
ell.ellipse |
East-North | m (95%) | 95% | 2D projection |
The Ellipse object provides the 2D parameters directly:
ell.ellipse.sma_95 # Semi-major axis (meters, 95%)
ell.ellipse.smi_95 # Semi-minor axis (meters, 95%)
ell.ellipse.ori_deg # Orientation (degrees CW from North)
ell.ellipse.alt_95 # Altitude uncertainty (meters, 95%)
ell.ellipse.ori_rad # Orientation in radians
# CEP (Circular Error Probable) - radius of circle containing conf% of 2D probability
ell.ellipse.cep_pct() # CEP-50 (default conf=0.50)
ell.ellipse.cep_pct(0.95) # CEP-95
ell.ellipse.cep_sigma() # CEP at 1-sigma (default sigma=1.0)
ell.ellipse.cep_sigma(2.0) # CEP at 2-sigma
Statistical Distances
All distance methods return unitless values: 0 at center, 1 on the boundary, >1 outside.
# 3D Mahalanobis distance (sigma units)
d = ell.dist_mahalanobis(other_pos)
# 3D normalized distance (95% confidence units)
d = ell.dist_norm(other_pos)
# 2D variants (East-North projection only, faster but less precise)
d = ell.dist_mahalanobis_2d(other_pos)
d = ell.dist_norm_2d(other_pos)
# Combined distance: accounts for uncertainty of both ellipsoids
d = ell.dist_norm(other_ell, combined=True)
# SEP (Spherical Error Probable) - radius of sphere containing conf% of 3D probability
ell.sep_pct() # SEP-50 (default conf=0.50)
ell.sep_pct(0.95) # SEP-95
ell.sep_sigma() # SEP at 1-sigma (default sigma=1.0)
ell.sep_sigma(2.0) # SEP at 2-sigma
Dependencies
- gri-memoize: Per-instance caching of lazy-loaded matrix conversions
- gri-pos: Position class (
Pos) thatEllinherits from - gri-utils: Coordinate conversions, constants, ellipsoid math
- numpy: Matrix operations
Other Projects
Current list of other GRI FOSS Projects we are building and maintaining.
License
MIT License. See LICENSE for details.
Release files for gri-ell 0.3.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| gri_ell-0.3.4.tar.gz | 46.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| gri_ell-0.3.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 76.8 kB
Release files / gri_ell-0.3.4.tar.gz
| Download URL | gri_ell-0.3.4.tar.gz |
|---|---|
| Size | 46.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
223dba078c9c0eac001a7b2752020b01a508cfb9360467e752a228dd32cf1e47
|
|
BLAKE2b-256 checksum How to use checksums |
867a9de151fc75236cc87385a3c7e5b2811a03326924c16ae15f42f18bbb6d3a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / gri_ell-0.3.4-py3-none-any.whl
| Download URL | gri_ell-0.3.4-py3-none-any.whl |
|---|---|
| Size | 30.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
42482971c04f1ae5b2514699bfdf9b7bce3a176e6a4c6fc4f4b5d8ad95f4456d
|
|
BLAKE2b-256 checksum How to use checksums |
e86b5d88f0743acaff04dec292901e7844fcc4ed0a9a92a9ba2c421636ccae08
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|