Library

Documentation for SatelliteAnalysis.jl.

SatelliteAnalysis._F_and_∂F_l0p — Method
_F_and_∂F_l0p(l::Integer, p::Integer, sin_i::BigFloat, cos_i::BigFloat) -> BigFloat, BigFloat

Compute the inclination function F_{l,0,p}(i) and its derivative ∂F_{l,0,p} / ∂i as defined in [1, p. 642]. The inclination is specified by its sine sin_i [-] and cosine cos_i [-], allowing the caller to compute them only once for all the degrees.

Note

Internally, we must use BigFloat to allow calculations on high degrees.

References

  • [1] Vallado, D. A (2013). Fundamentals of Astrodynamics and Applications. 4th ed. Microcosm Press, Hawthorne, CA.
source
SatelliteAnalysis._angle_unit_factor — Method
_angle_unit_factor(angle_unit::Symbol) -> Float64

Return the factor that converts an angle in radians to the unit angle_unit, which can be :rad for radians or :deg for degrees.

Extended help

Throws

  • ArgumentError: If angle_unit is not :rad or :deg.
source
SatelliteAnalysis._default_eci_to_ecef — Method
_default_eci_to_ecef(r_eci::AbstractVector, jd::Number) -> AbstractVector

Convert the vector r_eci from the Earth-centered inertial (ECI) reference frame to the Earth-centered, Earth-fixed (ECEF) reference frame at the instant jd [Julian Day, UTC]. This function considers TEME as the ECI reference frame and PEF as the ECEF reference frame. It is the default value of the keyword f_eci_to_ecef in the analyses, and it is thread-safe.

source
SatelliteAnalysis._distance_unit_factor — Method
_distance_unit_factor(distance_unit::Symbol) -> Float64

Return the factor that converts a distance in meters to the unit distance_unit, which can be :m for meters or :km for kilometers.

Extended help

Throws

  • ArgumentError: If distance_unit is not :m or :km.
source
SatelliteAnalysis._extension_error — Method
_extension_error(function_name::String, packages::String, using_example::String, valid_call::String) -> Union{}

Throw the error of the fallback method of the function function_name, which is provided by the package extension loaded together with packages (e.g., "Makie.jl and GeoJSON.jl"). This method is called if the extension is not loaded or if the arguments are not valid. Hence, the message must help the user in both cases: using_example is an example of packages that load the extension, and valid_call is the signature of the valid call.

Extended help

Throws

  • ErrorException: Always.
source
SatelliteAnalysis._frozen_orbit__zonal_unnormalization_factor — Method
_frozen_orbit__zonal_unnormalization_factor(::Val{:full}, l::Integer) -> Float64
_frozen_orbit__zonal_unnormalization_factor(::Val{:schmidt}, l::Integer) -> Float64
_frozen_orbit__zonal_unnormalization_factor(::Val{:unnormalized}, l::Integer) -> Float64

Return the factor that converts the zonal coefficient (order 0) of degree l to the unnormalized coefficient given the normalization used in the gravity model, which is returned by the function GravityModels.coefficient_norm.

The factor of the full normalization is √(2l + 1) for the zonal terms, whereas the Schmidt quasi-normalization does not modify them.

Extended help

Throws

  • ArgumentError: If the normalization is not supported.
source
SatelliteAnalysis._ground_facility_position_and_zenith — Method
_ground_facility_position_and_zenith(gf_lat::Number, gf_lon::Number, gf_h::Number) -> SVector{3, T}, SVector{3, T}

Compute the position [m] of the ground facility with latitude gf_lat [rad], longitude gf_lon [rad], and altitude gf_h [m] (WGS-84), and the unit vector [-] that points to its local vertical (zenith), which is normal to the WGS-84 ellipsoid. Both vectors are represented in the ECEF reference frame, and they are the inputs of the function _is_ground_facility_visible.

Returns

  • SVector{3, T}: Ground facility position represented in the ECEF reference frame [m].
  • SVector{3, T}: Unit vector that points to the local vertical of the ground facility represented in the ECEF reference frame [-].
source
SatelliteAnalysis._ground_repeating_orbit__adjacent_track_half_angle — Method
_ground_repeating_orbit__adjacent_track_half_angle(a::T1, e::T2, i::T3, orbit_cycle::Integer; kwargs...) where {T1 <: Number, T2 <: Number, T3 <: Number} -> T

Compute the angle [rad] between one ground track and the middle of the region between two adjacent ground tracks at the Equator, measured from the Earth's center, in a ground repeating orbit. The orbit is described by its semi-major axis a [m], eccentricity e [-], inclination i [rad], and orbit cycle orbit_cycle [day]. Notice that this angle is measured perpendicularly to the ground tracks.

The type T is obtained by promoting T1, T2, and T3 to a floating-point number.

Keywords

  • perturbation::Symbol: Symbol to select the perturbation terms that will be used. It can be :J0, :J2, or :J4.
  • m0::Number: Standard gravitational parameter for Earth [m³ / s²].
  • J2::Number: J₂ perturbation term.
  • J4::Number: J₄ perturbation term.
  • R0::Number: Earth's equatorial radius [m].
  • we::Number: Earth's angular speed [rad / s].
source
SatelliteAnalysis._ground_repeating_orbit__half_angle_to_track_angle — Method
_ground_repeating_orbit__half_angle_to_track_angle(β::Number, a::Number, R₀::Number) -> Number

Compute the angle [rad] between two adjacent ground tracks at the Equator measured from the satellite position given the angle β [rad] computed by _ground_repeating_orbit__adjacent_track_half_angle, the orbit semi-major axis a [m], and the Earth's equatorial radius R₀ [m].

source
SatelliteAnalysis._ground_repeating_orbit__half_angle_to_track_distance — Method
_ground_repeating_orbit__half_angle_to_track_distance(β::Number, R₀::Number) -> Number

Compute the distance [m] between two adjacent ground tracks on the Earth's surface at the Equator given the angle β [rad] computed by _ground_repeating_orbit__adjacent_track_half_angle and the Earth's equatorial radius R₀ [m].

source
SatelliteAnalysis._is_ground_facility_visible — Method
_is_ground_facility_visible(sat_r_e::AbstractVector, gf_r_e::AbstractVector, gf_up_e::AbstractVector, sin_θ::Number) -> Bool

Check if the satellite with position vector sat_r_e [m] is visible from the ground facility with position gf_r_e [m] and local vertical unit vector gf_up_e [-], where all vectors are represented in the ECEF reference frame. sin_θ is the sine of the minimum elevation angle [-].

This function does not perform any trigonometric operation. Hence, it is used in the algorithms that verify the visibility of the same ground facility many times.

source
SatelliteAnalysis._sun_sync_orbit__residues_and_jacobian — Method
_sun_sync_orbit__residues_and_jacobian(isqrt_ā::T, cos_i::T, Ω̇_d::T, ω_d::T, k₁::T, k₂::T, k₃::T, k₄::T, k₅::T, k₆::T) where {T <: Number} -> SVector{2, T}, SMatrix{2, 2, T, 4}

Compute the residues and the Jacobian used by the Newton-Raphson method in the function sun_sync_orbit_from_angular_velocity. The estimates are isqrt_ā, which is 1 / √(a / R₀) [-], and cos_i, which is the cosine of the inclination [-]. Ω̇_d is the desired RAAN time-derivative [° / day], ω_d is the desired angular velocity [° / min], and k₁ to k₆ are the auxiliary constants computed in that function.

Returns

  • SVector{2, T}: Residues f₁ [° / day], related to the RAAN time-derivative, and f₂ [° / min], related to the angular velocity.
  • SMatrix{2, 2, T, 4}: Jacobian of the residues with respect to isqrt_ā and cos_i.
source
SatelliteAnalysis._sun_sync_orbit_from_angular_velocity — Method
_sun_sync_orbit_from_angular_velocity(angvel::T1, e::T2; kwargs...) where {T1 <: Number, T2 <: Number} -> T, T, Bool, T, T

Solve the problem described in sun_sync_orbit_from_angular_velocity for the angular velocity angvel [rad / s] and the eccentricity e [-] without validating the inputs, throwing exceptions, or printing warnings. Hence, the caller must verify whether the algorithm converged and whether the solution has physical meaning, i.e., whether the absolute value of the returned inclination cosine is not larger than 1.

Note

The type T is obtained by promoting T1 and T2 to a floating-point number.

Keywords

  • max_iterations::Integer: Maximum number of iterations in the Newton-Raphson method.
  • tolerance::Union{Nothing, NTuple{2, Number}}: Residue tolerances to verify if the numerical method has converged. If it is nothing, (√eps(T), √eps(T)) will be used.
  • m0::Number: Standard gravitational parameter for Earth [m³ / s²].
  • J2::Number: J₂ perturbation term.
  • R0::Number: Earth's equatorial radius [m].

Returns

  • T: Semi-major axis [m].
  • T: Cosine of the inclination [-].
  • Bool: true if the Newton-Raphson algorithm converged, or false otherwise.
  • T: Residue related to the RAAN time-derivative [° / day].
  • T: Residue related to the angular velocity [° / min].
source
SatelliteAnalysis._time_unit_factor — Function
_time_unit_factor(time_unit::Symbol[, valid_units::Tuple]) -> Float64

Return the factor that converts a time in seconds to the unit time_unit. The supported units are :s for seconds, :min for minutes, :h for hours, :d for days, and :y for Julian years. The tuple valid_units contains the units the caller accepts, and, if it is omitted, only :s, :min, and :h are valid.

Note

The symbol :m is not a valid time unit because it selects meters in the distance units.

Extended help

Throws

  • ArgumentError: If time_unit is not in valid_units.
source
SatelliteAnalysis.beta_angle — Method
beta_angle(orb::KeplerianElements, Δjd::Number; kwargs...) -> T

Compute the beta angle [rad] for the orbit orb after Δjd days from its epoch. The output type T is obtained by promoting the types of the orbit elements and Δjd.

The algorithm was obtained from [1].

Note

It is expected that the input elements are represented in the TOD reference frame. If it is not the case, they can be converted using the function orb_eci_to_eci of SatelliteToolboxTransformations.jl.

Keywords

  • perturbation::Symbol: Select the perturbation terms that must be used when propagating the right ascension of the ascending node. The possible values are:
    • :J0: Consider a Keplerian orbit.
    • :J2: Consider the perturbation terms up to J₂.
    • :J4: Consider the perturbation terms J₂, J₂², and J₄.
    (Default: :J2)

References

  • [1]: Mortari, D., Wilkins, M. P., and Bruccoleri, C. On Sun-Synchronous Orbits and Associated Constellations

Extended Help

The beta angle is the angle between the orbit plane and the Sun. The positive direction is defined as that of the orbit angular momentum.

The beta angle is useful when computing the mean amount of solar radiation a satellite receives in a particular orbit.

Examples

julia> using SatelliteAnalysis, UnicodePlots

julia> jd₀ = date_to_jd(2021, 1, 1, 0, 0, 0)

julia> orb = KeplerianElements(
            jd₀,
            7130.982e3,
            0.001111,
            98.405 |> deg2rad,
            ltdn_to_raan(10.5, jd₀),
            90     |> deg2rad,
            0
        )

julia> β = beta_angle.(orb, 0:1:364)

julia> lineplot(0:1:364, rad2deg.(β), xlabel = "Day", ylabel = "Beta angle [°]")
                     ┌────────────────────────────────────────┐
                  30 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                     │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                     │⠀⣠⠞⠉⠙⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                     │⡴⠁⠀⠀⠀⠀⠹⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                     │⠀⠀⠀⠀⠀⠀⠀⠘⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡰⠃⠀⠀⠀│
                     │⠀⠀⠀⠀⠀⠀⠀⠀⠹⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡼⠁⠀⠀⠀⠀│
                     │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠹⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣀⠀⠀⠀⠀⠀⠀⣠⠞⠀⠀⠀⠀⠀⠀│
   Beta angle [°]    │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠱⡀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠖⠋⠀⠀⠀⠉⠓⠲⠤⠴⠚⠁⠀⠀⠀⠀⠀⠀⠀│
                     │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠹⣄⠀⠀⠀⠀⠀⣠⠞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                     │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠦⣄⣀⡠⠞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                     │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                     │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                     │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                     │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                  10 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
                     └────────────────────────────────────────┘
                     ⠀0⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀400⠀
                     ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀Day⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
source
SatelliteAnalysis.decay_analysis — Method
decay_analysis(orb::KeplerianElements; kwargs...) -> DataFrame
decay_analysis(sv::OrbitStateVector; kwargs...) -> DataFrame

Compute the orbital decay analysis of a satellite with initial mean elements orb represented in the TOD reference frame, propagating the mean orbital elements with averaged perturbations until the mean perigee altitude reaches terminate_altitude or the propagation time reaches tf.

By default, the input elements are treated as mean elements with respect to the averaged dynamics, following the same convention of semi-analytical tools such as STELA. Osculating elements, obtained, for example, from an instantaneous state vector, can be used by setting the keyword input_type to :osculating, in which case they are converted to mean elements before the propagation.

