# Pyorbital

Pyorbital is a python package to compute orbital parameters for satellites from TLE files as well as astronomical parameters of interest for satellite remote sensing. Currently Pyorbital only supports low earth orbit satellites.

## Installation

Pyorbital is available from the Python Package Index (PyPI) via pip or from the conda-forge conda channel. To install from PyPI in an existing environment:

    pip install pyorbital

Or in an existing conda-based environment:

    conda install -c conda-forge pyorbital

### From Source

Pyorbital can also be installed from source. If you want to install pyorbital from the latest in-development version on GitHub you can run:

    pip install git+https://github.com/pytroll/pyorbital.git

However, if you instead want to edit the source code and see the changes reflected when you run the code you can clone the git repository and install it in “editable” mode:

    git clone git://github.com/pytroll/pyorbital.git
    cd pyorbital
    pip install -e .

## Add platform missing information

Pyorbital comes with a file platforms.txt that maps a satellite name to the NORAD identifier.

This file already contain many low earth orbiting environmental or meteorological satellites and thus likely be sufficient for your purpose.

But should it not contain your satellites of interest make a copy of the platforms.txt file and add the missing satellites and their NORAD identifiers and place the file in the directory pointed to by `PYORBITAL_CONFIG_PATH`.

The NORAD identifier can be found as the first number of each line in the Two-Line Elements files (eg. from celestrak).

Pyorbital comes with a small script `check_platform.py` to check whether a satellite is already supported.

    python -m pyorbital.check_platform -s NOAA-21

    [INFO: 2023-01-22 21:20:25 : pyorbital.tlefile] Satellite NOAA-21 is supported. NORAD number: 54234
    [INFO: 2023-01-22 21:20:25 : pyorbital.tlefile] Satellite names and NORAD numbers are defined in /path/to/pyorbital/etc/directory/platforms.txt

## TLE files

Pyorbital has a module for parsing NORAD TLE-files

    >>> from pyorbital import tlefile
    >>> tle = tlefile.read('noaa 18', '/path/to/my/tle_file.txt')
    >>> tle.inclination
    99.043499999999995

