Rust Quick Start¶
satkit is a Rust library first; the Python package is a binding over it. This section covers using the crate directly. Everything in Learn applies to both languages, since the models and conventions are the same; the pages here show the Rust API for each topic, with complete programs you can run.
Add the crate¶
or in Cargo.toml:
satkit builds on stable Rust. Its linear-algebra types (Vector3, Matrix3, Quaternion, ...) come from the numeris crate and are re-exported in satkit::mathtypes; build vectors with Vector3::from_array([x, y, z]), or add numeris yourself for its vector! macro.
Cargo features¶
| Feature | Default | What it does |
|---|---|---|
download |
on | HTTP(S) downloads through ureq: fetching data files on first use, utils::update_datafiles, TLE::from_url and OMM::from_url. Without it, data files must already be on disk (Provisioning up front) and the URL loaders are not compiled |
omm-xml |
on | Parsing OMM XML (OMM::from_xml_string, from_xml_file, and XML in OMM::from_text / from_file) through quick-xml. OMM JSON needs no feature |
chrono |
off | Interoperability with chrono: From conversions between Instant and chrono::DateTime, and TimeLike for chrono::DateTime, so chrono times can be passed to every satkit function that takes a time |
To leave out the downloader, for a build without an HTTP client:
Data files¶
The IERS nutation tables and the gravity models are compiled in, so time scales, SGP4, Kepler and Lambert, gravity, and the precession–nutation part of the frame chain work with no files and no network. The JPL ephemeris (for the Sun and Moon in the numerical propagator, and planetary positions) is downloaded on first use; the Earth orientation and space-weather tables are downloaded on first use and refreshed by utils::update_datafiles:
// Download anything missing and refresh the Earth orientation and
// space-weather tables (needs the `download` feature)
satkit::utils::update_datafiles(None, false)?;
Frame transforms to or from ITRF use Earth orientation parameters (EOP). Without the EOP file they warn once and fall back to zero polar motion and UT1 = UTC, which is off by up to about 12″ (hundreds of meters at LEO), and propagate returns orbitprop::Error::EopUnavailable. The data pages apply unchanged to Rust:
- Data Files: what is compiled in, downloaded and refreshed.
- Data Directories: where satkit looks and writes,
SATKIT_DATA,SATKIT_OFFLINE, and provisioning a machine up front (utils::set_datadir,utils::set_offline). - Data Coverage: checking that the tables cover your epochs (
earth_orientation_params::status,spaceweather::status).
Warnings and logging¶
satkit reports stale or missing data, fallbacks and download notices through the log facade, with the emitting module as the target (e.g. satkit::earth_orientation_params). With no logger installed they are printed to stderr. Once you install a logger it decides what is shown. env_logger shows only errors unless RUST_LOG says otherwise, which would hide satkit's warnings, so give it a default:
fn main() {
// Show satkit's warnings unless RUST_LOG says otherwise
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("satkit=warn"))
.init();
// ...
}
and filter per module at run time, e.g. RUST_LOG=satkit=error or RUST_LOG=satkit=warn,satkit::spaceweather=error. The EOP and space-weather warnings can also be turned off at the source with earth_orientation_params::disable_eop_time_warning() and spaceweather::disable_space_weather_time_warning(). See Warnings and logging for what each warning means.
Errors¶
Fallible functions return a Result with the error type of their module, each an enum built with thiserror so it can be matched:
| Module | Error type | Typical causes |
|---|---|---|
| time | InstantError |
out-of-range date fields, unparsable strings, invalid leap second |
frametransform |
frametransform::Error |
frame pair not supported by the chosen function |
tle, omm |
tle::Error, omm::Error |
malformed records (with line number and satellite), checksum mismatch, HTTP errors |
sgp4 |
sgp4::Error |
initialization failure (eccentricity, decayed orbit); per-time failures are in SGP4State::errcode |
orbitprop |
orbitprop::Error |
no EOP data, invalid settings, a failed ephemeris lookup |
jplephem |
jplephem::Error |
ephemeris file missing (offline) or invalid, time outside its span |
kepler, lambert, lpephem |
kepler::Error, lambert::Error, lpephem::Error |
out-of-domain elements, no convergence, no sunrise |
| data | earth_orientation_params::Error, spaceweather::Error, utils::download::Error |
unreadable or unwritable data files, failed downloads |
Some are #[non_exhaustive], so a match on them needs a wildcard arm. All implement std::error::Error + Send + Sync, so in an application Box<dyn std::error::Error> (as in the examples) or anyhow::Result collects them with ?. The crate-level satkit::Error is deprecated; use the module errors.
A first program¶
//! Where is the ISS? Parse a TLE, run SGP4, and convert to latitude,
//! longitude and altitude.
//!
//! SGP4 needs no data files; the TEME -> ITRF rotation uses Earth
//! orientation parameters, downloaded on first use.
//!
//! ```text
//! cargo run --example quickstart
//! ```
use satkit::frametransform::qteme2itrf;
use satkit::sgp4::sgp4;
use satkit::{Duration, ITRFCoord, Vector3, TLE};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut tle = TLE::load_3line(
"ISS (ZARYA)",
"1 25544U 98067A 24001.50000000 .00016717 00000-0 10270-3 0 9009",
"2 25544 51.6432 351.4697 0007417 130.5364 329.6482 15.48915330299350",
)?;
// Half an orbit after the element-set epoch
let t = tle.epoch + Duration::from_minutes(46.0);
// SGP4 gives TEME position (m) and velocity (m/s), one column per time
let state = sgp4(&mut tle, &[t])?;
let p_teme = Vector3::from_slice(state.pos.col_slice(0));
// Rotate to the Earth-fixed frame and convert to geodetic
let itrf = ITRFCoord::from(qteme2itrf(&t) * p_teme);
println!("{} at {t}", tle.name);
println!(
" latitude {:.3} deg, longitude {:.3} deg, altitude {:.1} km",
itrf.latitude_deg(),
itrf.longitude_deg(),
itrf.hae() / 1e3
);
Ok(())
}
$ cargo run --example quickstart
ISS (ZARYA) at 2024-01-01T12:46:00.000000Z
latitude -51.019 deg, longitude -17.397 deg, altitude 441.6 km
Examples¶
Every program on these pages is a file in examples/ of the repository, compiled in CI, and runnable from a checkout with cargo run --example <name>:
| Page | Example | Needs |
|---|---|---|
| this page | quickstart |
EOP for the TEME → ITRF rotation |
| Time and Time Scales | time_scales, chrono_interop |
EOP for UT1 only; chrono_interop needs --features chrono |
| Coordinate Frames | frames |
EOP for exact ITRF rotations |
| SGP4, TLEs and OMMs | sgp4_tle |
EOP for the TEME → ITRF / GCRF rotations |
| Numerical Propagation | propagate_leo |
JPL ephemeris, EOP, space weather |
| Sun, Moon and Ephemerides | sun_moon, ephemeris |
nothing; JPL ephemeris for ephemeris |
| Kepler and Lambert | kepler_lambert |
nothing |
"EOP" and "space weather" are fetched on first use when the download feature is on; the JPL ephemeris is a one-time 102 MB download. The API reference on docs.rs documents every type and function.