The initial state can also be specified by the orbit state vector sv represented in the TOD reference frame. Since a state vector is an instantaneous (osculating) state, the default value of the keyword input_type is :osculating in this case.

The model averages the following perturbations over one orbit: Earth gravity zonal harmonics (including a closed-form J₂² correction), third-body attraction of the Sun and the Moon, atmospheric drag, and solar radiation pressure gated by the Earth shadow.

Warning

This function only works after loading the package OrdinaryDiffEqAdamsBashforthMoulton.jl, which provides the default solver VCABM. Loading OrdinaryDiffEq.jl v6 also works because it depends on that package, but OrdinaryDiffEq.jl v7 or newer does not. In this case, the package OrdinaryDiffEqAdamsBashforthMoulton.jl must be loaded explicitly.

Note

The default integrator configuration (solver, reltol, abstol, and num_sampling_points_per_orbit) is tuned for fast and accurate decay lifetime estimation: the lifetime and the altitude evolution change well below the atmospheric model uncertainty. However, the angular elements (RAAN, argument of perigee, and mean anomaly) accumulate a larger numerical error over long arcs. If accurate angles are required, use a tighter configuration, e.g. solver = Tsit5(), reltol = 1e-8, abstol = 1e-8, and num_sampling_points_per_orbit = 33.

Keywords

  • satellite_mass::Number: Satellite mass [kg]. This keyword is required.
  • satellite_mean_area::Number: Mean cross-sectional area [m²] used for both the atmospheric drag and the solar radiation pressure. This keyword is required.
  • atmospheric_model::Any: Callable object (a function or a callable structure) that returns the atmospheric density [kg/m³] at a given location and time considering a set of space indices. It must have the signature (jd_utc::Number, lat::Number, lon::Number, alt::Number, space_indices::NamedTuple) -> Number where jd_utc is the Julian date in UTC, lat, lon, and alt are the geodetic latitude [rad], longitude [rad], and altitude [m] of the point where the density is evaluated, and space_indices is the named tuple with the space indices at that instant provided by the keyword space_indices. If it is nothing, the system uses an internal wrapper for the NRLMSISE-00 model provided by SatelliteToolboxAtmosphericModels.jl, which requires the fields f107 (daily 10.7 cm solar flux) [sfu], f107_avg (81-day average of the 10.7 cm solar flux) [sfu], and ap (daily geomagnetic index) [-] in the named tuple. The macros @decay_analysis__jacchia77, @decay_analysis__jacchia77_stela, and @decay_analysis__jr1971 provide keyword sets that select the Jacchia 1977 (report and STELA variants) and the Jacchia-Roberts 1971 models instead. (Default: nothing)
  • atmospheric_model_name::Union{Nothing, String}: Name of the atmospheric model recorded in the metadata Atmospheric Model of the output DataFrame and shown, for example, by plot_decay_analysis. If it is nothing, the name is derived from the keyword atmospheric_model: "NRLMSISE-00" for the default model and "Custom (<name>)" for user-provided callables. (Default: nothing)
  • gravity_model::Union{AbstractGravityModel, Nothing}: Gravity model used to compute the Earth gravitational perturbation. If it is nothing, the system fetches and loads the EGM96 model. (Default: nothing)
  • input_type::Symbol: How the input elements orb are interpreted. If it is :mean, they are treated as mean elements with respect to the averaged dynamics. If it is :osculating, they are treated as osculating elements and converted to mean elements before the propagation. Any other symbol raises an ArgumentError. (Default: :mean)
  • num_sampling_points_per_orbit::Union{Nothing, Int}: Number of sampling points used to average the perturbations over one orbit. The perturbations are concentrated near the perigee in eccentric orbits, requiring more points. If it is nothing, the number is selected using the mean eccentricity e at the beginning of the analysis: 17 if e < 0.05, 33 if e < 0.3, or 65 otherwise. (Default: nothing)
  • abstol::Number: Absolute tolerance of the numerical integration. (Default: 1e-6)
  • C_d::Number: Drag coefficient [-]. (Default: 2.2)
  • C_r::Number: Solar radiation pressure coefficient [-]. (Default: 1.25)
  • distance_unit::Symbol: Unit of the altitude columns in the output DataFrame. It can be :m for meters or :km for kilometers. (Default: :km)
  • space_indices::Any: Space indices required by the atmospheric model. It can be a constant NamedTuple used for all instants or a callable object of time (in Julian days) that returns the named tuple with the space indices at that instant: (jd_utc::Number) -> NamedTuple. If it is nothing, the system provides the named tuple (f107 = ..., f107_avg = ..., ap = ...) required by the default atmospheric model using the data in SpaceIndices.jl: the observed daily F10.7 of the previous day (space index F10obs), as prescribed by the NRLMSISE-00 documentation, the observed centered 81-day average F10.7 (space index F10obs_avg_center81), and the observed daily geomagnetic index (space index Ap_daily). Outside the observed timespans, the F10.7 values fall back to the predicted observed F10.7 (space index F10obs_predicted), which is a harmonic model fitted to the observed data that captures the mean solar cycle behavior, and the geomagnetic index falls back to Ap = 9, as in STELA. In this case, the required space index sets are initialized automatically, downloading the data files on first use. (Default: nothing)
  • reltol::Number: Relative tolerance of the numerical integration. (Default: 1e-6)
  • return_solution::Bool: If true, the raw solution of the numerical integration (see SciMLBase.ODESolution), whose state vector stores the mean alternate equinoctial elements [a, h, k, p, q, λ] in the same order as the fields of AlternateEquinoctialElements, is stored in the table-level metadata Solution of the output DataFrame. It can be obtained using metadata(df, "Solution"). Notice that the mean longitude λ is not wrapped to [0, 2π). (Default: false)
  • solver: Solver from the OrdinaryDiffEq.jl ecosystem used for the numerical integration. Notice that the user must load the package that provides the selected solver (for example, Tsit5 requires OrdinaryDiffEqTsit5.jl or OrdinaryDiffEq.jl). (Default: VCABM())
  • terminate_altitude::Number: Mean perigee altitude [m] that terminates the analysis. (Default: 120e3)
  • tf::Number: Maximum propagation time [s] after the orbit epoch. (Default: 30 * 365.25 * 86400, or 30 years)
  • time_unit::Symbol: Unit of the column time in the output DataFrame. It can be :s for seconds, :min for minutes, :h for hours, :d for days, or :y for Julian years (365.25 days). (Default: :y)
  • verbose::Bool: If true, a progress interface is shown in stderr during the numerical integration. In interactive terminals, a live panel shows a progress bar, the current mean perigee and apogee altitudes, the elapsed model time, and the elapsed wall time; at the end, the panel is left on the screen with the final state and a summary line is printed below it. Otherwise, plain progress lines are printed at every 5%, followed by the summary line. The progress fraction is the maximum between the time fraction and the perigee descent fraction, so it reaches 100% at either termination condition. Enabling the interface does not change the analysis result. (Default: false)

Returns

  • DataFrame: The mean orbital element evolution during the decay with the columns:
    • date: Date and time of each point [UTC] encoded using DateTime.
    • time: Elapsed time of each point since the beginning of the analysis [time_unit].
    • space_indices: Named tuple with the space indices used by the dynamics at each point. This column has no unit metadata since its fields have heterogeneous units. The default source provides the fields f107 [sfu], f107_avg [sfu], and ap [-].
    • mean_elements: Mean Keplerian elements encoded using KeplerianElements{MeanAnomaly} [SI], where the epoch is the point date [UTC]. Notice that the anomaly stored in the elements is the mean anomaly. The true anomaly can be obtained using the function true_anomaly.
    • apogee_altitude: Mean apogee altitude [distance_unit].
    • perigee_altitude: Mean perigee altitude [distance_unit].
    The unit of each column is stored in the DataFrame using metadata. The DataFrame also stores the following table-level metadata, which is used, for example, by the function plot_decay_analysis:
    • Atmospheric Model: Name of the atmospheric model used by the drag computation.
    • Description: Description of the table.
    • Drag Coefficient: Drag coefficient [-].
    • Satellite Mass: Satellite mass [kg].
    • Satellite Mean Area: Mean cross-sectional area [m²].
    • Space Indices Source: Description of the space indices source used by the dynamics.
    • SRP Coefficient: Solar radiation pressure coefficient [-].
    • Terminate Altitude: Mean perigee altitude that terminates the analysis [m].
    If the keyword return_solution is true, the DataFrame also stores the raw ODESolution in the metadata Solution, which is not propagated by DataFrame transformations.

Extended help

The satellite lifetime can be obtained from the last row of the returned DataFrame: if the perigee altitude reached terminate_altitude before tf, the last date is the decay epoch estimation.

Throws

  • ArgumentError: If input_type is not :mean or :osculating, if distance_unit is not :m or :km, or if time_unit is not :s, :min, :h, :d, or :y.
  • ArgumentError: If satellite_mass, num_sampling_points_per_orbit, abstol, reltol, or tf is not positive, or if satellite_mean_area, C_d, C_r, or terminate_altitude is negative.
  • ArgumentError: If the initial mean perigee altitude is not greater than terminate_altitude.

Examples

julia> using SatelliteAnalysis, OrdinaryDiffEqAdamsBashforthMoulton

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

julia> orb = KeplerianElements(
           jd₀,
           EARTH_EQUATORIAL_RADIUS + 300e3,
           0.001,
           98.0 |> deg2rad,
           ltdn_to_raan(10.5, jd₀),
           90 |> deg2rad,
           0
       );

julia> df = decay_analysis(
           orb;
           satellite_mass = 100.0,
           satellite_mean_area = 1.0,
           space_indices = (f107 = 140.0, f107_avg = 140.0, ap = 9.0)
       );

julia> df[end, :date]  # ..................................... Estimation of the decay epoch
2024-01-27T10:47:28.289

If the keyword space_indices is omitted, the analysis uses the observed and predicted indices provided by SpaceIndices.jl, requiring only the satellite properties:

julia> df = decay_analysis(orb; satellite_mass = 100.0, satellite_mean_area = 1.0);
source
SatelliteAnalysis.decay_analysis__jacchia77_kwargs — Method
decay_analysis__jacchia77_kwargs() -> NamedTuple

Return the named tuple with the keywords of decay_analysis that select the Jacchia 1977 atmospheric model: atmospheric_model, atmospheric_model_name, and space_indices. It is the function version of the macro @decay_analysis__jacchia77, which describes the model and the default space indices source. The function allows selecting the model programmatically:

kwargs = decay_analysis__jacchia77_kwargs()
decay_analysis(orb; satellite_mass = 100.0, satellite_mean_area = 1.0, kwargs...)

Keywords passed after the splatted named tuple override the ones it provides.

Warning

This function only works after loading the package OrdinaryDiffEqAdamsBashforthMoulton.jl, as described in decay_analysis.

source
SatelliteAnalysis.decay_analysis__jacchia77_stela_kwargs — Method
decay_analysis__jacchia77_stela_kwargs() -> NamedTuple

Return the named tuple with the keywords of decay_analysis that select the STELA variant of the Jacchia 1977 atmospheric model: atmospheric_model, atmospheric_model_name, and space_indices. It is the function version of the macro @decay_analysis__jacchia77_stela, which describes the model and the default space indices source. The function allows selecting the model programmatically:

kwargs = decay_analysis__jacchia77_stela_kwargs()
decay_analysis(orb; satellite_mass = 100.0, satellite_mean_area = 1.0, kwargs...)

Keywords passed after the splatted named tuple override the ones it provides.

Warning

This function only works after loading the package OrdinaryDiffEqAdamsBashforthMoulton.jl, as described in decay_analysis.

source
SatelliteAnalysis.decay_analysis__jr1971_kwargs — Method
decay_analysis__jr1971_kwargs() -> NamedTuple

Return the named tuple with the keywords of decay_analysis that select the Jacchia-Roberts 1971 atmospheric model: atmospheric_model, atmospheric_model_name, and space_indices. It is the function version of the macro @decay_analysis__jr1971, which describes the model and the default space indices source. The function allows selecting the model programmatically:

kwargs = decay_analysis__jr1971_kwargs()
decay_analysis(orb; satellite_mass = 100.0, satellite_mean_area = 1.0, kwargs...)

Keywords passed after the splatted named tuple override the ones it provides.

Warning

This function only works after loading the package OrdinaryDiffEqAdamsBashforthMoulton.jl, as described in decay_analysis.

source
SatelliteAnalysis.design_sun_sync_ground_repeating_orbit — Method
design_sun_sync_ground_repeating_orbit(minimum_repetition::Int, maximum_repetition::Int; kwargs...) -> DataFrame

List all Sun-synchronous, ground-repeating orbits whose repetition period is in the interval [minimum_repetition, maximum_repetition] days.

