Ground Facility Accesses

We can compute the accesses of a satellite to a set of ground facilities using the function ground_facility_accesses:

SatelliteAnalysis.ground_facility_accesses — Function
ground_facility_accesses(orbp, [(WGS84)]; kwargs...) -> DataFrame

Compute the accesses of a satellite with orbit propagator orbp (see Propagators.init) to the ground facilities defined in the vector [(WGS84)]. The analysis interval begins in the propagator epoch plus initial_time and lasts for duration [s], where both are keywords.

The ground facilities are specified using a vector of tuples with three numbers:

Tuple{T1, T2, T3} where {T1 <: Number, T2 <: Number, T3 <: Number}

containing the WGS84 position of each ground facility [(WGS84)]:

(latitude [rad], longitude [rad], altitude [m])

This geodetic information is transformed to an ECEF vector using the function geodetic_to_ecef.

Warning

This function computes the accesses using multiple threads. Hence, the function f_eci_to_ecef must be thread safe.

Keywords

  • duration::Number: Duration of the analysis [s]. (Default: 86400)

  • f_eci_to_ecef::Function: Function to convert the orbit propagator position represented in the Earth-centered inertial (ECI) reference frame to the Earth-centered, Earth-fixed (ECEF) reference frame. The signature must be

    f_eci_to_ecef(r_i::AbstractVector, jd::Number) -> AbstractVector

    and it must return the position vector r_i represented in the ECEF at the instant jd [Julian Day]. By default, we use TEME as the ECI and PEF as the ECEF. (Default: _default_eci_to_ecef)

  • initial_time::Number: Initial time of the analysis after the propagator epoch [s]. (Default: 0)

  • minimum_elevation::Number: Minimum elevation angle for communication between the satellite and the ground facilities [rad]. (Default: 10°)

  • num_chunks::Integer: Number of chunks the algorithm will divide the time vector to compute the accesses. (Default: Threads.nthreads())

  • reduction::Function: A function that receives a boolean vector with the visibility between the satellite and each ground facility. It must return a boolean value indicating if the access must be computed or not. This is useful to merge access time between two or more facilities. (Default: any i.e. compute the access if at least one ground facility is visible)

  • step::Number: The step [s] used to propagate the orbit. Notice that we perform a cross tuning to accurately obtain the access time. However, if an access is lower than the step, it can be neglected. (Default: 60)

  • time_unit::Symbol: Select the unit in which the duration will be computed. The possible values are:

    • :s for seconds (Default);
    • :min for minutes; or
    • :h for hours.

Returns

  • DataFrame: The function returns a DataFrame with three columns:
    • access_beginning: Time of the access beginning [UTC] encoded using DateTime.
    • access_end: Time of the access end [UTC] encoded using DateTime.
    • duration: Duration of the access [time_unit].
    The unit of each column is stored in the DataFrame using metadata.

Extended Help

Throws

  • ArgumentError: If step is not positive, if duration is negative, or if time_unit is not :s, :min, or :h.

Examples

julia> using SatelliteAnalysis

julia> jd₀ = date_to_jd(2024, 1, 1);

julia> orb = KeplerianElements(
           jd₀,
           7130.982e3,
           0.001111,
           98.405 |> deg2rad,
           ltdn_to_raan(10.5, jd₀),
           π / 2,
           0
       );

julia> orbp = Propagators.init(Val(:J2), orb);

julia> ground_facility_accesses(orbp, (0, 0, 0))
2×3 DataFrame
 Row │ access_beginning         access_end               duration 
     │ DateTime                 DateTime                 Float64  
─────┼────────────────────────────────────────────────────────────
   1 │ 2024-01-01T10:20:03.136  2024-01-01T10:30:02.971   599.835
   2 │ 2024-01-01T22:49:55.910  2024-01-01T22:59:23.470   567.56

julia> ground_facility_accesses(orbp, (0, 0, 0); time_unit = :min)
2×3 DataFrame
 Row │ access_beginning         access_end               duration 
     │ DateTime                 DateTime                 Float64  
─────┼────────────────────────────────────────────────────────────
   1 │ 2024-01-01T10:20:03.136  2024-01-01T10:30:02.971   9.99725
   2 │ 2024-01-01T22:49:55.910  2024-01-01T22:59:23.470   9.45933
source

Examples

Let's compute the access time of the Amazonia-1 satellite to the INPE's ground station at Cuiabá, MT, Brazil.

First, we need to define an orbit propagator. In this case, we will use the TLE obtained from CelesTrak when this documentation was written:

julia> tle_amz1 = tle"""
           AMAZONIA 1
           1 47699U 21015A   24008.13079366  .00000299  00000+0  10693-3 0  9994
           2 47699  98.4120  87.2350 0001570  92.1147 268.0222 14.40836963150331
           """TLE: AMAZONIA 1 (Epoch = 2024-01-08T03:08:20.572):
  ├─ Line 1
  │    Satellite Number         : 47699
  │    Classification           : U
  │    International Designator : 21015A
  │    Epoch Year               : 24
  │    Epoch Day                : 8.13079366
  │    ṅ/2                      : 2.99e-6 rev/day²
  │    n̈/6                      : 0.0 rev/day³
  │    B*                       : 0.00010693 1/ER
  │    Ephemeris Type           : 0
  │    Element Set Number       : 999
  └─ Line 2
       Inclination              : 98.412°
       RA of the Ascending Node : 87.235°
       Eccentricity             : 0.000157
       Arg. of Perigee          : 92.1147°
       Mean Anomaly             : 268.0222°
       Mean Motion              : 14.40836963 rev/day
       Revolution Number        : 15033
