Modular state estimation building blocks — UKF, IMM, and multi-sensor fusion in C++ with Python bindings. Quaternion-native, real-time tracking.
Install:
pip install quakfilter
Requires Python ≥ 3.10 and NumPy ≥ 2.0. Built with Eigen 5 and optional OpenMP for parallel tracking.
Sigma-point UKF on a 16-dimensional quaternion state vector (position, velocity, orientation, angular velocity). Handles non-linear dynamics without Jacobians.
ukf = quak.UKF(model, process_noise, measurement_noise, initial_covariance, x0)
Sigma points respect SO(3) quaternion geometry — no linearization artifacts on rotations. Pluggable manifold abstraction with built-in Euclidean and Quaternion types for correct retraction and lifting on non-Euclidean state spaces.
quak.Quaternion() # SO(3) manifold for UKF sigma-point generation
IMM estimator that blends multiple motion models (constant velocity, constant turn-rate, Singer jerk, helical) — automatically adapts to maneuvering targets.
imm = quak.IMMEstimator(models, transition_matrix, mode_probabilities)
Manages hundreds of concurrent tracks with automatic birth, death, and data association. OpenMP-accelerated parallel predict and update across all tracks.
pool = quak.TrackPool(models, config); pool.step(detections, timestamp)
Fuse 2D image detections with 3D state via calibrated camera projection. Supports pinhole, fisheye, and arbitrary distortion models.
sensor = quak.ProjectiveBBoxSensor(camera_params, noise_model)
Create a filter, predict forward, and update with measurements.
import numpy as np
import quak
# Constant-velocity rigid body model
model = quak.RigidBodyCVModel()
# Initial state: position + velocity + quaternion + angular velocity
x0 = np.zeros(16)
x0[9] = 1.0 # quaternion w-component
ukf = quak.UKF(
model=model,
process_noise=np.eye(15) * 0.01,
measurement_noise=np.eye(6) * 0.001,
initial_covariance=np.eye(15) * 0.1,
initial_state=x0,
)
# Predict → Update loop
ukf.predict(dt=0.1)
ukf.update(measurement)
TrackPool handles birth, death, and association for many targets simultaneously.
import quak
pool = quak.TrackPool(
models=[quak.RigidBodyCVModel(), quak.RigidBodyCTRVModel()],
transition_matrix=np.array([[0.95, 0.05], [0.05, 0.95]]),
)
for timestamp, detections in sensor_stream:
pool.step(detections, timestamp)
for track in pool.active_tracks:
print(f"Track {track.id}: {track.position}")