This function returns a DataFrame with the following columns:

  • semi_major_axis: Orbit semi-major axis.
  • altitude: Orbit altitude above the Equator (a - R0).
  • inclination: Orbit inclination.
  • period: Orbital period.
  • revs_per_day: If the keyword pretty_revs_per_day is false, this column contains Tuples with the integer and rational parts of the number of revolutions per day. Otherwise, it contains a string with a pretty representation of the number of revolutions per day.
  • adjacent_gt_distance: Distance between two adjacent ground tracks at Equator.
  • adjacent_gt_angle: Angle between two adjacent ground tracks at Equator measured from the satellite position.
Note

The units of those columns depend on the keywords. The unit of each column is stored in the DataFrame using the column metadata Unit.

Keywords

  • angle_unit::Symbol: Unit for all the angles in the output DataFrame. It can be :deg for degrees or :rad for radians. (Default: :deg)
  • distance_unit::Symbol: The unit for all the distances in the output DataFrame. It can be :m for meters or :km for kilometers. (Default: :km)
  • eccentricity::Number: Orbit eccentricity. (Default: 0)
  • maximum_revs_per_day::Number: Maximum number of revolutions per day of the orbits in the output DataFrame. (Default: 18)
  • minimum_revs_per_day::Number: Minimum number of revolutions per day of the orbits in the output DataFrame. (Default: 13)
  • pretty_revs_per_day::Bool: If true, the column with the revolutions per day will be converted to a string with a pretty representation of this information. (Default: true)
  • maximum_altitude::Union{Nothing, Number}: Maximum altitude [m] of the orbits in the output DataFrame. If it is nothing, the algorithm will not apply a higher limit to the orbital altitude. (Default: nothing)
  • minimum_altitude::Union{Nothing, Number}: Minimum altitude [m] of the orbits in the output DataFrame. If it is nothing, the algorithm will not apply a lower limit to the orbital altitude. (Default: nothing)
  • time_unit::Symbol: Unit for all the time values in the output DataFrame. It can be :s for seconds, :min for minutes, or :h for hours. (Default: :min)
  • m0::Number: Standard gravitational parameter for Earth [m³ / s²]. (Default: GM_EARTH)
  • J2::Number: J₂ perturbation term. (Default: EGM_2008_J2)
  • R0::Number: Earth's equatorial radius [m]. (Default: EARTH_EQUATORIAL_RADIUS)
  • we::Number: Earth's angular speed [rad / s]. (Default: EARTH_ANGULAR_SPEED)

Extended help

Throws

  • ArgumentError: If the repetition interval is not valid, if the interval [minimum_revs_per_day, maximum_revs_per_day] is not valid, if eccentricity is not in the interval [0, 1), or if angle_unit, distance_unit, or time_unit is not one of the supported symbols.
source
SatelliteAnalysis.eclipse_time_summary — Method
eclipse_time_summary(orbp::OrbitPropagator; kwargs...) -> DataFrame

Compute the eclipse time summary for the orbit propagator orbp. The summary is computed as the total time the object stays in the sunlight, penumbra, and umbra regions per orbit at each day.

Keywords

  • num_days::Integer: Number of days in which the analysis will be performed. (Default: 365)
  • step::Union{Nothing, Number}: The step [s] in which the propagation will occur. Notice that this function has a crossing estimation to accurately estimate the transition between the regions, including those entirely inside one step, such as a penumbra passage between the sunlight and the umbra. However, if this step is very large, we may miss a region if the lighting condition is the same in two consecutive instants. If it is nothing, it will be selected as the time in which the mean anomaly advances 0.5°. (Default: nothing)
  • time_unit::Symbol: Select the unit in which the results will be generated. The possible values are:
    • :s for seconds (Default);
    • :min for minutes; or
    • :h for hours.

Returns

  • DataFrame: The function returns a DataFrame with four columns:
    • date: Date of the analysis [UTC] encoded using Date.
    • sunlight: Total sunlight time per orbit at each day [time_unit].
    • penumbra: Total penumbra time per orbit at each day [time_unit].
    • umbra: Total umbra time per orbit at each day [time_unit].
    The unit of each column is stored in the DataFrame using metadata.

Extended Help

Throws

  • ArgumentError: If num_days is lower than 1, if step is not positive or not lower than the orbital period, or if time_unit is not :s, :min, or :h.

Examples

julia> using SatelliteAnalysis

julia> jd₀ = date_to_jd(2021, 1, 1, 0, 0, 0)

julia> orb = KeplerianElements(
           jd₀,
           7130.982e3,
           0.001111,
           98.405 |> deg2rad,
           ltdn_to_raan(10.5, jd₀),
           90     |> deg2rad,
           0
       )

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

julia> df = eclipse_time_summary(orbp; num_days = 5)
5×4 DataFrame
 Row │ date        sunlight  penumbra  umbra
     │ Date        Float64   Float64   Float64
─────┼─────────────────────────────────────────
   1 │ 2021-01-01   3972.63   20.4117  2006.96
   2 │ 2021-01-02   3973.85   20.4376  2005.71
   3 │ 2021-01-03   3974.77   20.4575  2004.77
   4 │ 2021-01-04   3975.74   20.4758  2003.79
   5 │ 2021-01-05   3976.94   20.5022  2002.55

julia> df = eclipse_time_summary(orbp; num_days = 5, time_unit = :min)
5×4 DataFrame
 Row │ date        sunlight  penumbra  umbra
     │ Date        Float64   Float64   Float64
─────┼─────────────────────────────────────────
   1 │ 2021-01-01   66.2105  0.340195  33.4493
   2 │ 2021-01-02   66.2308  0.340627  33.4285
   3 │ 2021-01-03   66.2461  0.340958  33.4129
   4 │ 2021-01-04   66.2623  0.341263  33.3964
   5 │ 2021-01-05   66.2824  0.341704  33.3759

julia> colmetadata(df)
Dict{Symbol, Dict{String, Symbol}} with 4 entries:
  :penumbra => Dict("Unit"=>:min)
  :sunlight => Dict("Unit"=>:min)
  :date     => Dict("Unit"=>:UTC)
  :umbra    => Dict("Unit"=>:min)
source
SatelliteAnalysis.fetch_country_polygons — Function
fetch_country_polygons(url = "https://pkgstore.datahub.io/core/geo-countries/countries/archive/23f420f929e0e09c39d916b8aaa166fb/countries.geojson"; kwargs...) -> String

Fetch the GeoJSON file with the country polygons in url. The algorithm stores the file in a scratch space. The function returns a String with the file path.

Note

If the file has already been downloaded, this function only returns its path. However, if the keyword force_download is true, the file is downloaded again from url.

Keywords

  • force_download::Bool: Download the file from url even if it already exists. (Default: false)
source
SatelliteAnalysis.find_crossing — Method
find_crossing(f::Function, t₀::Number, t₁::Number, s₀, s₁, vargs...; Δ = 1e-3, max = 100, kwargs...) -> T

Return the crossing time tc in which the function f(t) goes from the state s₀ to the state s₁. It is assumed that f(t₀) = s₀ and f(t₁) = s₁.

The parameters in vargs... are passed to the function f after t, and the keywords kwargs... are also passed to f. Hence, it will always be called as f(t, vargs...; kwargs...).

If the computed interval is smaller than Δ, or if the number of iterations reaches max, the algorithm stops.

Note

The output type T is obtained by the type of (t₀ + t₁) / 2.

Examples

julia> SatelliteAnalysis.find_crossing(
    t -> (sin(t) > 0),
    -0.3,
    0.3,
    false,
    true;
    Δ = 1e-10
)
6.984919309616089e-11
source
SatelliteAnalysis.frozen_orbit — Method
frozen_orbit(a::Number, i::Number; kwargs...) -> Float64, Float64

Compute the eccentricity [ ] and argument of perigee [rad] to obtain a frozen orbit when the orbit has semi-major axis a [m] and inclination i [rad]. This function uses the theory in [1].

Note

This function uses BigFloat internally to perform all computations, allowing very high degrees. However, the user must ensure that the default precision is enough for the required degree. Refer to the function setprecision for more information.

Keywords

  • gravity_model::Union{Nothing, AbstractGravityModel}: Gravity model used to compute the frozen eccentricity. Refer to the object AbstractGravityModel of the package SatelliteToolboxGravityModels.jl for more information. If it is nothing, the system will automatically fetch and load the EGM96 gravity model at the first call, keeping it in memory for the next ones. (Default: nothing)
  • max_degree::Int: Maximum gravity model degree used to compute the frozen eccentricity. If it is equal to or lower than 0, the maximum degree in gravity_model will be used. Otherwise, if it is lower than 3 or higher than the gravity_model maximum degree, it will be clamped accordingly. (Default: 53)

References

  • [1] Rosborough, G. W.; Ocampo, C. A (1991). Influence of higher degree zonals on the frozen orbit geometry. Proceedings of the AAS/AIAA Astrodynamics Conference, Durango, CO.

Extended Help

Due to the Earth's gravitational perturbation, the orbit of a satellite will experience secular changes in the argument of perigee. Hence, the satellite mean altitude per latitude will differ during the mission. This effect can be problematic, especially if we must compare images by a camera onboard the satellite in different periods. The altitude variation will change the resolution, leading to some problems when comparing the data.

We can avoid this problem if we compute an eccentricity and the argument of perigee that yields theoretically:

de      dω
── = 0, ── = 0
dt      dt

This orbit is called frozen. Refer to [1] for more information.

Throws

  • ArgumentError: If the inclination i is not within the interval (0, π) [rad] because the frozen orbit is not defined for equatorial orbits.

Examples

julia> using SatelliteAnalysis

julia> frozen_orbit(7130.982e3, 98.410 |> deg2rad)
(0.0011641853028456078, 1.5707963267948966)

