gri-kalman
Per-target Kalman tracking for geolocation: interacting multiple model (IMM)
filters with a motion-model bank, maneuver segmentation, RTS smoothing, and
EKF/UKF measurement updates from either Ell position fixes or raw observables.
This package was factored out of gri-convolve so the per-target estimators can
be reused without the ellipsoid-convolution stack. It depends only on gri-ell,
gri-obs, gri-pos, gri-utils (plus numpy/scipy).
Install
uv add gri-kalman
Trackers
All implement the Tracker protocol (update / update_observable / predict /
coast / smoothed_track / result / is_initialized):
| Tracker | Description |
|---|---|
IMM |
Interacting multiple model filter over a motion-model bank |
SmartIMM |
IMM with outlier rejection on the measurement stream |
SegmentedIMM |
Maneuver-segmenting IMM (per-segment filters) |
SmartSegmentedIMM |
Segmenting + outlier-rejecting (the recommended default) |
Motion models: ConstantVelocity, ConstantAcceleration, NearlyConstantSpeed,
CoordinatedTurn, Singer, AscendDescend, Static (plus the
LinearMotionModel / NonlinearMotionModel / MotionModel base protocols).
Local-level (ENU) awareness
The state is ECEF, but a maneuver's "horizontal" and "vertical" are defined
relative to local up, not the ECEF axes. Models whose dynamics or noise are
anisotropic in that sense take a level_rotation provider (an ECEF position ->
3x3 ECEF->ENU rotation):
CoordinatedTurnturns in the local horizontal plane about local up (not the ECEF polar axis).AscendDescendputs its large maneuvering noise along local up.ConstantVelocitycan split process noise / velocity prior into horizontal and a small vertical component, to model a level mover (boat, car, cruising aircraft).
Pass a constant rotation for a fixed local-level frame (rigorous over a bounded
area) or the position-dependent wgs84_level_rotation to follow Earth curvature
with no re-origining.
Gauss-Markov reverting components
Several models hold a state that should revert toward zero absent evidence, all
via the same first-order Gauss-Markov (Ornstein-Uhlenbeck) mechanism — a
(tau, sigma) pair (time constant + steady-state spread), gauss_markov_step:
Staticreverts its (nuisance) velocity toward zero.CoordinatedTurnreverts its turn rate toward zero (straight), so a turn rate picked up from noise on a straight leg relaxes instead of persisting.Singerreverts its acceleration toward zero (the canonical named case).
The pull is gentle (long tau) — real maneuver evidence overrides it within a
scan or two, so it costs no responsiveness.
Smoothing: rts_smooth, rts_smooth_segments, track_to_ells. Result container:
KalmanResult.
EKF vs UKF for observable updates
update() consumes an Ell (3D position + covariance) and is always an exact
linear update. update_observable() consumes a nonlinear observable (TDOA, FDOA,
AOA, Range, ...); choose the linearization with update_method:
"ekf"(default): linearizes at the predicted mean via the observable'sjacobian(). Cheap and accurate when the prior is tight relative to the geometry's nonlinearity."ukf": propagates sigma points throughpredicted()(no Jacobian). More robust (better-calibrated covariance) when the prior is broad and the observable is strongly nonlinear -- e.g. track initiation, long coast gaps, AOA, or satellite TDOA. Tune the spread withukf_alpha.
The UKF's advantage is consistency, not necessarily smaller point error; switch to it for robustness when the prior is broad, not expecting lower position error in mildly nonlinear cases.
Output: the unified tracking surface
tracker.result returns a KalmanResult that satisfies the TrackingOutput
protocol — the same surface the multi-target gri-multitrack engine reports, so
a consumer reads tracks, per-observation dispositions, and (on request) smoothed
trajectories the same way regardless of which tracker produced them. A
single-target tracker is the degenerate one-track case.
-
result.tracks— a list ofTrackEstimate(one element here; useresult.trackfor it). Each carriesstateas anEllVel(position + velocity + full 6x6 covariance; anEllAccwhen a constant-acceleration model contributes),mode_probabilities,existence,confirmed,hits, and a boundpredict. -
result.dispositions— oneDispositionper observation, in arrival order. Each hasindex,used,verdict(assigned/rejected),track,confidence. The outlier / unused bucket is simply:outliers = [d for d in result.dispositions if not d.used]
Only the gating trackers (
SmartIMM,SmartSegmentedIMM) reject; a plainIMMhas no gate, so everything isassigned. -
Prediction is a bound closure:
result.track.predict(dt_s)returns aPredictedState(anEllVelattime + dt_s), propagated through the motion model. Ask for any horizon on demand — there is no fixed prediction list. -
Smoothing is optional and on request (it refines the past trajectory, not the present estimate, so it is never part of the live output):
smoothed = result.smoothed() # {label: [(t, Ell), ...]}
The live
tracksare the filtered ("best given data so far") estimate;smoothed()returns the retrospective ("best given all data") trajectory.
out = tracker.result
fix = out.track.state # EllVel: .ell (position), .vel_xyz, .vel_cov
v = out.track.state.vel_xyz # current velocity
outliers = [d for d in out.dispositions if not d.used]
future = out.track.predict(30.0).state # extrapolate 30 s ahead
past = out.smoothed() # retrospective trajectory (opt-in)
Notes
- State is ECEF; positions/covariances interchange with gri-ell
Ellobjects. - Downstream consumers: the multi-target engine
gri-multitrackorchestrates these trackers via theTrackerprotocol; gri-convolve no longer ships them.
License
MIT -- see LICENSE.
Release files for gri-kalman 0.3.2
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_kalman-0.3.2.tar.gz | 88.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| gri_kalman-0.3.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 166.6 kB
Release files / gri_kalman-0.3.2.tar.gz
| Download URL | gri_kalman-0.3.2.tar.gz |
|---|---|
| Size | 88.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2f55e138f4dbf4620e9139d02857446545e6963796cc2f7f63165c06b732b3c5
|
|
BLAKE2b-256 checksum How to use checksums |
eab1fd2ef84bcaa65bcf4ee85b2293e38bd7ad37b549089df48106052a9e3bfd
|
| 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_kalman-0.3.2-py3-none-any.whl
| Download URL | gri_kalman-0.3.2-py3-none-any.whl |
|---|---|
| Size | 78.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
36ce60e04ffadb6b0874ab4d9ba0961e14313d1e799b4bb2a46f1b33c4fd40a1
|
|
BLAKE2b-256 checksum How to use checksums |
49d9f041b335b62efb318696bd23cb3c41bc0f576afe6136ef20d1cff605235e
|
| 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}
|