If no path is provided pyorbital first tries to read any local TLE files defined by the environment variable `TLES` giving a glob pattern that can be used to retrieve all relevant files:

    TLES=/path/to/tle_files/*/tle*txt

If this variable is not set Pyorbital will try get the earth observation TLE files over the internet from celestrak. Note this downloading only happens if no specific TLE file is provided or if the `TLES` environment variable is not set.

### TLE download and database

The historical TLE files can be requested from celestrak’s request page.

There is also a script, `fetch_tles.py`, that can be used to collect TLE data from several locations. The currently supported locations are:

- generic network locations without login

- Space-Track (login credentials needed)

- local files

The data are saved in a SQLite3 database, and can be written to a file after each run. To see configuration options, see the example configuration in `examples/tle.yaml`.

## Computing satellite position

The orbital module enables computation of satellite position and velocity at a specific time:

    >>> from pyorbital.orbital import Orbital
    >>> from datetime import datetime
    >>> # Use current TLEs from the internet:
    >>> orb = Orbital("Suomi NPP")
    >>> now = datetime.utcnow()
    >>> # Get normalized position and velocity of the satellite:
    >>> orb.get_position(now)
    (array([-0.20015267,  0.09001458,  1.10686756]),
     array([ 0.06148495,  0.03234914,  0.00846805]))
    >>> # Get longitude, latitude and altitude of the satellite:
    >>> orb.get_lonlatalt(now)
    (40.374855865574951, 78.849923885700363, 839.62504115338368)

## Use actual TLEs to increase accuracy

    >>> from pyorbital.orbital import Orbital
    >>> from datetime import datetime
    >>> orb = Orbital("Suomi NPP")
    >>> dtobj = datetime(2015,2,7,3,0)
    >>> orb.get_lonlatalt(dtobj)
    (152.11564698762811, 20.475251739329622, 829.37355785502211)

But since we are interested in knowing the position of the Suomi-NPP more than two and half years from now (September 26, 2017) we can not rely on the current TLEs, but rather need a TLE closer to the time of interest:

    >>> snpp = Orbital('Suomi NPP', tle_file='/path/to/tle/files/tle-20150207.txt')
    >>> snpp.get_lonlatalt(dtobj)
    (105.37373804512762, 79.160752404540133, 838.94605490133154)

If we take a TLE from one week earlier we get a slightly different result:

    >>> snpp = Orbital('Suomi NPP', tle_file='/path/to/tle/files/tle-20150131.txt')
    >>> snpp.get_lonlatalt(dtobj)
    (104.1539184988462, 79.328272480878141, 838.81555967963391)

## Computing astronomical parameters

The astronomy module enables computation of certain parameters of interest for satellite remote sensing for instance the Sun-zenith angle:

    >>> from pyorbital import astronomy
    >>> from datetime import datetime
    >>> utc_time = datetime(2012, 5, 15, 15, 45)
    >>> lon, lat = 12, 56
    >>> astronomy.sun_zenith_angle(utc_time, lon, lat)
    62.685986438071602

PYORBITAL_CONFIG_PATH

  It is possible (but not mandatory) to define this environment variable to have full control of certain static data used by Pyorbital:

  Pyorbital comes with a file platforms.txt that maps a satellite name to the NORAD identifier. This internal file is accessed by Pyorbital without the user having to do anything. But if you need to change or update this file you can make your own copy and place in the directory pointed to by this environment variable.

TLES

  Two Line Element (TLE) files are accessed automatically over the internet without the user having to do anything. When doing that Pyorbital will fetch the most recent TLE data which may not be the most optimal for historic data for instance. Also, it may not be sustainable in a production environment.

  However, it is possible to let Pyorbital look for the necessary and more optimal TLE data locally, by specifying locations where such local TLE files are located. If the TLES environment variable is set to a glob pattern to local locations, Pyorbital will first search for the needed TLEs there. This can both be useful in an operational setup where access to the internet is restricted, and when processing old/historic satellite data.

  It is possible (but not mandatory) to define this environment variable.

## API

### Orbital computations

Module for computing the orbital parameters of satellites.

class pyorbital.orbital.OrbitElements(tle)

  Class holding the orbital elements.

class pyorbital.orbital.Orbital(satellite, tle_file=None, line1=None, line2=None)

  Class for orbital computations.

  The satellite parameter is the name of the satellite to work on and is used to retrieve the right TLE data for internet or from tle_file in case it is provided.

  find_aol(utc_time, lon, lat)

    Find AOL.

  find_aos(utc_time, lon, lat)

    Find AOS.

  get_equatorial_crossing_time(tstart, tend, node='ascending', local_time=False, rtol=1e-09)

    Estimate the equatorial crossing time of an orbit.

    The crossing time is determined via the orbit number, which increases by one if the spacecraft passes the ascending node at the equator. A bisection algorithm is used to find the time of that passage.

    Parameters:

      - tstart – Start time of the orbit

      - tend – End time of the orbit. Orbit number at the end must be at least one greater than at the start. If there are multiple revolutions in the given time interval, the crossing time of the last revolution in that interval will be computed.

      - node – Specifies whether to compute the crossing time at the ascending or descending node. Choices: (‘ascending’, ‘descending’).

      - local_time – By default the UTC crossing time is returned. Use this flag to convert UTC to local time.

      - rtol – Tolerance of the bisection algorithm. The smaller the tolerance, the more accurate the result.

  get_last_an_time(utc_time)

    Calculate time of last ascending node relative to the specified time.

  get_lonlatalt(utc_time)

    Calculate sublon, sublat and altitude of satellite.

    http://celestrak.com/columns/v02n03/

  get_next_passes(utc_time, length, lon, lat, alt, tol=0.001, horizon=0)

    Calculate passes for the next hours for a given start time and a given observer.

    Original by Martin.

    Utc_time:

      Observation time (datetime object)

    Length:

      Number of hours to find passes (int)

    Lon:

      Longitude of observer position on ground (float)

    Lat:

      Latitude of observer position on ground (float)

    Alt:

      Altitude above sea-level (geoid) in km of observer position on ground (float)

    Tol:

      precision of the result in seconds

    Horizon:

      the elevation of horizon to compute risetime and falltime.

    Returns:

      [(rise-time, fall-time, max-elevation-time), …]

  get_observer_look(utc_time, lon, lat, alt)

    Calculate observers look angle to a satellite.

    See http://celestrak.com/columns/v02n02/

    utc_time: Observation time (datetime object) lon: Longitude of observer position on ground in degrees east lat: Latitude of observer position on ground in degrees north alt: Altitude above sea-level (geoid) of observer position on ground in km

    Return: (Azimuth, Elevation)

  get_orbit_number(utc_time, tbus_style=False, as_float=False)

    Calculate orbit number at specified time.

    Parameters:

      - utc_time – UTC time as a datetime.datetime object.

      - tbus_style – If True, use TBUS-style orbit numbering (TLE orbit number + 1)

      - as_float – Return a continuous orbit number as float.

  get_position(utc_time, normalize=True)

    Get the cartesian position and velocity from the satellite.

  utc2local(utc_time)

    Convert UTC to local time.

exception pyorbital.orbital.OrbitalError

  Custom exception for the Orbital class.

pyorbital.orbital.get_observer_look(sat_lon, sat_lat, sat_alt, utc_time, lon, lat, alt)

  Calculate observers look angle to a satellite.

  http://celestrak.com/columns/v02n02/

  Utc_time:

    Observation time (datetime object)

  Lon:

    Longitude of observer position on ground in degrees east

  Lat:

    Latitude of observer position on ground in degrees north

  Alt:

    Altitude above sea-level (geoid) of observer position on ground in km

  Returns:

    (Azimuth, Elevation)

pyorbital.orbital.kep2xyz(kep)

  Keppler to cartesian coordinates conversion.

  (Not sure what ‘kep’ actually refers to, just guessing! FIXME!)

### TLE handling

Classes and functions for handling TLE files.

exception pyorbital.tlefile.ChecksumError

  ChecksumError.

class pyorbital.tlefile.Downloader(config)

  Class for downloading TLE data.

  fetch_plain_tle()

    Fetch plain text-formated TLE data.

  fetch_spacetrack()

    Fetch TLE data from Space-Track.

  read_tle_files()

    Read TLE data from files.

  read_xml_admin_messages()

    Read Eumetsat admin messages in XML format.

pyorbital.tlefile.SATELLITES = {'ALOS-2': '39766', 'CALIPSO': '29108', 'CLOUDSAT': '29107', 'CRYOSAT-2': '36508', 'CSK-1': '31598', 'CSK-2': '32376', 'CSK-3': '33412', 'CSK-4': '37216', 'DMSP-F15': '25991', 'DMSP-F16': '28054', 'DMSP-F17': '29522', 'DMSP-F18': '35951', 'DMSP-F19': '39630', 'EOS-AQUA': '27424', 'EOS-AURA': '28376', 'EOS-TERRA': '25994', 'FY-2D': '29640', 'FY-2E': '33463', 'FY-2F': '38049', 'FY-2G': '40367', 'FY-3A': '32958', 'FY-3B': '37214', 'FY-3C': '39260', 'FY-3D': '43010', 'FY-3E': '49008', 'FY-3F': '57490', 'FY-3G': '56232', 'GOES-13': '29155', 'GOES-14': '35491', 'GOES-15': '36411', 'GOES-16': '41866', 'GOES-17': '43226', 'GOES-18': '51850', 'GOES-19': '60133', 'HIMAWARI-6': '28622', 'HIMAWARI-7': '28937', 'HIMAWARI-8': '40267', 'HIMAWARI-9': '41836', 'INSAT-3A': '27714', 'INSAT-3C': '27298', 'INSAT-3D': '39216', 'JASON-2': '33105', 'KALPANA-1': '27525', 'LANDSAT-7': '25682', 'LANDSAT-8': '39084', 'METEOSAT-10': '38552', 'METEOSAT-11': '40732', 'METEOSAT-12': '54743', 'METEOSAT-7': '24932', 'METEOSAT-8': '27509', 'METEOSAT-9': '28912', 'METOP-A': '29499', 'METOP-B': '38771', 'METOP-C': '43689', 'NOAA-10': '16969', 'NOAA-11': '19531', 'NOAA-12': '21263', 'NOAA-14': '23455', 'NOAA-15': '25338', 'NOAA-16': '26536', 'NOAA-17': '27453', 'NOAA-18': '28654', 'NOAA-19': '33591', 'NOAA-20': '43013', 'NOAA-21': '54234', 'NOAA-6': '11416', 'NOAA-7': '12553', 'NOAA-8': '13923', 'NOAA-9': '15427', 'RADARSAT-2': '32382', 'SENTINEL-1A': '39634', 'SENTINEL-1B': '41456', 'SENTINEL-2A': '40697', 'SENTINEL-2B': '42063', 'SENTINEL-3A': '41335', 'SENTINEL-3B': '43437', 'SENTINEL-5P': '42969', 'SMOS': '36036', 'SPOT-5': '27421', 'SPOT-6': '38755', 'SPOT-7': '40053', 'SUOMI-NPP': '37849', 'TANDEM-X': '36605', 'TERRASAR-X': '31698', 'TIROS-N': '11060'}

  The platform numbers are given in a file $PYORBITAL_CONFIG_PATH/platforms.txt in the following format:

      # Mappings between satellite catalogue numbers and corresponding
      # platform names from OSCAR.
      ALOS-2 39766
      CloudSat 29107
      CALIPSO 29108
      CryoSat-2 36508
      CSK-1 31598
      CSK-2 32376
      CSK-3 33412
      CSK-4 37216
      DMSP-F15 25991
      DMSP-F16 28054
      DMSP-F17 29522
      DMSP-F18 35951
      DMSP-F19 39630
      EOS-Aqua 27424
      EOS-Aura 28376
      EOS-Terra 25994
      FY-2D 29640
      FY-2E 33463
      FY-2F 38049
      FY-2G 40367
      FY-3A 32958
      FY-3B 37214
      FY-3C 39260
      FY-3D 43010
      FY-3E 49008
      FY-3F 57490
      FY-3G 56232
      GOES-13 29155
      GOES-14 35491
      GOES-15 36411
      GOES-16 41866
      GOES-17 43226
      GOES-18 51850
      GOES-19 60133
      Himawari-6 28622
      Himawari-7 28937
      Himawari-8 40267
      Himawari-9 41836
      INSAT-3A 27714
      INSAT-3C 27298
      INSAT-3D 39216
      JASON-2 33105
      Kalpana-1 27525
      Landsat-7 25682
      Landsat-8 39084
      Meteosat-7 24932
      Meteosat-8 27509
      Meteosat-9 28912
      Meteosat-10 38552
      Meteosat-11 40732
      Meteosat-12 54743
      Metop-A 29499
      Metop-B 38771
      Metop-C 43689
      TIROS-N 11060
      NOAA-6 11416
      NOAA-7 12553
      NOAA-8 13923
      NOAA-9 15427
      NOAA-10 16969
      NOAA-11 19531
      NOAA-12 21263
      NOAA-14 23455
      NOAA-15 25338
      NOAA-16 26536
      NOAA-17 27453
      NOAA-18 28654
      NOAA-19 33591
      NOAA-20 43013
      NOAA-21 54234
      RadarSat-2 32382
      Sentinel-1A 39634
      Sentinel-1B 41456
      Sentinel-2A 40697
      Sentinel-2B 42063
      Sentinel-3A 41335
      Sentinel-3B 43437
      Sentinel-5P 42969
      SMOS 36036
      SPOT-5 27421
      SPOT-6 38755
      SPOT-7 40053
      Suomi-NPP 37849
      TanDEM-X 36605
      TerraSAR-X 31698

class pyorbital.tlefile.SQLiteTLE(db_location, platforms, writer_config)

  Store TLE data in a sqlite3 database.

  close()

    Close the database.

  update_db(tle, source)

    Update the collected data.

    Only data with newer epoch than the existing one is used.

  write_tle_txt()

    Write TLE data to a text file.

class pyorbital.tlefile.Tle(platform, tle_file=None, line1=None, line2=None)

  Class holding TLE objects.

  property line1

    Return first TLE line.

  property line2

    Return second TLE line.

  property platform

    Return satellite platform name.

exception pyorbital.tlefile.TleDownloadTimeoutError

  TLE download timeout exception.

pyorbital.tlefile.check_is_platform_supported(satname)

  Check if satellite is supported and print info.

pyorbital.tlefile.collect_filenames(paths)

  Collect all filenames from paths.

pyorbital.tlefile.fetch(destination)

  Fetch TLE from internet and save it to destination.

pyorbital.tlefile.get_platforms_filepath()

  Get the platforms.txt file path.

  Check that the file exists or raise an error.

pyorbital.tlefile.main()

  Run a test TLE reading.

pyorbital.tlefile.read(platform, tle_file=None, line1=None, line2=None)

  Read TLE for platform.

  The data are read from tle_file, from line1 and line2, from the newest file provided in the TLES pattern, or from internet if none is provided.

pyorbital.tlefile.read_platform_numbers(filename, in_upper=False, num_as_int=False)

  Read platform numbers from $PYORBITAL_CONFIG_PATH/platforms.txt.

pyorbital.tlefile.read_tle_from_mmam_xml_file(fname)

  Read TLE data from MMAM XMl file (EUMETSAT).

pyorbital.tlefile.read_tles_from_mmam_xml_files(paths)

  Read TLE data from a list of MMAM XMl file (EUMETSAT).

  MMAM = Multi-Mission Administration Message

pyorbital.tlefile.table_exists(db, name)

  Check if the table ‘name’ exists in the database.

### Astronomical computations

Angle and time-based astronomy functions.

Parts taken from http://www.geoastro.de/elevaz/basics/index.htm

#### Note on argument types

Many of these functions accept Python datetime objects, numpy datetime64 objects, or anything that can be turned into a numpy array of datetime64 objects. These objects are inherently 64-bit so if other arguments (ex. longitude and latitude arrays) are 32-bit floats internal operations will be automatically promoted to 64-bit floating point numbers. Where possible these are then converted back to 32-bit before being returned. In general scalar inputs will also produce scalar outputs.

pyorbital.astronomy.cos_zen(utc_time, lon, lat)

  Derive the cosine of the sun-zenith angle for lon, lat at utc_time.

  utc_time: datetime.datetime instance of the UTC time lon: Longitude in degrees lat: Latitude in degrees. Returns: Cosine of the sun zenith angle.

pyorbital.astronomy.get_alt_az(utc_time, lon, lat)

  Return sun altitude and azimuth from utc_time, lon, and lat.

  lon,lat in degrees The returned angles are given in radians.

pyorbital.astronomy.gmst(utc_time)

  Greenwich mean sidereal utc_time, in radians.

  As defined in the AIAA 2006 implementation: http://www.celestrak.com/publications/AIAA/2006-6753/

pyorbital.astronomy.jdays(utc_time)

  Get the julian day of utc_time.

pyorbital.astronomy.jdays2000(utc_time)

  Get the days since year 2000.

pyorbital.astronomy.observer_position(utc_time, lon, lat, alt)

  Calculate observer ECI position.

  http://celestrak.com/columns/v02n03/

pyorbital.astronomy.sun_earth_distance_correction(utc_time)

  Calculate the sun earth distance correction, relative to 1 AU.

pyorbital.astronomy.sun_ecliptic_longitude(utc_time)

  Ecliptic longitude of the sun at utc_time.

pyorbital.astronomy.sun_ra_dec(utc_time)

  Right ascension and declination of the sun at utc_time.

pyorbital.astronomy.sun_zenith_angle(utc_time, lon, lat)

  Sun-zenith angle for lon, lat at utc_time.

  lon,lat in degrees. The sun zenith angle returned is in degrees.