Source code for satkit.events.gnd_access

# satkit: Satellite Mission Analysis and Design for Python
#
# Copyright (C) 2023 Egemen Imre
#
# Licensed under GNU GPL v3.0. See LICENSE.rst for more info.
"""
Module for ground-based accesses and passes.

"""

from org.orekit.bodies import GeodeticPoint, OneAxisEllipsoid
from org.orekit.frames import TopocentricFrame
from org.orekit.models import AtmosphericRefractionModel
from org.orekit.propagation import Propagator
from org.orekit.time import AbsoluteDate
from org.orekit.utils import ElevationMask
from pint import Quantity

from satkit import u
from satkit.events.eventfinders import gnd_pass_finder
from satkit.time.timeinterval import TimeInterval
from satkit.utils.utilities import (
    compute_gnd_az_el,
    compute_gnd_az_el_list,
    init_topo_frame,
)


@u.wraps(None, (None, None, None, None, None, None, "sec"), False)
class GroundPass:
    """
    Parameters associated with a "pass" (line-of-sight availability) over
    a ground location.

    A "pass" could be a satellite communications pass over a ground station
    or an observation opportunity for a ground observation station. The object
    then holds information such as pass duration, peak elevation time and value
    and azimuth-elevation-range list.

    The constructor computes the pass properties given the pass time interval.
    For RF applications (e.g., radar or comms) atmospheric refraction should *not*
    be used. Atmospheric refraction is useful for optical applications (e.g.,
    satellite tracking with a telescope).

    Usually this object is not created manually, but is an outcome of the calculation
    of a list of passes over a ground location.

    Parameters
    ----------
    pass_interval
        Time interval of the pass (shallow copied into the object)
    max_elev_time
        Time of maximum elevation (shallow copied into the object)
    gnd_pos
        Ground position in geodetic coordinates (or the topocentric frame associated with it)
    propagator
        Propagator to generate the trajectory of the satellite (or any other object)
    planet
        The planet where the ground location is located. Defaults to WGS84 Earth.
    refraction_model
        Atmospheric Refraction Model, defaults to `None`
    az_el_timestep
        Stepsize for the azimuth-elevation-range list
    """

    def __init__(
        self,
        pass_interval: TimeInterval,
        max_elev_time: AbsoluteDate,
        gnd_pos: GeodeticPoint | TopocentricFrame,
        propagator: Propagator,
        planet: OneAxisEllipsoid = None,
        refraction_model: AtmosphericRefractionModel = None,
        az_el_timestep=60 * u.sec,
    ):
        # shallow copy the interval
        self.pass_interval = pass_interval

        # shallow copy the max elevation time
        self.max_elev_time = max_elev_time

        # compute max elevation AER values
        frame = propagator.getFrame()
        pvt_max_elev = propagator.getPVCoordinates(max_elev_time, frame)

        self.max_elev_aer = compute_gnd_az_el(
            max_elev_time, gnd_pos, pvt_max_elev, frame, planet, refraction_model
        )

        # compute az-el list (with atmospheric refraction where necessary)
        self.az_el_list = compute_gnd_az_el_list(
            pass_interval,
            gnd_pos,
            propagator,
            planet,
            refraction_model,
            az_el_timestep,
        )


[docs]class GroundPassList: @u.wraps(None, (None, None, None, "rad", None, None, None, "sec"), False) def __init__( self, search_interval: TimeInterval, gnd_pos: GeodeticPoint | TopocentricFrame, elev_mask: float | Quantity | ElevationMask, propagator: Propagator, planet: OneAxisEllipsoid = None, refraction_model: AtmosphericRefractionModel = None, az_el_timestep=60 * u.sec, ): """ Parameters associated with a list of "passes" (line-of-sight availability) over a ground location. The constructor computes the pass properties given the search interval. A "pass" could be a satellite communications pass over a ground station or an observation opportunity for a ground observation station. The object then holds information such as pass duration, peak elevation time and value as well as azimuth-elevation-range list for multiple such passes or `GroundPass` objects. This method is not limited to a ground location on Earth (as defined by the `planet` parameter). It uses the Orekit `ElevationDetector` to find the "elevation equal to elevation mask" events. However, the cases with "no events in the search interval" are handled correctly. The output is a `TimeIntervalList` which can then be intersected with another interval list, for example "ground location illuminated intervals". The method accepts both a fixed elevation mask or an `ElevationMask` with a complex mask shape. The planet parameter can be any `OneAxisEllipsoid` with its own fixed frame. For example, Earth can be generated as follows:: itrf = FramesFactory.getITRF(IERSConventions.IERS_2010, True) earth = OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, Constants.WGS84_EARTH_FLATTENING, itrf) If the `gnd_pos` parameter is defined as a `TopocentricFrame`, then the optional planet parameter is ignored. Otherwise, it is set to Earth as given above. Atmospheric Refraction Model should be set to `None` for communications applications. It can be set to `EarthITU453AtmosphereRefraction` or `EarthStandardAtmosphereRefraction` (provided by Orekit) for visual or optical applications. Parameters ---------- search_interval Search interval for the "elevation events" gnd_pos Ground position in geodetic coordinates (or the topocentric frame associated with it) elev_mask Elevation mask, either a fixed value or a complex mask shape propagator Propagator to generate the trajectory of the satellite (or any other object) planet The planet where the ground location is located. Defaults to WGS84 Earth. refraction_model Atmospheric Refraction Model, defaults to `None` az_el_timestep Stepsize for the azimuth-elevation-range list """ # init topocentric frame topo_frame = init_topo_frame(gnd_pos, planet) # find the ground pass intervals and max elevations self.pass_intervals, max_elev_times = gnd_pass_finder( search_interval, topo_frame, elev_mask, propagator, planet, refraction_model, ) # compute the Ground Passes self.pass_list = [] for interval, max_elev_time in list( zip(self.pass_intervals.intervals, max_elev_times) ): # compute the pass details gnd_pass = GroundPass( interval, max_elev_time, topo_frame, propagator, planet, refraction_model, az_el_timestep, ) self.pass_list.append(gnd_pass)