Expand description
§tetra3
A fast, robust lost-in-space star plate solver written in Rust.
Status: Alpha — The core solver is based on well-vetted algorithms but has only been tested against a limited set of images. The API is not yet stable and may change between releases. Having said that, it has been made to work on both low-SNR images taken with a backyard camera and high-star-density images from more complex telescopes.
Given a set of star centroids extracted from a camera image, tetra3 identifies
the stars against a catalog and returns the camera’s pointing direction as a
quaternion — no prior attitude estimate required.
Documentation: For tutorials, concept guides, and Python API reference, see the tetra3rs documentation.
§Features
- Lost-in-space solving — determines attitude from star patterns with no initial guess
- Tracking mode — when an attitude hint is available (e.g. the previous frame’s
solution), skip the 4-star pattern-hash phase and match centroids directly against
catalog stars near the hinted boresight. Set
SolveConfig::attitude_hint/SolveConfig::hint_uncertainty_rad. Succeeds with as few as 3 stars, robust to sparse / low-SNR fields, with automatic fallback to lost-in-space unlessSolveConfig::strict_hintis set. - Fast — geometric hashing of 4-star patterns with breadth-first (brightest-first) search
- Robust — statistical verification via binomial false-positive probability
- Multiscale — supports a range of field-of-view scales in a single database
- Proper motion — propagates Gaia DR3 / Hipparcos catalog positions to any observation epoch
- Compact binary databases — databases serialize with postcard in a portable, lightweight binary format with no offset-size limit, so wide-FOV-range multiscale databases of any size load cleanly.
- Centroid extraction — detect stars from images with local background subtraction,
connected-component labeling, and quadratic sub-pixel peak refinement (
imagefeature) - Camera model — unified
CameraModelstruct (focal length, optical center, parity, distortion) used throughout the solve and calibration pipeline - Distortion calibration — fit SIP polynomial or radial distortion models from one or
more solved images via
calibrate_camera - WCS output — solve results include FITS-standard WCS fields (CD matrix, CRVAL) and
SolveResult::pixel_to_world/SolveResult::world_to_pixelmethods - Stellar aberration — optional correction for the ~20″ apparent shift in star
positions caused by the observer’s barycentric velocity; set
SolveConfig::observer_velocity_km_s(useearth_barycentric_velocityfor ground-based / Earth-orbiting observers) - Tested on real spacecraft imagery — successfully solves NASA TESS Full Frame Images (~12° FOV, significant optical distortion). Multi-image calibration across 10 TESS sectors achieves sub-arcsec agreement with FITS WCS solutions
§Example
use tetra3::{GenerateDatabaseConfig, SolverDatabase, SolveConfig, Centroid, SolveStatus};
// Generate a database from the Gaia catalog
let config = GenerateDatabaseConfig {
max_fov_deg: 20.0,
epoch_proper_motion_year: Some(2025.0),
..Default::default()
};
let db = SolverDatabase::generate_from_gaia("data/gaia_merged.bin", &config).unwrap();
// Save for fast loading later, or load a previously saved database
db.save_to_file("data/my_database.bin").unwrap();
let db = SolverDatabase::load_from_file("data/my_database.bin").unwrap();
// Solve from image centroids (pixel coordinates, origin at image center)
let centroids = vec![
Centroid { x: 100.0, y: 200.0, mass: Some(50.0), cov: None },
Centroid { x: -50.0, y: -10.0, mass: Some(45.0), cov: None },
// ... more centroids ...
];
let solve_config = SolveConfig {
fov_estimate_rad: (15.0_f32).to_radians(), // horizontal FOV
image_width: 1024,
image_height: 1024,
fov_max_error_rad: Some((2.0_f32).to_radians()),
..Default::default()
};
let result = db.solve_from_centroids(¢roids, &solve_config);
if result.status == SolveStatus::MatchFound {
let q = result.qicrs2cam.unwrap();
println!("Attitude: {q}");
println!("Matched {} stars in {:.1} ms",
result.num_matches.unwrap(), result.solve_time_ms);
}§Tracking mode
For frame-to-frame solving where each solve seeds the next, pass the prior attitude as a hint to skip the 4-star pattern-hash phase:
let config = SolveConfig {
attitude_hint: prev.qicrs2cam,
hint_uncertainty_rad: 1.0_f32.to_radians(),
camera_model: prev.camera_model.clone().unwrap(),
..SolveConfig::new((15.0_f32).to_radians(), 1024, 1024)
};
let result = db.solve_from_centroids(¢roids, &config);The solver projects catalog stars near the hinted boresight, nearest-neighbor
matches them to centroids, and runs the same Wahba SVD + verification + WCS
refine path as lost-in-space. Tracking succeeds with as few as 3 matched stars
(LIS needs 4) and is robust to pattern-hash failures from sparse / low-SNR
fields. On failure it falls back to lost-in-space automatically unless
SolveConfig::strict_hint is true.
§Stellar aberration
Stellar aberration shifts apparent star positions by up to ~20″ due to the observer’s barycentric velocity (~30 km/s for Earth). The pattern-matching step is unaffected (inter-star angular separations are invariant to first order in v/c), but the final attitude quaternion is biased by ~20″ unless corrected.
Pass the observer’s barycentric velocity (ICRS, km/s) via
SolveConfig::observer_velocity_km_s. The solver applies the classical
correction s' = (s + β) / |s + β| to all catalog vectors before matching
and refinement.
For ground-based observers, earth_barycentric_velocity is the whole
story. For observers on LEO spacecraft, Earth-orbital velocity (~7.5 km/s,
~5″ bias) is not negligible — pass the total barycentric velocity
(Earth-around-Sun + spacecraft-around-Earth) instead of just
earth_barycentric_velocity alone.
use tetra3::{earth_barycentric_velocity, SolveConfig};
let v = earth_barycentric_velocity(9321.0); // days since J2000.0
let config = SolveConfig {
observer_velocity_km_s: Some(v),
..SolveConfig::new((10.0_f32).to_radians(), 1024, 1024)
};§Algorithm overview
- Pattern generation — select combinations of 4 bright centroids; compute 6 pairwise angular separations and normalize into 5 edge ratios (a geometric invariant)
- Hash lookup — quantize the edge ratios into a key and probe a precomputed hash table for matching catalog patterns
- Attitude estimation — solve Wahba’s problem via SVD to find the rotation from catalog (ICRS) to camera frame
- Verification — project nearby catalog stars into the camera frame, count matches, and accept only if the false-positive probability (binomial CDF) is below threshold
- Refinement — re-estimate the rotation using all matched star pairs via iterative SVD passes
- WCS fit — constrained 3-DOF tangent-plane refinement (rotation angle θ + CRVAL offset) with sigma-clipping, producing FITS-standard WCS output
§Credits
This crate is a Rust implementation of the tetra3 / cedar-solve algorithm:
- tetra3 — the original Python implementation by Gustav Pettersson at ESA
- cedar-solve — Steven Rosenthal’s C++/Rust star plate solver, which this implementation closely follows
- Paper: G. Pettersson, “Tetra3: a fast and robust star identification algorithm,” ESA GNC Conference, 2023
This Rust implementation was developed by Steven Michael with assistance from Claude Code (Anthropic).
Re-exports§
pub use camera_model::CameraModel;pub use error::Error;pub use error::Result;pub use distortion::calibrate_camera;pub use distortion::CalibrateConfig;pub use distortion::CalibrateResult;pub use distortion::Distortion;pub use distortion::DistortionModelType;pub use distortion::PolynomialDistortion;pub use distortion::RadialDistortion;pub use solver::DatabaseProperties;pub use solver::GenerateDatabaseConfig;pub use solver::SolveConfig;pub use solver::SolveResult;pub use solver::SolveStatus;pub use solver::SolverDatabase;pub use aberration::earth_barycentric_velocity;pub use star::*;pub use starcatalog::*;
Modules§
- aberration
- Stellar aberration utilities.
- camera_
model - Camera intrinsics model: focal length, optical center, parity, and distortion.
- distortion
- Lens distortion models for correcting optical distortion in star images.
- error
- Error type for tetra3.
- solver
- Star plate solver based on the tetra3/cedar-solve algorithm.
- star
- starcatalog
- Spatial star catalog optimized for fast cone (angular-radius) searches.