citra-solve
Efficient lost-in-space astrometric plate solver for embedded systems.
Features
- Low memory footprint: ~16KB runtime heap, memory-mapped index files
- Wide FOV support: 10-30+ degree fields with SIP distortion modeling
- Robust matching: Handles false stars (noise, hot pixels) and missing stars
- Fast solving: O(1) hash table lookups with early termination
- Pure Rust: No external dependencies for core solving
Quick Start
Building an Index
First, build a star pattern index from a catalog:
# Build from Hipparcos catalog
# Or generate a synthetic test index
Using the Solver
use ;
// Load a pre-built index
let index = open?;
// Create solver with default config
let solver = new;
// Your detected stars from image (sorted by brightness)
let stars = vec!;
// Solve!
match solver.solve
Architecture
citra-solve uses a geometric hashing approach inspired by astrometry.net and tetra3:
- Pattern Generation: Extract 4-star "quads" from detected stars
- Geometric Hash: Compute scale/rotation invariant features (5 normalized edge ratios)
- Hash Lookup: O(1) lookup in pre-built index
- Hypothesis Generation: Generate WCS hypotheses from matched patterns
- Bayesian Verification: Verify hypotheses using log-odds framework
- Refinement: Iterative least-squares refinement with outlier rejection
Module Structure
src/
├── core/ # Types (RaDec, Vec3) and math utilities
├── catalog/ # Index format, builder, and memory-mapped reader
├── pattern/ # Quad extraction and geometric hashing
├── solver/ # Hypothesis generation, verification, refinement
├── wcs/ # TAN projection and SIP distortion
└── bench/ # Benchmarking harness and synthetic data
Index Format
The index file uses a compact binary format:
| Section | Description |
|---|---|
| Header (64B) | Magic, version, star/pattern counts, FOV range |
| Stars | Packed 12-byte entries (RA, Dec, magnitude) |
| Bin offsets | u32 offsets for each hash bin |
| Patterns | Packed 18-byte entries (4 star indices + 5 ratios) |
Index files are memory-mapped for efficient access without loading into RAM.
Configuration
Solver Config
let config = SolverConfig ;
Presets:
SolverConfig::default()- Balanced accuracy/speedSolverConfig::fast()- Quick solving, lower accuracySolverConfig::thorough()- Maximum accuracy, slower
Build Config
let config = BuildConfig ;
Benchmarking
Run benchmarks against synthetic data:
use ;
let mut suite = new;
suite.run_synthetic;
suite.print_report;
Compare with astrometry.net:
use ;
// Run astrometry.net
let wcs_path = run_astrometry_net?;
let astrometry_wcs = parse_astrometry_wcs?;
// Compare solutions
let comparison = compare_solutions;
println!;
Performance Targets
| Metric | Target |
|---|---|
| Solve rate | >95% (clean fields) |
| Position accuracy | <10 arcsec |
| Solve time | <100ms (after index load) |
| Runtime memory | ~16 KB heap |
| Index size | ~10 MB (10-30° FOV, mag 7) |
Catalog Support
Currently supported:
- Hipparcos (~118k stars) - via
build-indextool - CSV format (RA,Dec,Mag,ID)
- Synthetic catalogs (for testing)
Planned:
- Gaia DR3 subset
- Tycho-2
License
MIT
Acknowledgments
- astrometry.net - Original plate solving algorithms
- tetra3 - TETRA algorithm implementation
- FITS WCS standard