Repository navigation
0.24 comes out of a full review of the time, frames, ephemeris, SGP4, data and binding layers. It fixes a set of long-standing defects, several of which gave wrong numbers without any error, and it tightens the Python API: exception types, return shapes and keyword handling. Please read Migrating to 0.24 before upgrading.
Check your results
These defects changed numbers without raising an error. If your work depends on one of them, re-run it with 0.24. The migration page has the details.
- Quaternion × N×3 array applied the inverse rotation (0.14.1–0.23.1). A single 3-vector was rotated correctly.
satproperties(a, b)positional arguments swapped drag and radiation pressure. The constructor is now keyword-only.lambertwas wrong for long-way, retrograde, hyperbolic and near-parabolic transfers (0.14.1–0.23.1).kepler.from_pvwas wrong at inclination π.- SGP4 kept a stale initialization after a TLE was edited or
gravconst/opsmodechanged. Rustsgp4()and TLE fitting used WGS84; the default is now WGS72 everywhere. - Time strings with UTC offsets:
from_rfc3339ignored±HHMM/±HH, thestrptime%zsign was inverted, andfrom_stringread offsets as microseconds. - Leap seconds and TDB: midnight after a leap second was 1 s early, UT1 was up to 0.5 s off the day before one, TDB was off by up to 3.3 ms, and the JPL ephemerides were evaluated at TT instead of TDB.
moon.pos_gcrfreturned mean-of-date coordinates,planets.heliocentric_poshad wrong obliquity and outer-planet terms, andsun.rise_setoften returned the next day's events.- Drag and density: drag now applies up to 1,000 km (was 700 km). Density on the day after a missing F10.7 was 35–39 % low, and
density.nrlmsise()ignoreddatetimetimes. - Pre-1972 UTC follows the 1961–1971 "rubber second" model, so labels move by up to 9.9 s. EOP before 1973 is no longer available: UT1 = UTC there.
Highlights
- Python 3.11–3.15: wheels for CPython 3.15 (ready for its October release); Python 3.10 (end of life October 2026) is no longer supported.
- numpy
datetime64time input everywhere a time or time array is accepted (any unit, read as UTC), so pandas / xarray time columns go straight in. - Warnings use standard logging: Rust's
logfacade (stderr when no logger is installed) and, in Python, theloggingmodule undersatkit.*loggers — silence withlogging.getLogger("satkit").setLevel(logging.ERROR). - Faster: EOP and space-weather lookups,
gmst(−53 %), TEME→ITRF (−40 %) and GEO propagation (−12 %) are faster than 0.23.1; LEO propagation with drag is ~2 % faster. - Earth orientation from IERS
finals2000A.allonly, with a stale-prediction warning, rejection of truncated downloads, and a parser that no longer panics on duplicated rows. - Time: the pre-1972 UTC model matches ERFA; the Earth rotation angle agrees with ERFA to 9 µas (it was off by up to 1 cm at LEO, 6 cm at GEO); microsecond rounding is exact through strings,
datetime, chrono and pickles; Rust has newchecked_add/checked_sub. - TLEs: parse errors give the line and satellite, there is a new Rust
TLE::records()iterator, checksum checks are optional (check_checksum=True), and mismatched or orphan lines are rejected. OMMs with day-of-year epochs are accepted. The line-1 classification letter is kept (TLE.classification, OMMCLASSIFICATION_TYPE), and malformed Alpha-5 satellite numbers are rejected. - SGP4: thread-safe on a shared TLE;
errflag=Truereports element sets that cannot be initialized as NaN rows;TLE.fit_from_states()takesgravconst/opsmode. - New: Python
moon.pos_mod;geodeticandpropstatspickle;satstate,density.nrlmsise()andsun.rise_set()accept adatetime. - Robustness:
sun.shadowfuncno longer returns NaN near L2 or inside the Earth, the planets' Kepler solver can no longer hang, and time arithmetic overflow raisesOverflowErrorinstead of wrapping. - Docs: a rewritten Time Systems reference page, a Troubleshooting & FAQ page and the migration guide.
- Verification: differential tests against ERFA, property tests (proptest / hypothesis), and stubtest over every stub module. Builds are reproducible.
Breaking changes
See the migration page for each change and what to do.
- Python 3.11 or newer is required.
satproperties()is keyword-only. Unknown keywords raiseTypeError(wasValueError).- One-element lists keep their axis:
sgp4(tle, [t])is(1, 3)andsgp4([tle], t)is(1, 3). TLE.from_lines()/from_file()/from_url()always returnlist[TLE].- Warnings go through
log/ Pythonlogginginstead of being printed directly; their text no longer starts withWarning:when shown by Python. - Many invalid calls raise a specific
TypeError/ValueError/OverflowError/ZeroDivisionErrorinstead ofRuntimeErroror a meaningless value (table). - EOP comes only from IERS
finals2000A.all, and thesatkit[data]extra is gone. utils.build_date()is removed (utils.version()now returns the release version), andframetransform.eop_source()is deprecated.- Pickles written by 0.24 do not load in 0.23.
- Rust:
EopSourceremoved,DataDirReadOnly { path, reason },EopCoveragefields,SGP4InitArgs::epoch_days_1950,lambert::Error#[non_exhaustive],Instantoperators saturate,Instant::UNIX_EPOCH.raw, new publicTLE::classificationfield. - Reminder: the deprecated Python
as_*conversions are removed in 0.25.
Full list: CHANGELOG.
Install / upgrade
pip install --upgrade satkitcargo add satkit@0.24conda install -c conda-forge satkit=0.24