Interface to the Predict satellite tracking and orbital prediction library
Project description
PyPredict
NOTE: To preserve compatibility with
predict
, pypredict uses north latitude and west longitude for terrestrial coordinates.
Do you want accurate and time-tested satellite tracking and pass prediction in a convenient python wrapper? You're in the right place.
PyPredict is a C Python extension directly adapted from the ubiquitous predict satellite tracking command line application. Originally written for the commodore 64, predict has a proven pedigree; We just aim to provide a convenient API. PyPredict is a port of the predict codebase and should yield identical results.
If you think you've found an error in pypredict
, please include output from predict
on same inputs to the bug report.
If you think you've found a bug in predict, please report and we'll coordinate with upstream.
Installation
sudo apt-get install python-dev
sudo python setup.py install
Usage
Observe a satellite (relative to a position on earth)
import predict
tle = """0 LEMUR 1
1 40044U 14033AL 15013.74135905 .00002013 00000-0 31503-3 0 6119
2 40044 097.9584 269.2923 0059425 258.2447 101.2095 14.72707190 30443"""
qth = (37.771034, 122.413815, 7) # lat (N), long (W), alt (meters)
predict.observe(tle, qth) # optional time argument defaults to time.time()
# => {'altitude': 676.8782276657903,
# 'azimuth': 96.04762045174824,
# 'beta_angle': -27.92735429908726,
# 'decayed': 0,
# 'doppler': 1259.6041017128405,
# 'eci_obs_x': -2438.227652191655,
# 'eci_obs_y': -4420.154476060397,
# 'eci_obs_z': 3885.390601342013,
# 'eci_sun_x': 148633398.020844,
# 'eci_sun_y': -7451536.44122029,
# 'eci_sun_z': -3229999.50056359,
# 'eci_vx': 0.20076213530665032,
# 'eci_vy': -1.3282146055077213,
# 'eci_vz': 7.377067234096598,
# 'eci_x': 6045.827328897242,
# 'eci_y': -3540.5885778261277,
# 'eci_z': -825.4065096776636,
# 'eclipse_depth': -87.61858291647795,
# 'elevation': -43.711904591801726,
# 'epoch': 1521290038.347793,
# 'footprint': 5633.548906707907,
# 'geostationary': 0,
# 'has_aos': 1,
# 'latitude': -6.759563817939698,
# 'longitude': 326.1137007912563,
# 'name': '0 LEMUR 1',
# 'norad_id': 40044,
# 'orbit': 20532,
# 'orbital_model': 'SGP4',
# 'orbital_phase': 145.3256815318047,
# 'orbital_velocity': 26994.138671706416,
# 'slant_range': 9743.943478523843,
# 'sunlit': 1,
# 'visibility': 'D'
# }
Show upcoming transits of satellite over ground station
# start and stop transit times as UNIX timestamp
transit_start = 1680775200
transit_stop = 1681034400
p = predict.transits(tle, qth, transit_start, transit_stop)
print("Start of Transit\tTransit Duration (s)\tPeak Elevation")
for transit in p:
print(f"{transit.start}\t{transit.duration()}\t{transit.peak()['elevation']}")
Modeling an entire constellation
Generating transits for a lot of satellites over a lot of ground stations can be slow. Luckily, generating transits for each satellite-groundstation pair can be parallelized for a big speed-up.
import itertools
from multiprocessing.pool import Pool
import time
import predict
import requests
# Define a function that returns arguments for all the transits() calls you want to make
def _transits_call_arguments():
now = time.time()
tle = requests.get('http://tle.spire.com/25544').text.rstrip()
for latitude in range(-90, 91, 15):
for longitude in range(-180, 181, 15):
qth = (latitude, longitude, 0)
yield {'tle': tle, 'qth': qth, 'ending_before': now+60*60*24*7}
# Define a function that calls the transit function on a set of arguments and does per-transit processing
def _transits_call_fx(kwargs):
try:
transits = list(predict.transits(**kwargs))
return [t.above(10) for t in transits]
except predict.PredictException:
pass
# Map the transit() caller across all the arguments you want, then flatten results into a single list
pool = Pool(processes=10)
array_of_results = pool.map(_transits_call_fx, _transits_call_arguments())
flattened_results = list(itertools.chain.from_iterable(filter(None, array_of_results)))
transits = flattened_results
NOTE: If precise accuracy isn't necessary (for modeling purposes, for example) setting the tolerance argument
to the above
call to a larger value, say 1 degree, can provide a significant performance boost.
Call predict analogs directly
predict.quick_find(tle.split('\n'), time.time(), (37.7727, 122.407, 25))
predict.quick_predict(tle.split('\n'), time.time(), (37.7727, 122.407, 25))
API
observe(tle, qth[, at=None]) Return an observation of a satellite relative to a groundstation. qth groundstation coordinates as (lat(N),long(W),alt(m)) If at is not defined, defaults to current time (time.time()) Returns an "observation" or dictionary containing: altitude _ altitude of satellite in kilometers azimuth - azimuth of satellite in degrees from perspective of groundstation. beta_angle decayed - 1 if satellite has decayed out of orbit, 0 otherwise. doppler - doppler shift between groundstation and satellite. eci_obs_x eci_obs_y eci_obs_z eci_sun_x eci_sun_y eci_sun_z eci_vx eci_vy eci_vz eci_x eci_y eci_z eclipse_depth elevation - elevation of satellite in degrees from perspective of groundstation. epoch - time of observation in seconds (unix epoch) footprint geostationary - 1 if satellite is determined to be geostationary, 0 otherwise. has_aos - 1 if the satellite will eventually be visible from the groundstation latitude - north latitude of point on earth directly under satellite. longitude - west longitude of point on earth directly under satellite. name - name of satellite from first line of TLE. norad_id - NORAD id of satellite. orbit orbital_phase orbital_model orbital_velocity slant_range - distance to satellite from groundstation in meters. sunlit - 1 if satellite is in sunlight, 0 otherwise. visibility transits(tle, qth[, ending_after=None][, ending_before=None]) Returns iterator of Transit objects representing passes of tle over qth. If ending_after is not defined, defaults to current time If ending_before is not defined, the iterator will yield until calculation failure.
NOTE: We yield passes based on their end time. This means we'll yield currently active passes in the two-argument invocation form, but their start times will be in the past.
Transit(tle, qth, start, end) Utility class representing a pass of a satellite over a groundstation. Instantiation parameters are parsed and made available as fields. duration() Returns length of transit in seconds peak(epsilon=0.1) Returns epoch time where transit reaches maximum elevation (within ~epsilon) at(timestamp) Returns observation during transit via quick_find(tle, timestamp, qth) aboveb(elevation, tolerance) Returns portion of transit above elevation. If the entire transit is below the target elevation, both endpoints will be set to the peak and the duration will be zero. If a portion of the transit is above the elevation target, the endpoints will be between elevation and elevation + tolerance (unless endpoint is already above elevation, in which case it will be unchanged) quick_find(tle[, time[, (lat, long, alt)]]) time defaults to current time (lat, long, alt) defaults to values in ~/.predict/predict.qth Returns observation dictionary equivalent to observe(tle, time, (lat, long, alt)) quick_predict(tle[, time[, (lat, long, alt)]]) Returns an array of observations for the next pass as calculated by predict. Each observation is identical to that returned by quick_find.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Hashes for pypredict-1.7.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | bd1940b22906c74a35ea003c3b85c8ca22c4a6d9d31b1c490770695884cfd1fc |
|
MD5 | 8faa1d554e511801dd6099cd6cf62cae |
|
BLAKE2b-256 | 7e65713cbce7c7e0502727d1196b94706f4e6ca50e0a821bbf57e11c66487a8c |
Hashes for pypredict-1.7.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 9307f56c27a769834dc31c4d6204d8d93619004e7630da33bee821f2b64b5527 |
|
MD5 | 34adfab99660cc28e4d1e611a15569aa |
|
BLAKE2b-256 | 9ace4726c1a92d495bc1d229c09ab830e169124b250c9afb5079b0230b29c354 |
Hashes for pypredict-1.7.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 35f39c017128d88afea116fe9ba7762c6804b2c034a5f858c501014c1fee2792 |
|
MD5 | 0c250534409a0c3ee32b2dd9e4f39fd4 |
|
BLAKE2b-256 | 84cf951a919022bcdfa81a5f313f6a936e2d3c00084c93c163db4f71dda908d6 |
Hashes for pypredict-1.7.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 7f159a44d37a18849d1a46717b88ffe4df3bdc6f4b8273449aae5eefba09599d |
|
MD5 | ce3d0972f60435d10c46001ee9917e83 |
|
BLAKE2b-256 | e5869af7e4f280790b5cf408afc6453e886e763dc987935d43ba0280584356b7 |
Hashes for pypredict-1.7.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 8e65c4f40d55ea88ebf7afe6df8a8df6157fbcaff8bc7a6bdabf1d2af1d17fd6 |
|
MD5 | 8c37e2ddd56fbfaf46abacd087842bd6 |
|
BLAKE2b-256 | 8edd22b7b5beb7d3f54d0962227354f04a2f21593300aa669a2d08c49679a73c |
Hashes for pypredict-1.7.1-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 3ab430372af8237d60b2210b5ebf2f63e51ca62a63c5ffb72a068589b553fabe |
|
MD5 | bd46899f6dce53d8f96fb6513ce17efd |
|
BLAKE2b-256 | 2fc6edd2c295e28be33ae74f79b01552d056f8863bc734c626d9e0b5e59f2344 |
Hashes for pypredict-1.7.1-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | f1b921570fdf2d56c095305fb1fd368ddf1ad6f19769b48ed86b799960d29529 |
|
MD5 | d4e3f3aba6cd789af72ad1bd0d2f7d1a |
|
BLAKE2b-256 | 2d8056fb47fbab0dc5175857f8b88d0ac31b8920b0f92ce652eabd747b37cbe7 |