|
1 | 1 | # astroz Python Bindings |
2 | 2 |
|
3 | | -High-performance SGP4 satellite orbit propagation for Python, powered by Zig with SIMD acceleration. |
| 3 | +High-performance SGP4 satellite propagation, powered by Zig with SIMD acceleration. |
4 | 4 |
|
5 | | -**Supported platforms:** macOS and Linux |
6 | | -**Requires:** Python 3.10+ |
| 5 | +**Platforms:** macOS, Linux | **Requires:** Python 3.10+ |
7 | 6 |
|
8 | 7 | ## Quick Start |
9 | 8 |
|
10 | 9 | ```python |
11 | | -from astroz import Tle, Sgp4 |
| 10 | +from astroz import load_constellation, propagate_constellation |
12 | 11 | import numpy as np |
13 | 12 |
|
14 | | -# Parse TLE |
15 | | -tle = Tle("""1 25544U 98067A 24127.82853009 .00015698 00000+0 27310-3 0 9995 |
16 | | -2 25544 51.6393 160.4574 0003580 140.6673 205.7250 15.50957674452123""") |
17 | | - |
18 | | -# Single propagation |
19 | | -sgp4 = Sgp4(tle) |
20 | | -pos, vel = sgp4.propagate(30.0) # 30 minutes after TLE epoch |
| 13 | +# Load Starlink satellites and propagate for 1 day |
| 14 | +constellation = load_constellation("starlink") |
| 15 | +positions = propagate_constellation(constellation, np.arange(1440)) |
| 16 | +# positions: (1440, num_satellites, 3) in km, ECEF coordinates |
| 17 | +``` |
21 | 18 |
|
22 | | -# Batch propagation (convenience method) |
23 | | -times = np.arange(0, 1440, 1.0, dtype=np.float64) # 1 day, 1-min intervals |
24 | | -positions, velocities = sgp4.propagate_batch(times) |
| 19 | +## Loading TLEs |
25 | 20 |
|
26 | | -# Or use propagate_into for zero-copy into pre-allocated arrays |
27 | | -positions = np.empty((len(times), 3), dtype=np.float64) |
28 | | -velocities = np.empty((len(times), 3), dtype=np.float64) |
29 | | -sgp4.propagate_into(times, positions, velocities) |
| 21 | +```python |
| 22 | +from astroz import load_constellation |
| 23 | + |
| 24 | +# CelesTrak groups |
| 25 | +constellation = load_constellation("starlink") |
| 26 | +constellation = load_constellation("iss") |
| 27 | +constellation = load_constellation("gps") |
| 28 | +constellation = load_constellation("all") # ~10k active satellites |
| 29 | + |
| 30 | +# By NORAD ID |
| 31 | +constellation = load_constellation(norad_id=25544) # ISS |
| 32 | +constellation = load_constellation(norad_id=[25544, 48274]) # Multiple |
| 33 | + |
| 34 | +# Local file or URL |
| 35 | +constellation = load_constellation("satellites.tle") |
| 36 | +constellation = load_constellation("https://example.com/tles.txt") |
| 37 | + |
| 38 | +# With metadata (name, norad_id, inclination, period, etc.) |
| 39 | +constellation, metadata = load_constellation("starlink", with_metadata=True) |
| 40 | +for sat in metadata: |
| 41 | + print(f"{sat['name']}: {sat['inclination']:.1f}° inc, {sat['period']:.1f} min period") |
30 | 42 | ``` |
31 | 43 |
|
32 | | -## Performance |
| 44 | +Groups: `all`, `starlink`, `oneweb`, `planet`, `spire`, `gps`, `glonass`, `galileo`, `beidou`, `stations`/`iss`, `weather`, `geo` |
| 45 | + |
| 46 | +## Propagation |
| 47 | + |
| 48 | +```python |
| 49 | +from astroz import load_constellation, propagate_constellation |
| 50 | +from datetime import datetime, timezone |
| 51 | +import numpy as np |
| 52 | + |
| 53 | +constellation = load_constellation("starlink") |
33 | 54 |
|
34 | | -**1.3-2.9x faster** than python-sgp4: |
| 55 | +# Simple (defaults: now, ECEF) |
| 56 | +positions = propagate_constellation(constellation, np.arange(1440)) |
35 | 57 |
|
36 | | -| Scenario | astroz | python-sgp4 | Speedup | |
37 | | -|----------|--------|-------------|---------| |
38 | | -| 2 weeks (second intervals) | 160 ms | 464 ms | **2.9x** | |
39 | | -| 1 month (minute intervals) | 5.9 ms | 16.1 ms | **2.7x** | |
| 58 | +# With options |
| 59 | +positions = propagate_constellation( |
| 60 | + constellation, |
| 61 | + np.arange(14 * 1440), # 2 weeks |
| 62 | + start_time=datetime(2024, 6, 1, tzinfo=timezone.utc), |
| 63 | + output="geodetic", # "ecef" (default), "teme", or "geodetic" |
| 64 | +) |
40 | 65 |
|
41 | | -## API |
| 66 | +# With velocities |
| 67 | +positions, velocities = propagate_constellation( |
| 68 | + constellation, np.arange(1440), velocities=True |
| 69 | +) |
| 70 | +``` |
42 | 71 |
|
43 | | -### Tle |
| 72 | +## Single Satellite |
44 | 73 |
|
45 | 74 | ```python |
46 | | -tle = Tle(tle_string) |
47 | | -tle.satellite_number # NORAD catalog number |
48 | | -tle.epoch # Epoch (J2000 seconds) |
49 | | -tle.inclination # Degrees |
50 | | -tle.eccentricity |
51 | | -tle.mean_motion # Rev/day |
| 75 | +from astroz import Tle, Sgp4 |
| 76 | +import numpy as np |
| 77 | + |
| 78 | +tle = Tle("""1 25544U 98067A 24127.82853009 .00015698 00000+0 27310-3 0 9995 |
| 79 | +2 25544 51.6393 160.4574 0003580 140.6673 205.7250 15.50957674452123""") |
| 80 | + |
| 81 | +sgp4 = Sgp4(tle) |
| 82 | +pos, vel = sgp4.propagate(30.0) # 30 min after epoch |
| 83 | +positions, velocities = sgp4.propagate_batch(np.arange(1440)) |
52 | 84 | ``` |
53 | 85 |
|
54 | | -### Sgp4 |
| 86 | +## Collision Screening |
55 | 87 |
|
56 | 88 | ```python |
57 | | -sgp4 = Sgp4(tle, gravity_model=WGS84) # WGS84 (default) or WGS72 |
| 89 | +from astroz import load_constellation, propagate_constellation, coarse_screen, min_distances |
| 90 | +import numpy as np |
58 | 91 |
|
59 | | -# Single point |
60 | | -pos, vel = sgp4.propagate(tsince) # tsince in minutes |
61 | | -# Returns ((x,y,z), (vx,vy,vz)) in km and km/s (TEME frame) |
| 92 | +constellation = load_constellation("starlink") |
| 93 | +positions = propagate_constellation( |
| 94 | + constellation, np.arange(1440), |
| 95 | + output="teme", layout="satellite_major" |
| 96 | +) |
62 | 97 |
|
63 | | -# Batch (convenience) - returns allocated arrays |
64 | | -positions, velocities = sgp4.propagate_batch(times) |
| 98 | +# Find pairs within 10km |
| 99 | +pairs, t_indices = coarse_screen(positions, threshold=10.0) |
65 | 100 |
|
66 | | -# Batch (zero-copy) - writes directly to pre-allocated arrays |
67 | | -sgp4.propagate_into(times, positions, velocities) |
| 101 | +# Get exact minimum distances |
| 102 | +pairs_array = np.array(pairs, dtype=np.uint32) |
| 103 | +min_dists, min_times = min_distances(positions, pairs_array) |
68 | 104 | ``` |
69 | 105 |
|
| 106 | +## Performance |
| 107 | + |
| 108 | +| Constellation (13,448 sats × 1,440 steps) | Throughput | |
| 109 | +|--------------------------------------------|------------| |
| 110 | +| 1 thread | 7.7M props/sec | |
| 111 | +| 16 threads | 56M props/sec | |
| 112 | + |
| 113 | +Set `ASTROZ_THREADS` to control thread count. |
| 114 | + |
70 | 115 | ## Building |
71 | 116 |
|
72 | | -Requires [Zig](https://ziglang.org/) and Python 3.12+. |
| 117 | +Requires [Zig](https://ziglang.org/) and Python 3.10+. |
73 | 118 |
|
74 | 119 | ```bash |
75 | 120 | cd bindings/python |
|
0 commit comments