julia> orbp = Propagators.init(Val(:SGP4), tle_amz1)OrbitPropagatorSgp4{Float64, Float64} (SGP4 Orbit Propagator): ├─ Mean Elements │ Epoch : 2.46032e6 (2024-01-08T03:08:20.572) │ Semi-Major Axis : 7133.871818 km │ Mean Motion : 14.40836963 rev/day │ Eccentricity : 0.000157 │ Inclination : 98.412° │ RA of Asc. Node : 87.235° │ Arg. of Periapsis : 92.1147° │ Mean Anomaly : 268.0222° │ B* : 0.00010693 1/ER ├─ Constants │ R₀ : 6378.137 km │ XKE : 0.07436685317 er^(3/2)/min │ J₂ : 0.001082629989 │ J₃ : -2.53215306e-6 │ J₄ : -1.61098761e-6 └─ Propagation Last Instant : 0.0 min

Now, we can compute the access time during one day considering the INPE's station at Cuiabá:

julia> ground_facility_accesses(
           orbp,
           [(-(15 + 33 / 60) |> deg2rad, -(56 + 04 / 60) |> deg2rad, 0)];
           duration = 1 * 86400,
           minimum_elevation = 5 |> deg2rad,
           time_unit = :min
       )4×3 DataFrame
 Row │ access_beginning         access_end               duration  
     │ DateTime                 DateTime                 Float64   
─────┼─────────────────────────────────────────────────────────────
   1 │ 2024-01-08T03:08:20.572  2024-01-08T03:09:16.311   0.928983
   2 │ 2024-01-08T13:56:48.099  2024-01-08T14:08:50.888  12.0465
   3 │ 2024-01-08T15:39:28.281  2024-01-08T15:43:47.366   4.31808
   4 │ 2024-01-09T02:18:02.879  2024-01-09T02:30:08.933  12.1009

If we want to change the reference frames used in the analysis, we must provide a function f_eci_to_ecef(r_i, jd) that converts the vector r_i to the desired ECEF frame at the instant jd [Julian Day]. For example, let's use the more precise ITRF instead of the PEF (default):

julia> const eop = fetch_iers_eop(Val(:IAU1980));
julia> function f_eci_to_ecef(r_teme, jd) D_itrf_teme = r_eci_to_ecef(TEME(), ITRF(), jd, eop) r_itrf = D_itrf_teme * r_teme return r_itrf endf_eci_to_ecef (generic function with 1 method)
julia> ground_facility_accesses( orbp, [(-(15 + 33 / 60) |> deg2rad, -(56 + 04 / 60) |> deg2rad, 0)]; duration = 1 * 86400, f_eci_to_ecef = f_eci_to_ecef, minimum_elevation = 5 |> deg2rad, time_unit = :min )4×3 DataFrame Row │ access_beginning access_end duration │ DateTime DateTime Float64 ─────┼──────────────────────────────────────────────────────────── 1 │ 2024-01-08T03:08:20.572 2024-01-08T03:09:16.312 0.929 2 │ 2024-01-08T13:56:48.098 2024-01-08T14:08:50.887 12.0465 3 │ 2024-01-08T15:39:28.281 2024-01-08T15:43:47.364 4.31805 4 │ 2024-01-09T02:18:02.879 2024-01-09T02:30:08.935 12.1009

We can also perform analyses using multiple ground facilities. For example, let's find the accumulated access if we consider the INPE's stations at Cuiabá, MT, Brazil, and Alcântara, MA, Brazil:

julia> ground_facility_accesses(
           orbp,
           [
               (-(15 + 33 / 60) |> deg2rad, -(56 + 04 / 60) |> deg2rad, 0)
               (-( 2 + 20 / 60) |> deg2rad, -(44 + 24 / 60) |> deg2rad, 0)
           ];
           duration = 1 * 86400,
           minimum_elevation = 5 |> deg2rad,
           time_unit = :min
       )6×3 DataFrame
 Row │ access_beginning         access_end               duration  
     │ DateTime                 DateTime                 Float64   
─────┼─────────────────────────────────────────────────────────────
   1 │ 2024-01-08T03:08:20.572  2024-01-08T03:09:16.311   0.928983
   2 │ 2024-01-08T12:16:55.777  2024-01-08T12:23:20.782   6.41675
   3 │ 2024-01-08T13:52:44.135  2024-01-08T14:08:50.888  16.1125
   4 │ 2024-01-08T15:39:28.281  2024-01-08T15:43:47.366   4.31808
   5 │ 2024-01-09T00:43:23.473  2024-01-09T00:53:25.918  10.0408
   6 │ 2024-01-09T02:18:02.879  2024-01-09T02:32:05.994  14.0519

By default, the algorithm computes the accumulated access, i.e., it considers the access active if either station has visibility to the satellite. We can change this logic by overloading the function in the keyword parameter reduction. For example, let's compute only the accesses when the satellite has visibility to both ground stations at the same time:

julia> ground_facility_accesses(
           orbp,
           [
               (-(15 + 33 / 60) |> deg2rad, -(56 + 04 / 60) |> deg2rad, 0)
               (-( 2 + 20 / 60) |> deg2rad, -(44 + 24 / 60) |> deg2rad, 0)
           ];
           duration = 1 * 86400,
           minimum_elevation = 5 |> deg2rad,
           reduction = v -> (&)(v...),
           time_unit = :min
       )2×3 DataFrame
 Row │ access_beginning         access_end               duration 
     │ DateTime                 DateTime                 Float64  
─────┼────────────────────────────────────────────────────────────
   1 │ 2024-01-08T13:56:48.099  2024-01-08T14:04:29.601   7.6917
   2 │ 2024-01-09T02:21:47.636  2024-01-09T02:30:08.933   8.35495