julia> jgm3 = GravityModels.load(IcgemFile, fetch_icgem_file(:JGM3))
[ Info: Downloading the ICGEM file 'JGM3.gfc' from 'http://icgem.gfz-potsdam.de/getmodel/gfc/a3375e01a717ac162962138a5e94f10
466b71aa4a130d7f7d5b18ab3d5f90c3d/JGM3.gfc'...
IcgemFile{Float64}:
      Product type : gravity_field
       Model name  : JGM3
  Gravity constant : 3.986004415e14
            Radius : 6.3781363e6
    Maximum degree : 70
            Errors : formal
       Tide system : unknown
              Norm : fully_normalized
         Data type : Float64

julia> frozen_orbit(7130.982e3, 98.410 |> deg2rad; gravity_model = jgm3)
(0.001163484769069545, 1.5707963267948966)
source
SatelliteAnalysis.ground_facility_accesses — Method
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
SatelliteAnalysis.ground_facility_gaps — Method
ground_facility_gaps(orbp, args...; duration::Number = 86400, initial_time::Number = 0, kwargs...) -> DataFrame

Compute the gaps between the accesses of ground facilities. The arguments and keywords are the same as the ones used in the function ground_facility_accesses.

Notice that the gap analysis starts in the orbit propagator epoch plus initial_time and lasts for duration [s].

Returns

  • DataFrame: The function returns a DataFrame with three columns:
    • gap_beginning: Time of the gap beginning [UTC] encoded using DateTime.
    • gap_end: Time of the gap end [UTC] encoded using DateTime.
    • duration: Duration of the gap [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_gaps(orbp, (0, 0, 0))
3×3 DataFrame
 Row │ gap_beginning            gap_end                  duration 
     │ DateTime                 DateTime                 Float64  
─────┼────────────────────────────────────────────────────────────
   1 │ 2024-01-01T00:00:00      2024-01-01T10:20:03.136  37203.1
   2 │ 2024-01-01T10:30:02.971  2024-01-01T22:49:55.910  44392.9
   3 │ 2024-01-01T22:59:23.470  2024-01-02T00:00:00       3636.53

julia> ground_facility_gaps(orbp, (0, 0, 0); time_unit = :min)
3×3 DataFrame
 Row │ gap_beginning            gap_end                  duration 
     │ DateTime                 DateTime                 Float64  
─────┼────────────────────────────────────────────────────────────
   1 │ 2024-01-01T00:00:00      2024-01-01T10:20:03.136  620.052
   2 │ 2024-01-01T10:30:02.971  2024-01-01T22:49:55.910  739.882
   3 │ 2024-01-01T22:59:23.470  2024-01-02T00:00:00       60.6088
source
SatelliteAnalysis.ground_facility_visibility_circle — Method
ground_facility_visibility_circle(gf_wgs84::Tuple, satellite_position_norm::Number; kwargs...) -> Vector{NTuple{2, Float64}}

Compute the ground facility visibility circle from the position gf_wgs84 (WGS84) to a satellite in which its distance from the Earth's center is satellite_position_norm [m]. It returns a vector of NTuple{2, Float64} where the first element is the latitude [rad] and the second is the longitude [rad] of each point in the visibility circle.

The ground facility is specified using a tuple with its WGS84 position:

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

Keywords

  • add_nans::Bool: If true, we add NaN if there is a discontinuity in the visibility circle, which happens when it crosses the meridian ±180°, to improve plotting. (Default: true)
  • azimuth_step::Number: The step in the azimuth [rad] used to compute the visibility circle. (Default: 0.1 |> deg2rad)
  • minimum_elevation::Number: Minimum elevation angle for communication between the satellite and the ground facility [rad]. (Default: 10 |> deg2rad)

Extended Help

Throws

  • ArgumentError: If satellite_position_norm is not greater than the distance between the ground facility and the Earth's center.

Examples

julia> using SatelliteAnalysis, UnicodePlots

julia> gfv = ground_facility_visibility_circle((0, 0, 0), EARTH_EQUATORIAL_RADIUS + 700e3);

julia> lineplot(last.(gfv) .|> rad2deg, first.(gfv) .|> rad2deg; xlim = (-180, 180), ylim = (-90, 90))
       ┌────────────────────────────────────────┐ 
    90 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
       │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
       │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
       │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
       │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
       │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
       │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡼⠉⡏⢧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
       │⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⡧⠤⡧⢼⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤│ 
       │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢳⣀⣇⡞⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
       │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
       │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
       │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
       │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
       │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
   -90 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
       └────────────────────────────────────────┘ 
       ⠀-180⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀180⠀ 

julia> gfv = ground_facility_visibility_circle((-40 |> deg2rad, -60 |> deg2rad, 700), EARTH_EQUATORIAL_RADIUS + 700e3);

julia> lineplot(last.(gfv) .|> rad2deg, first.(gfv) .|> rad2deg; xlim = (-180, 180), ylim = (-90, 90))
       ┌────────────────────────────────────────┐ 
    90 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
       │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
       │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
       │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
       │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
       │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
       │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
       │⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⡧⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤│ 
       │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
       │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠖⠒⢦⡀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
       │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⠃⠀⠀⠀⢹⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
       │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⣄⠀⠀⠀⣸⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
       │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠒⠋⠁⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
       │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
   -90 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│ 
       └────────────────────────────────────────┘ 
       ⠀-180⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀180⠀ 
source
SatelliteAnalysis.ground_repeating_orbit_adjacent_track_angle — Method
ground_repeating_orbit_adjacent_track_angle(a::T1, e::T2, i::T3, orbit_cycle::Integer; kwargs...) where {T1 <: Number, T2 <: Number, T3 <: Number} -> T

Compute the adjacent track angle [rad] at Equator in a ground repeating orbit measured from the satellite position. The orbit is described by its semi-major axis a [m], eccentricity e [ ], inclination i [rad], and orbit cycle orbit_cycle [day].

Warning

The code does not check if the orbit is ground-repeating with orbit_cycle [day].

Note

Internally, this function uses the precision obtained by promoting T1, T2, and T3 to a floating-point number T.

Keywords

  • perturbation::Symbol: Symbol to select the perturbation terms that will be used. It can be :J0, :J2, or :J4. (Default: :J2)
  • m0::Number: Standard gravitational parameter for Earth [m³ / s²]. (Default: GM_EARTH)
  • J2::Number: J₂ perturbation term. (Default: EGM_2008_J2)
  • J4::Number: J₄ perturbation term. (Default: EGM_2008_J4)
  • R0::Number: Earth's equatorial radius [m]. (Default: EARTH_EQUATORIAL_RADIUS)
  • we::Number: Earth's angular speed [rad / s]. (Default: EARTH_ANGULAR_SPEED)

Extended help

A ground repeating orbit is any orbit that the number of revolutions per day is a rational number. Hence, this type of orbit repeats its ground trace after a finite number of days.

The information orbit_cycle is redundant given that we have a, e, and i. However, it is necessary to improve the algorithm precision. Otherwise, the orbit_cycle must be obtained by computing the orbit period using a, e, and i and then converting it to a rational number, leading to numerical problems.

Throws

  • ArgumentError: If orbit_cycle is not positive.
source
SatelliteAnalysis.ground_repeating_orbit_adjacent_track_distance — Method
ground_repeating_orbit_adjacent_track_distance(a::T1, e::T2, i::T3, orbit_cycle::Integer; kwargs...) where {T1 <: Number, T2 <: Number, T3 <: Number} -> T

Compute the adjacent track distance [m] at Equator in a ground repeating orbit. The orbit is described by its semi-major axis a [m], eccentricity e [ ], inclination i [rad], and orbit cycle orbit_cycle [day].

Warning

The code does not check if the orbit is ground-repeating with orbit_cycle [day].

Note

Internally, this function uses the precision obtained by promoting T1, T2, and T3 to a floating-point number T.

Keywords

  • perturbation::Symbol: Symbol to select the perturbation terms that will be used. It can be :J0, :J2, or :J4. (Default: :J2)
  • m0::Number: Standard gravitational parameter for Earth [m³ / s²]. (Default: GM_EARTH)
  • J2::Number: J₂ perturbation term. (Default: EGM_2008_J2)
  • J4::Number: J₄ perturbation term. (Default: EGM_2008_J4)
  • R0::Number: Earth's equatorial radius [m]. (Default: EARTH_EQUATORIAL_RADIUS)
  • we::Number: Earth's angular speed [rad / s]. (Default: EARTH_ANGULAR_SPEED)

Extended help

A ground repeating orbit is any orbit that the number of revolutions per day is a rational number. Hence, this type of orbit repeats its ground trace after a finite number of days.

The information orbit_cycle is redundant given that we have a, e, and i. However, it is necessary to improve the algorithm precision. Otherwise, the orbit_cycle must be obtained by computing the orbit period using a, e, and i and then converting it to a rational number, leading to numerical problems.

Throws

  • ArgumentError: If orbit_cycle is not positive.
source
SatelliteAnalysis.ground_track — Method
ground_track(orbp::OrbitPropagator; kwargs...) -> Vector{NTuple{2, T}}

Compute the satellite ground track using the orbit propagator orbp. It returns a vector of NTuple{2, T} where T is the promoted floating-point type of the time inputs, the first element is the latitude [rad], and the second is the longitude [rad] of each point in the ground track.

Keywords

  • add_nans::Bool: If true, we add NaN if there is a discontinuity in the ground track to improve plotting. (Default: true)

  • duration::Number: Duration of the analysis [s]. The ground track always ends at the instant initial_time + duration, even if duration is not a multiple of step. (Default: 86400)

  • initial_time::Number: Initial time regarding the orbit propagator orbp epoch [s]. (Default: 0)

  • 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)

  • step::Union{Nothing, Number}: Step for the computation. If nothing, we will roughly compute the step to approximate 1° in the mean anomaly. (Default: nothing)

  • track_types::Symbol: A symbol describing what kind of track types we must add to the output vector. It can be :ascending for only ascending passages, :descending for only descending passages, or :all for both. (Default: :all)

Extended Help

Throws

  • ArgumentError: If step is not positive, if duration is negative, or if track_types is not :all, :ascending, or :descending.

Examples

julia> using SatelliteAnalysis, UnicodePlots

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> gt = ground_track(orbp);

julia> lineplot(last.(gt), first.(gt))
      ┌────────────────────────────────────────┐
    2 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
      │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
      │⠀⠀⠀⠀⣸⡿⠿⣻⠿⣿⠿⣟⡯⢟⡿⢿⣿⡿⣿⡟⣿⡿⢿⣿⢿⣿⢻⣿⠿⣿⡟⣿⡿⣿⡿⢿⠀⠀⠀⠀│
      │⠀⠀⠀⠀⠞⠹⡼⠙⣶⠋⢶⠋⢣⠏⢳⡞⠀⣿⡁⡽⡇⣹⡇⢨⢏⢈⢯⠀⣿⡀⡽⡁⣹⡇⢸⣯⠀⠀⠀⠀│
      │⠀⠀⠀⠀⢦⢰⢳⢠⢿⡀⡟⡄⡞⡇⡸⣇⢸⠁⢷⠃⣷⡇⢸⡏⠸⡼⠈⣾⠀⣷⠃⢣⠇⢹⣏⠏⠀⠀⠀⠀│
      │⠀⠀⠀⠀⢸⡞⠘⣾⠀⣿⠁⢧⠃⢹⡇⢸⡏⠀⣼⠀⣿⡆⢰⡇⢀⣇⠀⣷⠀⣾⠀⣸⡀⢸⣿⠀⠀⠀⠀⠀│
      │⠀⠀⠀⠀⢀⡇⠀⣇⠀⣿⠀⢸⠀⢸⡁⢨⡇⠀⡇⡇⡏⡇⣸⢳⢸⢸⢰⢻⣀⡏⡆⡇⡇⡜⣯⠀⠀⠀⠀⠀│
      │⠤⠤⠤⠤⢼⢧⢤⢿⠤⣿⠤⡿⡦⡼⡧⢼⣧⢴⠥⢧⡧⢼⡧⢼⡾⠼⣼⠤⣿⠤⣧⠧⢷⣧⢿⠤⠤⠤⠤⠤│
      │⠀⠀⠀⠀⡼⢸⢸⠸⣼⠁⣇⠇⡇⡇⢳⡞⢸⢸⠀⢸⡇⢸⡇⠈⡇⠀⡏⠀⣿⠀⢸⠀⢸⢹⠘⡆⠀⠀⠀⠀│
      │⠀⠀⠀⠀⠁⠈⡏⠀⡿⠀⢿⠀⢹⠃⢸⡇⠘⡇⠀⡜⡇⣸⡇⢸⢧⢠⢿⠀⣿⠀⡾⡄⡸⡟⠀⣷⠀⠀⠀⠀│
      │⠀⠀⠀⠀⢆⢰⢳⢀⢿⠀⡿⡄⡼⡆⣸⣇⢰⢧⢠⠇⣧⡇⢹⡞⠸⡼⠘⣾⠁⣷⠃⢧⢧⢷⢀⡟⠀⠀⠀⠀│
      │⠀⠀⠀⠀⢘⣎⢈⣞⠀⣿⡁⣳⡃⣹⡇⢸⣏⢘⣞⢀⡿⢆⡼⢧⣰⢳⣠⠿⣀⠾⣄⡞⣆⢈⣿⠀⠀⠀⠀⠀│
      │⠀⠀⠀⠀⢹⣾⣿⣾⣿⣶⣿⣧⣿⣷⣿⣷⣾⣿⣼⣿⣷⣾⣷⣾⣵⣲⣽⣶⣿⣶⣯⣶⣼⣿⣾⣿⠀⠀⠀⠀│
      │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
   -2 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
      └────────────────────────────────────────┘
      ⠀-4⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀4⠀

julia> gt = ground_track(orbp, track_types = :ascending);

julia> lineplot(last.(gt), first.(gt))
      ┌────────────────────────────────────────┐
    2 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
      │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
      │⠀⠀⠀⠀⢸⡛⠽⡛⠿⣟⠫⣟⠫⢍⠛⠻⢿⡻⢽⡛⡿⡛⠿⣟⠯⣟⠫⢟⠻⢿⡛⢽⡛⠽⡛⠯⠀⠀⠀⠀│
      │⠀⠀⠀⠀⠀⠹⡄⠘⡆⠈⢆⠈⢣⠀⢳⡀⠀⢳⡀⠹⡇⠙⡆⠈⢆⠈⢧⠀⢳⡀⠱⡀⠙⡄⠘⣆⠀⠀⠀⠀│
      │⠀⠀⠀⠀⢦⠀⢱⠀⢸⡀⠘⡄⠈⡇⠀⣇⠀⠀⢧⠀⣷⠀⢸⠀⠸⡄⠈⡆⠀⣇⠀⢣⠀⢹⠀⠈⠀⠀⠀⠀│
      │⠀⠀⠀⠀⢸⡀⠘⡆⠀⡇⠀⢇⠀⢹⠀⢸⠀⠀⢸⠀⡟⡆⠀⡇⠀⣇⠀⢳⠀⢸⠀⠸⡀⠈⡇⠀⠀⠀⠀⠀│
      │⠀⠀⠀⠀⠀⡇⠀⣇⠀⢳⠀⢸⠀⠸⡀⠈⡇⠀⠀⡇⡇⡇⠀⢳⠀⢸⠀⢸⡀⠈⡆⠀⡇⠀⢧⠀⠀⠀⠀⠀│
      │⠤⠤⠤⠤⠤⢧⠤⢼⠤⢼⠤⠼⡦⠤⡧⠤⣧⠤⠤⢧⡧⢼⠤⢼⠤⠼⡤⠤⡧⠤⡧⠤⢷⠤⢼⠤⠤⠤⠤⠤│
      │⠀⠀⠀⠀⠀⢸⠀⠸⡄⠀⡇⠀⡇⠀⢳⠀⢸⠀⠀⢸⡇⠸⡄⠈⡇⠀⡇⠀⢧⠀⢸⠀⢸⠀⠘⡆⠀⠀⠀⠀│
      │⠀⠀⠀⠀⠀⠈⡇⠀⡇⠀⢧⠀⢹⠀⢸⡀⠘⡆⠀⠘⡇⠀⡇⠀⢧⠀⢹⠀⢸⠀⠸⡄⠈⡇⠀⣇⠀⠀⠀⠀│
      │⠀⠀⠀⠀⢆⠀⢳⠀⢸⠀⠸⡄⠘⡆⠀⣇⠀⢧⠀⠀⣧⠀⢹⠀⠸⡀⠘⡆⠀⣇⠀⢧⠀⢳⠀⠘⠀⠀⠀⠀│
      │⠀⠀⠀⠀⠘⣆⠈⢆⠀⢧⡀⢳⡀⠹⡄⠘⣄⠘⣆⠀⡏⢆⠀⢧⠀⢳⡀⠹⡀⠸⣄⠘⣆⠈⢧⠀⠀⠀⠀⠀│
      │⠀⠀⠀⠀⠐⣬⣗⣮⣷⣦⣵⣢⣽⣲⣽⣶⣬⣗⣬⣗⣧⣬⣓⣦⣵⣢⣽⣲⣽⣶⣬⣖⣬⣗⣮⡵⠀⠀⠀⠀│
      │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
   -2 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
      └────────────────────────────────────────┘
      ⠀-4⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀4⠀

julia> gt = ground_track(orbp, track_types = :descending);

julia> lineplot(last.(gt), first.(gt))
      ┌────────────────────────────────────────┐
    2 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
      │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
      │⠀⠀⠀⠀⣸⡽⠟⣻⠽⣻⠿⢛⡯⢛⡯⢟⡻⠝⣻⠝⣿⠽⢛⠯⢛⡯⢛⡿⠟⡻⠝⣻⠽⣻⠿⢓⠀⠀⠀⠀│
      │⠀⠀⠀⠀⠞⠀⡼⠁⣰⠃⢰⠋⢠⠏⢀⡞⠀⡜⠁⡼⡇⣰⠃⢠⠏⢀⠎⠀⡞⠀⡼⠁⣰⠃⢰⣫⠀⠀⠀⠀│
      │⠀⠀⠀⠀⠀⢰⠃⢠⠇⠀⡏⠀⡞⠀⡸⠀⢸⠁⢰⠃⣇⡇⠀⡏⠀⡼⠀⣸⠀⢰⠃⢠⠇⠀⣏⠇⠀⠀⠀⠀│
      │⠀⠀⠀⠀⠀⡞⠀⣸⠀⢸⠁⢠⠃⠀⡇⠀⡏⠀⡼⠀⣿⠀⢰⠁⢀⡇⠀⡇⠀⡞⠀⣸⠀⢸⢸⠀⠀⠀⠀⠀│
      │⠀⠀⠀⠀⢀⡇⠀⡇⠀⡜⠀⢸⠀⢸⠁⢠⠇⠀⡇⠀⡏⠀⣸⠀⢸⠀⢰⠃⢀⡇⠀⡇⠀⡜⡏⠀⠀⠀⠀⠀│
      │⠤⠤⠤⠤⢼⠤⢤⠧⠤⡧⠤⡯⠤⡼⠤⢼⠤⢴⠥⢤⡧⠤⡧⠤⡾⠤⢼⠤⢼⠤⢤⠧⠤⣧⠧⠤⠤⠤⠤⠤│
      │⠀⠀⠀⠀⡼⠀⢸⠀⢸⠁⢀⠇⠀⡇⠀⡞⠀⢸⠀⢸⡇⢠⠃⠀⡇⠀⡏⠀⡼⠀⢸⠀⢸⢹⠀⠀⠀⠀⠀⠀│
      │⠀⠀⠀⠀⠁⠀⡎⠀⡸⠀⢸⠀⢰⠃⢀⡇⠀⡇⠀⡜⡇⣸⠀⢸⠁⢠⠇⠀⡇⠀⡎⠀⡸⡞⠀⣰⠀⠀⠀⠀│
      │⠀⠀⠀⠀⠀⢰⠃⢀⠇⠀⡏⠀⡼⠀⣸⠀⢰⠁⢠⠇⣇⡇⠀⡞⠀⡼⠀⢸⠁⢰⠃⢀⢧⠇⢀⡇⠀⠀⠀⠀│
      │⠀⠀⠀⠀⢀⠎⢀⡞⠀⡼⠁⡰⠃⣠⠃⢠⠏⢀⡞⢀⡿⠀⡼⠁⣰⠃⢠⠇⢀⠎⢀⡞⠀⢀⡜⠀⠀⠀⠀⠀│
      │⠀⠀⠀⠀⢩⣖⣯⣔⣮⣴⣾⣥⣺⣥⣲⣥⣖⣯⣔⣯⣷⣾⣵⣺⣥⣲⣥⣶⣯⣖⣋⣤⣔⣯⣔⣎⠀⠀⠀⠀│
      │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
   -2 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
      └────────────────────────────────────────┘
      ⠀-4⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀4⠀
source
SatelliteAnalysis.ground_track_inclination — Method
ground_track_inclination(a::Number, e::Number, i::Number; kwargs...) -> T
ground_track_inclination(orb::Orbit{Tepoch, T}; kwargs...) where {Tepoch <: Number, T <: Number} -> T

Compute the ground track inclination at the Equator [rad] in an orbit with semi-major axis a [m], eccentricity e [ ], and inclination i [rad]. The orbit can also be specified by orb (see Orbit).

Note

The output type T in the first signature is obtained by promoting the inputs to a float type.

Warning

The algorithm here assumes a small orbit eccentricity.

Keywords

  • perturbation::Symbol: Symbol to select the perturbation terms that will be used. It can be :J0, :J2, or :J4. (Default: :J2)
  • m0::Number: Standard gravitational parameter for Earth [m³ / s²]. (Default: GM_EARTH)
  • J2::Number: J₂ perturbation term. (Default: EGM_2008_J2)
  • J4::Number: J₄ perturbation term. (Default: EGM_2008_J4)
  • R0::Number: Earth's equatorial radius [m]. (Default: EARTH_EQUATORIAL_RADIUS)
  • we::Number: Earth's angular speed [rad / s]. (Default: EARTH_ANGULAR_SPEED)

Extended Help

We define the ground track inclination as the angle that the ground track has with respect to the Equator. This information is important to compute, for example, the required swath for a remote sensing satellite to cover the entire Earth.

The ground track inclination i_gt is given by:

            ┌                       ┐
            │      ω_s ⋅ sin i      │
i_gt = atan │ ───────────────────── │
            │ ω_s ⋅ cos i - ω_e + Ω̇ │
            └                       ┘

where ω_s = n + ω̇ is the satellite angular velocity, n is the perturbed mean motion, i is the orbit inclination, ω is the orbit argument of perigee, Ω is the orbit right ascension of the ascending node, and ω_e is the Earth's angular rate.

Formally, we should use the satellite instantaneous angular speed at the Equator instead of the mean angular speed ω_s. However, given the perturbations caused by the Earth's gravitational potential, the former is not simple to compute. This calculation would required to implement an orbit propagator here. Thus, we simplify it by assuming that the orbit eccentricity is small. This assumption is reasonable given the missions that would benefit from the computation of the ground track inclination. In this case, the orbit angular speed is almost constant and equal to ω_s.

Examples

julia> using SatelliteAnalysis

julia> ground_track_inclination(7130.982e3, 0.00111, 98.410 |> deg2rad) |> rad2deg
102.30052101661899

julia> jd₀ = date_to_jd(2021, 1, 1)
2.4592155e6

julia> orb = KeplerianElements(
           jd₀,
           7130.982e3,
           0.001111,
           98.410 |> deg2rad,
           ltdn_to_raan(10.5, jd₀),
           π / 2,
           0
       )
KeplerianElements{TrueAnomaly, Float64, Float64}:
  Epoch             : 2.45922e6 (2021-01-01T00:00:00)
  Semi-Major Axis   : 7130.982 km
  Eccentricity      : 0.001111
  Inclination       : 98.41°
  RA of Asc. Node   : 78.40205742°
  Arg. of Periapsis : 90.0°
  True Anomaly      : 0.0°

julia> ground_track_inclination(orb) |> rad2deg
102.30052101658998
source
SatelliteAnalysis.is_ground_facility_visible — Method
is_ground_facility_visible(sat_r_e::AbstractVector, gf_lat::Number, gf_lon::Number, gf_h::Number, θ::Number) -> Bool
is_ground_facility_visible(sat_r_e::AbstractVector, gf_r_e::AbstractVector, gf_up_e::AbstractVector, θ::Number) -> Bool
is_ground_facility_visible(sat_r_e::AbstractVector, gf_r_e::AbstractVector, θ::Number) -> Bool
is_ground_facility_visible(sat_r_ned::AbstractVector, θ::Number) -> Bool

Check if the satellite with position vector sat_r_e (ECEF) is inside the visibility circle of a ground facility with latitude gf_lat [rad], longitude gf_lon [rad], altitude gf_h [m] (WGS-84) or ECEF position gf_r_e [m]. The algorithm considers that the ground station has visibility to the satellite if its elevation angle is larger than θ [rad].

The user can also pass the satellite position represented in the NED (North-East-Down) reference frame sat_r_ned [m] at the ground station location, which increases the performance since the algorithm performs no reference frame conversion.

If the visibility of the same ground facility must be verified for many satellite positions, the fastest method receives the ground facility ECEF position gf_r_e [m] together with the unit vector gf_up_e [-] that points to the local vertical (zenith) of the ground facility represented in the ECEF reference frame. Both can be computed only once:

gf_r_e  = geodetic_to_ecef(gf_lat, gf_lon, gf_h)
gf_up_e = [cos(gf_lat) * cos(gf_lon), cos(gf_lat) * sin(gf_lon), sin(gf_lat)]

In this case, the algorithm performs neither reference frame conversions nor trigonometric operations related to the ground facility position.

Returns

  • Bool: true if the satellite is inside the visibility circle, or false otherwise.
source
SatelliteAnalysis.lighting_condition — Method
lighting_condition(r_i::AbstractVector, s_i::AbstractVector) -> Symbol

Compute the lighting condition at the position r_i [m] considering the Sun position vector s_i [m]. The possible return values are:

  • :sunlight: The point is under direct sunlight.
  • :penumbra: The point is in penumbra region.
  • :umbra: The point is in umbra region.

The algorithm used in this function was based on [1].

Note

The vectors r_i and s_i must be represented in the same reference frame.

References

  • [1] Longo, C. R. O., Rickman, S. L (1995). Method for the Calculation of Spacecraft Umbra and Penumbra Shadow Terminator Points. NASA Technical Paper 3547.
source
SatelliteAnalysis.makie_palette — Method
SatelliteAnalysis.makie_palette(n::Int; kwargs...) -> Vector{Colorant}

Return the first n colors of the 6-color categorical palette used by the SatelliteAnalysis.jl Makie theme.

Note

This function is defined in a package extension. Hence, Makie.jl must be loaded (e.g., using CairoMakie) before calling it, otherwise it throws an ErrorException.

This function is not exported. Access it as SatelliteAnalysis.makie_palette.

See also: makie_theme

Keywords

  • variant::Symbol: Variant of the palette, as in the function makie_theme. If it is :dark, return the palette designed for dark backgrounds. If it is :light, return the palette designed for light backgrounds, matching the default theme. (Default: :light)

Extended help

Throws

  • ArgumentError: If n is negative or greater than the number of colors in the palette, or if variant is not :dark or :light.
  • ErrorException: If Makie.jl is not loaded.
source
SatelliteAnalysis.makie_theme — Method
SatelliteAnalysis.makie_theme(; kwargs...) -> Makie.Theme
SatelliteAnalysis.makie_theme(variant::Symbol; kwargs...) -> Makie.Theme
SatelliteAnalysis.makie_theme(variant::Val; kwargs...) -> Makie.Theme

Return the SatelliteAnalysis.jl Makie theme, ready to be applied with set_theme! or with_theme.

variant selects the color scheme: :dark (or Val(:dark)) for dark backgrounds, and :light (or Val(:light)) for light backgrounds. If variant is omitted, the light theme is returned.

Note

This function is defined in a package extension. Hence, Makie.jl must be loaded (e.g., using CairoMakie) before calling it, otherwise it throws an ErrorException.

This function is not exported. Access it as SatelliteAnalysis.makie_theme.

See also: makie_palette

Keywords

  • fontscale::Real: Factor to uniformly scale every font size (tick labels, axis labels, titles, legends, etc.). For example, fontscale = 1.25 makes all text 25% larger, which is useful when a figure is shrunk into a small slide area. (Default: 1)
  • mono_ticklabels::Bool: If true, render the axis and colorbar tick labels using the monospaced font IBM Plex Mono. The fixed-width digits keep numeric ticks vertically aligned, which is useful for plots dominated by numbers. (Default: false)

Extended help

The recommended figure size for 16:9 slides is:

Figure(size = (1280, 720))

The recommended export resolution is:

save("plot.png", fig; px_per_unit = 2)  # 2560 × 1440 px

Throws

  • ArgumentError: If the theme variant is not :dark or :light.
  • ErrorException: If Makie.jl is not loaded.
source
SatelliteAnalysis.plot_decay_analysis — Method
plot_decay_analysis(df::DataFrame; kwargs...) -> Figure, Axis

Plot the decay analysis in df, computed using the function decay_analysis. It returns the objects Figure and Axis used to plot the data. For more information, please refer to Makie.jl documentation.

The figure shows the evolution of the mean apogee and perigee altitudes and an information panel with the satellite mass, the satellite mean area, the estimated time to reenter, and a card with the analysis assumptions (atmospheric model and drag and SRP coefficients). A dashed line marks the terminate altitude used to declare the reentry, and the reentry is annotated next to the reentry marker. By default, the figure shows only relative times; the keyword show_dates adds the absolute dates [UTC] to the subtitle, the information panel, and the reentry annotation. The legend is placed outside the plot, at the bottom of the column that contains the information panel, inside a card that matches the information panel style. The time to reenter is only shown if the analysis detected a reentry, i.e., if the mean perigee altitude reached the terminate altitude. The satellite mass [kg], the satellite mean area [m²], and the terminate altitude [m] are obtained from the DataFrame metadata written by decay_analysis (Satellite Mass, Satellite Mean Area, and Terminate Altitude), but they can be overridden using keywords. The assumptions are resolved from the metadata Atmospheric Model, Drag Coefficient, and SRP Coefficient. Information whose value cannot be resolved, because the metadata is absent and the related keyword was not passed, is omitted from the panel.

Warning

This function only works after loading the package Makie.jl. Furthermore, the user must also load one Makie.jl backend (CairoMakie.jl or GLMakie.jl, for example) to see the result.

Keywords

  • f107_avg_getter::Any: Callable object that extracts the 81-day average of the 10.7 cm solar flux [sfu] from an element of the column space_indices of df, used when the keyword show_f107 is true. If it is nothing, the 81-day average curve is omitted from the plot. (Default: si -> si.f107_avg)
  • f107_getter::Any: Callable object that extracts the daily 10.7 cm solar flux [sfu] from an element of the column space_indices of df, used when the keyword show_f107 is true. If it is nothing, the daily curve is omitted from the plot. (Default: si -> si.f107)
  • fontscale::Real: Factor to uniformly scale every font size of the figure, useful when rendering at a size other than the default. If theme is a Makie.Theme or nothing, it only scales the font sizes selected by this function, such as the ones in the information panel and in the legend. (Default: 1)
  • mission_name::Union{Nothing, AbstractString}: Mission name rendered in uppercase above the plot title. If it is nothing, no mission name is added to the figure. (Default: nothing)
  • mono_ticklabels::Bool: If true, the tick labels are rendered using a monospaced font. This keyword only has effect if theme is a Symbol. (Default: false)
  • panel_width::Union{Nothing, Real}: Width [px] of the column with the information panel and the legend. If it is nothing, the width scales with the figure width. (Default: nothing)
  • satellite_mass::Union{Nothing, Number}: Satellite mass [kg] shown in the information panel. If it is nothing, the value is obtained from the metadata Satellite Mass of df. (Default: nothing)
  • satellite_mean_area::Union{Nothing, Number}: Satellite mean area [m²] shown in the information panel. If it is nothing, the value is obtained from the metadata Satellite Mean Area of df. (Default: nothing)
  • show_assumptions::Bool: If true, the information panel shows a card with the analysis assumptions resolved from the DataFrame metadata written by decay_analysis. (Default: true)
  • show_dates::Bool: If true, the absolute dates [UTC] are shown in the figure: the automatic subtitle shows the analysis timespan, the information panel shows the estimated reentry date below the time to reenter, and the reentry annotation shows the estimated reentry date. Otherwise, the analysis is treated as relative and no dates are shown. (Default: false)
  • show_f107::Bool: If true, the daily and the 81-day average 10.7 cm solar flux indices, extracted from the column space_indices of df using the keywords f107_getter and f107_avg_getter, are plotted [sfu] using a twin y-axis placed at the right side of the figure. The lines are rendered with transparency below the other plot elements, and the twin y-axis ticks use canonical values aligned with the grid of the main axis. (Default: false)
  • show_reentry_callout::Bool: If true and the analysis detected a reentry, an annotation is added in the plot next to the reentry marker. It shows the estimated reentry date [UTC] when show_dates is true and the text "Reentry" otherwise. (Default: true)
  • subtitle::Union{Nothing, AbstractString, Symbol}: Subtitle rendered below the plot title. If it is :auto, the subtitle shows the analysis timespan [UTC] when show_dates is true; otherwise, no subtitle is added. If it is nothing, no subtitle is added to the figure. Any other Symbol raises an ArgumentError. (Default: :auto)
  • terminate_altitude::Union{Nothing, Number}: Mean perigee altitude [m] that terminates the decay analysis, used to detect if a reentry happened. If it is nothing, the value is obtained from the metadata Terminate Altitude of df. (Default: nothing)
  • theme::Union{Nothing, Symbol, Makie.Theme}: Theme used to style the figure, which is applied locally. If it is a Symbol, it selects the variant of the theme created by the function SatelliteAnalysis.makie_theme, which can be :light or :dark. If it is a Makie.Theme, this theme is applied. If it is nothing, no theme is applied, and the figure uses the current Makie theme. In the last two cases, the elements that are not styled by the theme use the colors of the variant :light. (Default: :light)
  • title::AbstractString: Title of the plot. (Default: "Orbital Decay Analysis")
  • xlims::Union{Nothing, Tuple}: Limits of the x-axis of the main plot. If it is nothing, the limits are computed automatically. (Default: nothing)
  • ylims::Union{Nothing, Tuple}: Limits of the y-axis of the main plot. If it is nothing, the limits are computed automatically. (Default: nothing)
  • size::Tuple: Size of the figure. (Default: (1344, 756))

All other kwargs... are passed to the function Figure.

To export the figure in high resolution for reports, use save("plot.png", fig; px_per_unit = 2).

Extended help

Throws

  • ArgumentError: If df is empty.
  • ArgumentError: If df does not have the columns time, date, apogee_altitude, and perigee_altitude, or if the keyword show_f107 is true and df does not have the column space_indices.
  • ArgumentError: If the keyword show_f107 is true and both f107_getter and f107_avg_getter are nothing, or if the getters cannot extract the values from the column space_indices.
  • ArgumentError: If the theme variant in theme is not :dark or :light.
  • ArgumentError: If the keyword subtitle is a Symbol other than :auto.

Examples

julia> using SatelliteAnalysis, OrdinaryDiffEqAdamsBashforthMoulton, CairoMakie

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

julia> orb = KeplerianElements(
           jd₀,
           EARTH_EQUATORIAL_RADIUS + 300e3,
           0.001,
           98.0 |> deg2rad,
           ltdn_to_raan(10.5, jd₀),
           90 |> deg2rad,
           0
       );

julia> df = decay_analysis(
           orb;
           satellite_mass = 100.0,
           satellite_mean_area = 1.0,
           space_indices = (f107 = 140.0, f107_avg = 140.0, ap = 9.0)
       );

julia> fig, ax = plot_decay_analysis(df);

julia> fig
source
SatelliteAnalysis.plot_ground_facility_visibility_circles! — Method
plot_ground_facility_visibility_circles!(ax::Axis, vgf_vc::Vector{Vector{NTuple{2, T}}}; kwargs...) where {T <: Number} -> Vector{Lines}

Plot in the Makie.jl axis ax the ground facility visibility circles in the vector vgf_vc, where each element is computed using the function ground_facility_visibility_circle. It returns a vector with the plot of each visibility circle, which can be used, for example, to build a legend.

Note

Since this function draws into an existing axis, it does not apply the theme provided by the function SatelliteAnalysis.makie_theme. The plot inherits the styling of the figure that owns ax.

Warning

This function only works after loading the package GeoJSON.jl and one Makie.jl backend (CairoMakie.jl or GLMakie.jl, for example).

Keywords

  • ground_facilities::Union{Nothing, AbstractVector{<:NTuple{3, Number}}}: Vector with the WGS84 position of each ground facility (latitude [rad], longitude [rad], altitude [m]), as used to compute the visibility circles, which selects the position of the ground facility markers. If it is nothing, the positions are estimated using the visibility circles. (Default: nothing)
  • ground_facility_names::Union{Nothing, AbstractVector{<:AbstractString}}: The user can provide a vector of strings with the length of vgf_vc to be plotted with the visibility circles. If this parameter is nothing, no ground facility name is added to the figure. (Default: nothing)

All other kwargs... are passed to the function lines! that plots each visibility circle, allowing the selection of attributes such as linestyle and linewidth.

Extended Help

Throws

  • ArgumentError: If ground_facility_names or ground_facilities is not nothing and its length differs from the length of vgf_vc.

Examples

julia> using SatelliteAnalysis, GeoJSON, GLMakie

julia> gfv1 = ground_facility_visibility_circle((0, 0, 0), EARTH_EQUATORIAL_RADIUS + 700e3);

julia> gfv2 = ground_facility_visibility_circle((-40 |> deg2rad, -60 |> deg2rad, 0), EARTH_EQUATORIAL_RADIUS + 700e3);

julia> fig = Figure(size = (1000, 1000))

julia> ax = Axis(fig[1, 1])

julia> plot_ground_facility_visibility_circles!(
           ax,
           [gfv1, gfv2];
           ground_facility_names = ["GF 1", "GF 2"]
       )
source
SatelliteAnalysis.plot_ground_facility_visibility_circles — Method
plot_ground_facility_visibility_circles(vgf_vc::Vector{Vector{NTuple{2, T}}}; kwargs...) where {T <: Number} -> Figure, Axis

Plot the ground facility visibility circles in the vector vgf_vc, where each element is computed using the function ground_facility_visibility_circle. It returns the objects Figure and Axis used to plot the data. For more information, please refer to Makie.jl documentation.

Note

This function plots the countries' borders in the created figure using the file with the country polygons fetched with the function fetch_country_polygons. Hence, if this file does not exist, the algorithm tries to download it.

Warning

This function only works after loading the package GeoJSON.jl and one Makie.jl backend (CairoMakie.jl or GLMakie.jl, for example).

Keywords

  • ground_facilities::Union{Nothing, AbstractVector{<:NTuple{3, Number}}}: Vector with the WGS84 position of each ground facility (latitude [rad], longitude [rad], altitude [m]), as used to compute the visibility circles, which selects the position of the ground facility markers. If it is nothing, the positions are estimated using the visibility circles. (Default: nothing)
  • ground_facility_names::Union{Nothing, AbstractVector{<:AbstractString}}: The user can provide a vector of strings with the length of vgf_vc to be plotted with the visibility circles. If this parameter is nothing, no ground facility name is added to the figure. (Default: nothing)
  • theme::Union{Nothing, Symbol, Makie.Theme}: Theme used to style the figure, which is applied locally. If it is a Symbol, it selects the variant of the theme created by the function SatelliteAnalysis.makie_theme, which can be :light or :dark. If it is a Makie.Theme, this theme is applied. If it is nothing, no theme is applied, and the figure uses the current Makie theme. In the last two cases, the elements that are not styled by the theme use the colors of the variant :light. (Default: :light)

All other kwargs... are passed to the function plot_world_map.

Extended help

Throws

  • ArgumentError: If the theme variant in theme is not :dark or :light.
  • ArgumentError: If ground_facility_names or ground_facilities is not nothing and its length differs from the length of vgf_vc.

Examples

julia> using SatelliteAnalysis, GeoJSON, GLMakie

julia> gfv1 = ground_facility_visibility_circle((0, 0, 0), EARTH_EQUATORIAL_RADIUS + 700e3);

julia> gfv2 = ground_facility_visibility_circle((-40 |> deg2rad, -60 |> deg2rad, 0), EARTH_EQUATORIAL_RADIUS + 700e3);

julia> fig, ax = plot_ground_facility_visibility_circles(
           [gfv1, gfv2];
           ground_facility_names = ["GF 1", "GF 2"]
       );

julia> fig
source
SatelliteAnalysis.plot_ground_track! — Method
plot_ground_track!(ax::Axis, gt::Vector{NTuple{2, T}}; kwargs...) where {T <: Number} -> Lines

Plot in the Makie.jl axis ax the ground track gt computed using the function ground_track, returning the created plot, which can be used, for example, to build a legend. All the keywords kwargs... are passed to the function lines!, allowing the selection of attributes such as color, label, linestyle, and linewidth.

Note

Since this function draws into an existing axis, it does not apply the theme provided by the function SatelliteAnalysis.makie_theme. The plot inherits the styling of the figure that owns ax.

Warning

This function only works after loading the package GeoJSON.jl and one Makie.jl backend (CairoMakie.jl or GLMakie.jl, for example).

Extended Help

Examples

julia> using SatelliteAnalysis, GeoJSON, GLMakie

julia> jd₀ = date_to_jd(2021, 1, 1)
2.4592155e6

julia> orb = KeplerianElements(
           jd₀,
           7130.982e3,
           0.001111,
           98.405 |> deg2rad,
           ltdn_to_raan(10.5, jd₀),
           π / 2,
           0
       )
KeplerianElements{TrueAnomaly, Float64, Float64}:
  Epoch             : 2.45922e6 (2021-01-01T00:00:00)
  Semi-Major Axis   : 7130.982 km
  Eccentricity      : 0.001111
  Inclination       : 98.405°
  RA of Asc. Node   : 78.40205742°
  Arg. of Periapsis : 90.0°
  True Anomaly      : 0.0°

julia> orbp = Propagators.init(Val(:J2), orb)
OrbitPropagatorJ2{Float64, Float64}:
   Propagator name : J2 Orbit Propagator
  Propagator epoch : 2021-01-01T00:00:00
  Last propagation : 2021-01-01T00:00:00

julia> gt = ground_track(orbp; track_types = :descending, duration = 5 * 86400);


julia> fig = Figure(size = (1000, 1000))

julia> ax = Axis(fig[1, 1])

julia> plot_ground_track!(ax, gt)
source
SatelliteAnalysis.plot_ground_track — Method
plot_ground_track(gt::Vector{NTuple{2, T}}; kwargs...) where {T <: Number} -> Figure, Axis

Plot the ground track gt computed using the function ground_track. It returns the objects Figure and Axis used to plot the data. For more information, please refer to Makie.jl documentation.

Note

This function plots the countries' borders in the created figure using the file with the country polygons fetched with the function fetch_country_polygons. Hence, if this file does not exist, the algorithm tries to download it.

Warning

This function only works after loading the package GeoJSON.jl and one Makie.jl backend (CairoMakie.jl or GLMakie.jl, for example).

Keywords

  • theme::Union{Nothing, Symbol, Makie.Theme}: Theme used to style the figure, which is applied locally. If it is a Symbol, it selects the variant of the theme created by the function SatelliteAnalysis.makie_theme, which can be :light or :dark. If it is a Makie.Theme, this theme is applied. If it is nothing, no theme is applied, and the figure uses the current Makie theme. In the last two cases, the elements that are not styled by the theme use the colors of the variant :light. (Default: :light)

All other kwargs... are passed to the function plot_world_map.

Extended help

Throws

  • ArgumentError: If the theme variant in theme is not :dark or :light.

Examples

julia> using SatelliteAnalysis, GeoJSON, GLMakie

julia> jd₀ = date_to_jd(2021, 1, 1)
2.4592155e6

julia> orb = KeplerianElements(
           jd₀,
           7130.982e3,
           0.001111,
           98.405 |> deg2rad,
           ltdn_to_raan(10.5, jd₀),
           π / 2,
           0
       )
KeplerianElements{TrueAnomaly, Float64, Float64}:
  Epoch             : 2.45922e6 (2021-01-01T00:00:00)
  Semi-Major Axis   : 7130.982 km
  Eccentricity      : 0.001111
  Inclination       : 98.405°
  RA of Asc. Node   : 78.40205742°
  Arg. of Periapsis : 90.0°
  True Anomaly      : 0.0°

julia> orbp = Propagators.init(Val(:J2), orb)
OrbitPropagatorJ2{Float64, Float64}:
   Propagator name : J2 Orbit Propagator
  Propagator epoch : 2021-01-01T00:00:00
  Last propagation : 2021-01-01T00:00:00

julia> gt = ground_track(orbp; track_types = :descending, duration = 5 * 86400);

julia> fig, ax = plot_ground_track(gt; size = (2000, 1000))
(Scene (2000px, 1000px):
  0 Plots
  1 Child Scene:
    └ Scene (2000px, 1000px), Axis (2 plots))

julia> fig
source
SatelliteAnalysis.plot_world_map! — Method
plot_world_map!(ax::Axis; kwargs...) -> Poly

Plot the country polygons of the world map in the Makie.jl axis ax, in which the X-axis is the longitude [°] and the Y-axis is the latitude [°], returning the created plot. This function does not change the axis limits, ticks, or labels.

Note

This function plots the countries' borders using the file with the country polygons fetched with the function fetch_country_polygons. Hence, if this file does not exist, the algorithm tries to download it.

Note

Since this function draws into an existing axis, it does not apply the theme provided by the function SatelliteAnalysis.makie_theme. The plot inherits the styling of the figure that owns ax.

Warning

This function only works after loading the package GeoJSON.jl and one Makie.jl backend (CairoMakie.jl or GLMakie.jl, for example).

Keywords

  • theme::Union{Nothing, Symbol, Makie.Theme}: Select the colors of the country polygons, which are not styled by the Makie theme. If it is :dark or :light, we use the colors of the respective variant of the theme provided by SatelliteAnalysis.makie_theme. If it is a Makie.Theme or nothing, we use the colors of the light variant. (Default: :light)

All other kwargs... are passed to the function poly!, overriding the attributes selected by this function (color, strokecolor, and strokewidth).

Extended help

Throws

  • ArgumentError: If theme is a Symbol other than :dark or :light.
source
SatelliteAnalysis.plot_world_map — Method
plot_world_map(; kwargs...) -> Figure, Axis

Create a Makie.jl Figure and Axis with the world map. The figure is styled with the theme obtained from the function SatelliteAnalysis.makie_theme, selected by the keyword theme. All other kwargs... are passed to the function Figure. For more information, please refer to Makie.jl documentation.

Note

This function plots the countries' borders in the created figure using the file with the country polygons fetched with the function fetch_country_polygons. Hence, if this file does not exist, the algorithm tries to download it.

Warning

This function only works after loading the package GeoJSON.jl and one Makie.jl backend (CairoMakie.jl or GLMakie.jl, for example).

Keywords

  • theme::Union{Nothing, Symbol, Makie.Theme}: Theme used to style the figure, which is applied locally. If it is a Symbol, it selects the variant of the theme created by the function SatelliteAnalysis.makie_theme, which can be :light or :dark. If it is a Makie.Theme, this theme is applied. If it is nothing, no theme is applied, and the figure uses the current Makie theme. In the last two cases, the elements that are not styled by the theme use the colors of the variant :light. (Default: :light)
  • size::Tuple: Size of the figure. (Default: (1450, 800))

Extended help

Throws

  • ArgumentError: If the theme variant in theme is not :dark or :light.
source
SatelliteAnalysis.sun_sync_orbit_from_angular_velocity — Method
sun_sync_orbit_from_angular_velocity(angvel::T1, e::T2 = 0; kwargs...) where {T1 <: Number, T2 <: Number} -> T, T, Bool

Compute the Sun-synchronous orbit semi-major axis [m] and inclination [rad] given the angular velocity angvel [rad / s] and the orbit eccentricity e [ ]. If the latter is omitted, the orbit is considered circular, i.e., e = 0.

The algorithm here considers only the perturbation terms up to J₂.

Note

Internally, this function uses the precision obtained by promoting T1 and T2 to a floating-point number T.

Keywords

  • max_iterations::Integer: Maximum number of iterations in the Newton-Raphson method. (Default: 30)
  • no_warnings::Bool: If true, no warnings will be printed. (Default: false)
  • tolerance::Union{Nothing, NTuple{2, Number}}: Residue tolerances to verify if the numerical method has converged. If it is nothing, (√eps(T), √eps(T)) will be used, where T is the internal type for the computations. Notice that the residue function f₁ unit is [deg / day], whereas the f₂ unit is [deg / min]. (Default: nothing)
  • m0::Number: Standard gravitational parameter for Earth [m³ / s²]. (Default: GM_EARTH)
  • J2::Number: J₂ perturbation term. (Default: EGM_2008_J2)
  • R0::Number: Earth's equatorial radius [m]. (Default: EARTH_EQUATORIAL_RADIUS)

Returns

  • T: Semi-major axis [m].
  • T: Inclination [rad].
  • Bool: true if the Newton-Raphson algorithm converged, or false otherwise.

Extended help

A Sun-synchronous orbit is defined as an orbit in which the precession of the right ascension of the ascending node (RAAN) equals the Earth's orbit mean motion. In this case, the orbit plane will have the same orientation to the Sun at the ascending node.

The RAAN time-derivative considering only the secular terms up to J₂ is [1, p. 372]:

∂Ω      3                       n̄
── = - ─── R₀² . J₂ . cos(i) . ─── .
∂t      2                       p²

where:

         ┌                                                ┐
         │      3    R₀²                                  │
n̄ = n₀ . │ 1 + ─── . ─── . J₂ . √(1 - e²) . (2 - 3sin²(i))│.
         │      4     p²                                  │
         └                                                ┘

We can express the orbit angular velocity in terms of its nodal period, i.e., the period it takes for the satellite to cross the ascending node two consecutive times:

          ∂M     ∂ω
angvel = ──── + ────,
          ∂t     ∂t

                  3    R₀²
angvel = n̄ + n̄ . ─── . ─── . J₂ . (4 - 5sin²(i)),
                  4     p²

where n̄ is the perturbed mean motion due to the same consideration as presented for the RAAN time-derivative.

Finally, this function finds the pair (a, i) that simultaneously solves the equations:

∂Ω
── (a, i) = EARTH_ORBIT_MEAN_MOTION,
∂t

 ∂M            ∂ω
──── (a, i) + ──── (a, i) = angvel,
 ∂t            ∂t

using the Newton-Raphson method with the presented equations.

Throws

  • ArgumentError: If angvel is not positive, if e is not in the interval [0, 1), or if there is no Sun-synchronous orbit with the angular velocity angvel and eccentricity e.

Notice that, differently from sun_sync_orbit_inclination, this function only prints a warning if the perigee of the computed orbit is inside the Earth.

Examples

julia> using SatelliteAnalysis

julia> sun_sync_orbit_from_angular_velocity(0.06 |> deg2rad)
(7.130983931054438e6, 1.7175898374396166, true)

julia> sun_sync_orbit_from_angular_velocity(0.06 |> deg2rad, 0)
(7.130983931054438e6, 1.7175898374396166, true)

julia> sun_sync_orbit_from_angular_velocity(0.06 |> deg2rad, 0.1)
(7.130862514086433e6, 1.714641068920069, true)

The user can verify some internal information of the solver by turning on the debugging logs:

julia> using Logging

julia> with_logger(ConsoleLogger(stderr, Logging.Debug)) do
           sun_sync_orbit_from_angular_velocity(0.06 |> deg2rad)
       end
┌ Debug: Iteration #1
│   Estimation :
│     a  = 7136.635453908904 km
│     i  = 98.42900728043362 °
│   Residues :
│     f₁ = 0.0005980316229170501 ° / day
│     f₂ = 0.004266929861826085 ° / min
└ @ SatelliteAnalysis ~/.julia/dev/SatelliteAnalysis/src/sun_synchronous_orbits.jl
┌ Debug: Iteration #2
│   Estimation :
│     a  = 7130.981705295342 km
│     i  = 98.41061636567355 °
│   Residues :
│     f₁ = 2.676623528818922e-6 ° / day
│     f₂ = -1.6797554520664448e-6 ° / min
└ @ SatelliteAnalysis ~/.julia/dev/SatelliteAnalysis/src/sun_synchronous_orbits.jl
┌ Debug: Iteration #3
│   Estimation :
│     a  = 7130.983931054085 km
│     i  = 98.41064861981883 °
│   Residues :
│     f₁ = 3.592792729989469e-12 ° / day
│     f₂ = -2.6423307986078726e-13 ° / min
└ @ SatelliteAnalysis ~/.julia/dev/SatelliteAnalysis/src/sun_synchronous_orbits.jl
(7.130983931054438e6, 1.7175898374396166, true)

References

  • [1] Kozai, Y (1959). The Motion of a Close Earth Satellite. The Astronomical Journal, v. 64, no. 1274, pp. 367 – 377.
source
SatelliteAnalysis.sun_sync_orbit_inclination — Method
sun_sync_orbit_inclination(a::T1, e::T2 = 0; kwargs...) where {T1 <: Number, T2 <: Number} -> T, Bool

Compute the inclination [rad] of the Sun-synchronous orbit with semi-major axis a [m] and the eccentricity e [ ]. If the latter is omitted, the orbit is considered circular, i.e., e = 0.

The algorithm here considers only the perturbation terms up to J₂.

Note

Internally, this function uses the precision obtained by promoting T1 and T2 to a floating-point number T.

Keywords

  • max_iterations::Integer: Maximum number of iterations in the Newton-Raphson method. (Default: 30)
  • no_warnings::Bool: If true, no warnings will be printed. (Default: false)
  • tolerance::Union{Nothing, Number}: Residue tolerance to verify if the numerical method has converged. If it is nothing, √eps(T) will be used, where T is the internal type for the computations. Notice that the residue unit is [deg / day]. (Default: nothing)
  • m0::Number: Standard gravitational parameter for Earth [m³ / s²]. (Default: GM_EARTH)
  • J2::Number: J₂ perturbation term. (Default: EGM_2008_J2)
  • R0::Number: Earth's equatorial radius [m]. (Default: EARTH_EQUATORIAL_RADIUS)

Returns

  • T: Inclination [rad] of the Sun-synchronous orbit with semi-major axis a and eccentricity e.
  • Bool: true if the Newton-Raphson algorithm converged, or false otherwise.

Extended help

A Sun-synchronous orbit is defined as an orbit in which the precession of the right ascension of the ascending node (RAAN) equals the Earth's orbit mean motion. In this case, the orbit plane will have the same orientation to the Sun at the ascending node.

The RAAN time-derivative considering only the secular terms up to J₂ is [1, p. 372]:

∂Ω      3                       n̄
── = - ─── R₀² . J₂ . cos(i) . ─── .
∂t      2                       p²

where:

         ┌                                                ┐
         │      3    R₀²                                  │
n̄ = n₀ . │ 1 + ─── . ─── . J₂ . √(1 - e²) . (2 - 3sin²(i))│.
         │      4     p²                                  │
         └                                                ┘

Finally, this function solves the equation:

∂Ω
── (i) = EARTH_ORBIT_MEAN_MOTION
∂t

for i using the Newton-Raphson method with the presented equations.

Throws

  • ArgumentError: If e is not in the interval [0, 1), if the perigee is not above the Earth's surface, or if there is no Sun-synchronous orbit with the semi-major axis a and eccentricity e.

Examples

julia> using SatelliteAnalysis

julia> sun_sync_orbit_inclination(7130.982e3)
(1.7175896973066611, true)

julia> sun_sync_orbit_inclination(7130.982e3, 0)
(1.7175896973066611, true)

julia> sun_sync_orbit_inclination(7130.982e3, 0.001111)
(1.7175893324980402, true)

The user can verify some internal information of the solver by turning on the debugging logs:

julia> using Logging

julia> with_logger(ConsoleLogger(stderr, Logging.Debug)) do
           sun_sync_orbit_inclination(7130.982e3)
       end
┌ Debug: Iteration #1
│   Estimation : 98.41064059121584 °
│   Residue    : 0.0005992085524891833 ° / day
└ @ SatelliteAnalysis ~/.julia/dev/SatelliteAnalysis/src/sun_synchronous_orbits.jl
┌ Debug: Iteration #2
│   Estimation : 98.41064059082426 °
│   Residue    : -4.556321986370904e-11 ° / day
└ @ SatelliteAnalysis ~/.julia/dev/SatelliteAnalysis/src/sun_synchronous_orbits.jl
(1.7175896973066611, true)

References

  • [1] Kozai, Y (1959). The Motion of a Close Earth Satellite. The Astronomical Journal, v. 64, no. 1274, pp. 367 – 377.
source
SatelliteAnalysis.sun_sync_orbit_semi_major_axis — Method
sun_sync_orbit_semi_major_axis(i::T1, e::T2 = 0; kwargs...) where {T1 <: Number, T2 <: Number} -> T, Bool

Compute the semi-major axis [m] of the Sun-synchronous orbit with inclination i [rad] and the eccentricity e [ ]. If the latter is omitted, the orbit is considered circular, i.e., e = 0.

The algorithm here considers only the perturbation terms up to J₂.

Note

Internally, this function uses the precision obtained by promoting T1 and T2 to a floating-point number T.

Keywords

  • max_iterations::Integer: Maximum number of iterations in the Newton-Raphson method. (Default: 30)
  • no_warnings::Bool: If true, no warnings will be printed. (Default: false)
  • tolerance::Union{Nothing, Number}: Residue tolerance to verify if the numerical method has converged. If it is nothing, √eps(T) will be used, where T is the internal type for the computations. Notice that the residue unit is [deg / day]. (Default: nothing)
  • m0::Number: Standard gravitational parameter for Earth [m³ / s²]. (Default: GM_EARTH)
  • J2::Number: J₂ perturbation term. (Default: EGM_2008_J2)
  • R0::Number: Earth's equatorial radius [m]. (Default: EARTH_EQUATORIAL_RADIUS)

Returns

  • T: Semi-major axis [m] of the Sun-synchronous orbit with inclination i and eccentricity e.
  • Bool: true if the Newton-Raphson algorithm converged, or false otherwise.

Extended help

A Sun-synchronous orbit is defined as an orbit in which the precession of the right ascension of the ascending node (RAAN) equals the Earth's orbit mean motion. In this case, the orbit plane will have the same orientation to the Sun at the ascending node.

The RAAN time-derivative considering only the secular terms up to J₂ is [1, p. 372]:

∂Ω      3                       n̄
── = - ─── R₀² . J₂ . cos(i) . ─── .
∂t      2                       p²

where:

         ┌                                                ┐
         │      3    R₀²                                  │
n̄ = n₀ . │ 1 + ─── . ─── . J₂ . √(1 - e²) . (2 - 3sin²(i))│.
         │      4     p²                                  │
         └                                                ┘

Finally, this function solves the equation:

∂Ω
── (a) = EARTH_ORBIT_MEAN_MOTION
∂t

for a using the Newton-Raphson method with the presented equations.

Throws

  • ArgumentError: If e is not in the interval [0, 1), or if there is no Sun-synchronous orbit with the inclination i and eccentricity e.

Notice that, differently from sun_sync_orbit_inclination, this function only prints a warning if the perigee of the computed orbit is inside the Earth.

Examples

julia> using SatelliteAnalysis

julia> sun_sync_orbit_semi_major_axis(98.410 |> deg2rad)
(7.130827866508738e6, true)

julia> sun_sync_orbit_semi_major_axis(98.410 |> deg2rad, 0)
(7.130827866508738e6, true)

julia> sun_sync_orbit_semi_major_axis(98.410 |> deg2rad, 0.001111)
(7.1308328955274355e6, true)

The user can verify some internal information of the solver by turning on the debugging logs:

julia> using Logging

julia> with_logger(ConsoleLogger(stderr, Logging.Debug)) do
           sun_sync_orbit_semi_major_axis(98.41064163374567 |> deg2rad)
       end
┌ Debug: Iteration #1
│   Estimation : 7130.981820550704 km
│   Residue    : 0.0005989504045072862 ° / day
└ @ SatelliteAnalysis ~/.julia/dev/SatelliteAnalysis/src/sun_synchronous_orbits.jl
┌ Debug: Iteration #2
│   Estimation : 7130.982250931794 km
│   Residue    : -2.081337784770338e-7 ° / day
└ @ SatelliteAnalysis ~/.julia/dev/SatelliteAnalysis/src/sun_synchronous_orbits.jl
┌ Debug: Iteration #3
│   Estimation : 7130.982250931845 km
│   Residue    : -2.4312691616901194e-14 ° / day
└ @ SatelliteAnalysis ~/.julia/dev/SatelliteAnalysis/src/sun_synchronous_orbits.jl
(7.130982250931845e6, true)

References

  • [1] Kozai, Y (1959). The Motion of a Close Earth Satellite. The Astronomical Journal, v. 64, no. 1274, pp. 367 – 377.
source
SatelliteAnalysis.@decay_analysis__jacchia77 — Macro
@decay_analysis__jacchia77

Keyword set for decay_analysis that selects the Jacchia 1977 atmospheric model provided by SatelliteToolboxAtmosphericModels.jl instead of the default NRLMSISE-00. The macro expands to the keywords atmospheric_model, atmospheric_model_name, and space_indices, hence it must be used in the keyword section of the call:

decay_analysis(
    orb;
    satellite_mass = 100.0,
    satellite_mean_area = 1.0,
    @decay_analysis__jacchia77
)

The Jacchia 1977 model consumes the space indices f107 (daily 10.7 cm solar flux) [sfu], f107_avg (81-day average of the 10.7 cm solar flux) [sfu], and kp (daily geomagnetic index Kp) [-] from the named tuple provided by the keyword space_indices. The macro also selects a default space indices source with these fields: the daily F10.7 adjusted to 1 AU (space index F10adj), the centered 81-day average of the adjusted F10.7 (space index F10adj_avg_center81), and the observed daily Kp (space index Kp_daily), falling back to the predicted adjusted F10.7 (space index F10adj_predicted) and to Kp = 7 / 3 (equivalent to Ap = 9, as in STELA) outside the available timespans. The adjusted flux is used because the Jacchia models were derived using the flux normalized to 1 AU, unlike NRLMSISE-00, which uses the observed flux at the actual Earth-Sun distance.

Keywords passed after the macro override the ones it provides. For example, the following call uses the Jacchia 1977 model with constant space indices:

decay_analysis(
    orb;
    satellite_mass = 100.0,
    satellite_mean_area = 1.0,
    @decay_analysis__jacchia77,
    space_indices = (f107 = 140.0, f107_avg = 140.0, kp = 3.0)
)
Note

The Jacchia 1977 model does not have a closed-form solution, so its equations are numerically integrated at every density evaluation, making the analysis considerably slower than with the default NRLMSISE-00 model. The macro @decay_analysis__jr1971 selects the Jacchia-Roberts 1971 model, a closed-form analytic fit of the Jacchia model family with speed comparable to NRLMSISE-00.

Warning

This macro only works after loading the package OrdinaryDiffEqAdamsBashforthMoulton.jl, as described in decay_analysis.

source
SatelliteAnalysis.@decay_analysis__jacchia77_stela — Macro
@decay_analysis__jacchia77_stela

Keyword set for decay_analysis that selects the STELA variant of the Jacchia 1977 atmospheric model provided by SatelliteToolboxAtmosphericModels.jl instead of the default NRLMSISE-00. The macro expands to the keywords atmospheric_model, atmospheric_model_name, and space_indices, hence it must be used in the keyword section of the call:

decay_analysis(
    orb;
    satellite_mass = 100.0,
    satellite_mean_area = 1.0,
    @decay_analysis__jacchia77_stela
)

The STELA variant replicates the simplified assembly of the Jacchia 1977 model used by the CNES tools STELA and PATRIUS, which produces total densities a few percent higher on average than the report formulation selected by @decay_analysis__jacchia77. Hence, this macro allows reproducing decay analyses performed with those tools: the decay time of a 500 km sun-synchronous satellite computed by STELA is reproduced within about 1 %, whereas the report formulation yields a decay time about 7 % longer.

The model consumes the space indices f107 (daily 10.7 cm solar flux) [sfu], f107_avg (81-day average of the 10.7 cm solar flux) [sfu], and kp (daily geomagnetic index Kp) [-] from the named tuple provided by the keyword space_indices. The macro also selects the same default space indices source as @decay_analysis__jacchia77: the daily F10.7 adjusted to 1 AU (space index F10adj), the centered 81-day average of the adjusted F10.7 (space index F10adj_avg_center81), and the observed daily Kp (space index Kp_daily), falling back to the predicted adjusted F10.7 (space index F10adj_predicted) and to Kp = 7 / 3 (equivalent to Ap = 9, as in STELA) outside the available timespans.

Keywords passed after the macro override the ones it provides. For example, the following call uses the STELA variant with constant space indices:

decay_analysis(
    orb;
    satellite_mass = 100.0,
    satellite_mean_area = 1.0,
    @decay_analysis__jacchia77_stela,
    space_indices = (f107 = 140.0, f107_avg = 140.0, kp = 3.0)
)
Note

The Jacchia 1977 model does not have a closed-form solution, so its equations are numerically integrated at every density evaluation, making the analysis considerably slower than with the default NRLMSISE-00 model.

Warning

This macro only works after loading the package OrdinaryDiffEqAdamsBashforthMoulton.jl, as described in decay_analysis.

source
SatelliteAnalysis.@decay_analysis__jr1971 — Macro
@decay_analysis__jr1971

Keyword set for decay_analysis that selects the Jacchia-Roberts 1971 atmospheric model provided by SatelliteToolboxAtmosphericModels.jl instead of the default NRLMSISE-00. The macro expands to the keywords atmospheric_model, atmospheric_model_name, and space_indices, hence it must be used in the keyword section of the call:

decay_analysis(
    orb;
    satellite_mass = 100.0,
    satellite_mean_area = 1.0,
    @decay_analysis__jr1971
)

The Jacchia-Roberts 1971 model is a closed-form analytic fit of the Jacchia model family, with speed comparable to NRLMSISE-00, unlike the Jacchia 1977 model selected by @decay_analysis__jacchia77, whose equations are numerically integrated at every density evaluation.

The model consumes the space indices f107 (daily 10.7 cm solar flux) [sfu], f107_avg (81-day average of the 10.7 cm solar flux) [sfu], and kp (daily geomagnetic index Kp) [-] from the named tuple provided by the keyword space_indices. The macro also selects a default space indices source with these fields: the daily F10.7 adjusted to 1 AU (space index F10adj), the centered 81-day average of the adjusted F10.7 (space index F10adj_avg_center81), and the observed daily Kp (space index Kp_daily), falling back to the predicted adjusted F10.7 (space index F10adj_predicted) and to Kp = 7 / 3 (equivalent to Ap = 9, as in STELA) outside the available timespans. The adjusted flux is used because the Jacchia models were derived using the flux normalized to 1 AU, unlike NRLMSISE-00, which uses the observed flux at the actual Earth-Sun distance.

Keywords passed after the macro override the ones it provides. For example, the following call uses the Jacchia-Roberts 1971 model with constant space indices:

decay_analysis(
    orb;
    satellite_mass = 100.0,
    satellite_mean_area = 1.0,
    @decay_analysis__jr1971,
    space_indices = (f107 = 140.0, f107_avg = 140.0, kp = 3.0)
)
Warning

This macro only works after loading the package OrdinaryDiffEqAdamsBashforthMoulton.jl, as described in decay_analysis.

source