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, BigFloatCompute 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.
References
- [1] Vallado, D. A (2013). Fundamentals of Astrodynamics and Applications. 4th ed. Microcosm Press, Hawthorne, CA.
SatelliteAnalysis._angle_unit_factor — Method
_angle_unit_factor(angle_unit::Symbol) -> Float64Return 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: Ifangle_unitis not:rador:deg.
SatelliteAnalysis._default_eci_to_ecef — Method
_default_eci_to_ecef(r_eci::AbstractVector, jd::Number) -> AbstractVectorConvert 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.
SatelliteAnalysis._distance_unit_factor — Method
_distance_unit_factor(distance_unit::Symbol) -> Float64Return 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: Ifdistance_unitis not:mor:km.
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.
SatelliteAnalysis._frozen_orbit__default_gravity_model — Method
_frozen_orbit__default_gravity_model() -> AbstractGravityModelReturn the default gravity model used by frozen_orbit (EGM96). The model is loaded at the first call and kept in memory. This function is thread-safe.
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) -> Float64Return 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.
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 [-].
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} -> TCompute 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].
SatelliteAnalysis._ground_repeating_orbit__half_angle_to_track_angle — Method
_ground_repeating_orbit__half_angle_to_track_angle(β::Number, a::Number, R₀::Number) -> NumberCompute 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].
SatelliteAnalysis._ground_repeating_orbit__half_angle_to_track_distance — Method
_ground_repeating_orbit__half_angle_to_track_distance(β::Number, R₀::Number) -> NumberCompute 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].
SatelliteAnalysis._is_ground_facility_visible — Method
_is_ground_facility_visible(sat_r_e::AbstractVector, gf_r_e::AbstractVector, gf_up_e::AbstractVector, sin_θ::Number) -> BoolCheck 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.
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}: Residuesf₁[° / day], related to the RAAN time-derivative, andf₂[° / min], related to the angular velocity.SMatrix{2, 2, T, 4}: Jacobian of the residues with respect toisqrt_āandcos_i.
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, TSolve 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.
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 isnothing,(√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:trueif the Newton-Raphson algorithm converged, orfalseotherwise.T: Residue related to the RAAN time-derivative [° / day].T: Residue related to the angular velocity [° / min].
SatelliteAnalysis._time_unit_factor — Function
_time_unit_factor(time_unit::Symbol[, valid_units::Tuple]) -> Float64Return 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.
Extended help
Throws
ArgumentError: Iftime_unitis not invalid_units.
SatelliteAnalysis.beta_angle — Method
beta_angle(orb::KeplerianElements, Δjd::Number; kwargs...) -> TCompute 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].
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₄.
: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⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀SatelliteAnalysis.decay_analysis — Method
decay_analysis(orb::KeplerianElements; kwargs...) -> DataFrame
decay_analysis(sv::OrbitStateVector; kwargs...) -> DataFrameCompute 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.
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.
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) -> Numberwherejd_utcis the Julian date in UTC,lat,lon, andaltare the geodetic latitude [rad], longitude [rad], and altitude [m] of the point where the density is evaluated, andspace_indicesis the named tuple with the space indices at that instant provided by the keywordspace_indices. If it isnothing, the system uses an internal wrapper for the NRLMSISE-00 model provided by SatelliteToolboxAtmosphericModels.jl, which requires the fieldsf107(daily 10.7 cm solar flux) [sfu],f107_avg(81-day average of the 10.7 cm solar flux) [sfu], andap(daily geomagnetic index) [-] in the named tuple. The macros@decay_analysis__jacchia77,@decay_analysis__jacchia77_stela, and@decay_analysis__jr1971provide 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 metadataAtmospheric Modelof the outputDataFrameand shown, for example, byplot_decay_analysis. If it isnothing, the name is derived from the keywordatmospheric_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 isnothing, the system fetches and loads the EGM96 model. (Default:nothing)input_type::Symbol: How the input elementsorbare 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 anArgumentError. (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 isnothing, the number is selected using the mean eccentricityeat the beginning of the analysis: 17 ife < 0.05, 33 ife < 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 outputDataFrame. It can be:mfor meters or:kmfor kilometers. (Default::km)space_indices::Any: Space indices required by the atmospheric model. It can be a constantNamedTupleused 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 isnothing, 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 indexF10obs), as prescribed by the NRLMSISE-00 documentation, the observed centered 81-day average F10.7 (space indexF10obs_avg_center81), and the observed daily geomagnetic index (space indexAp_daily). Outside the observed timespans, the F10.7 values fall back to the predicted observed F10.7 (space indexF10obs_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: Iftrue, the raw solution of the numerical integration (seeSciMLBase.ODESolution), whose state vector stores the mean alternate equinoctial elements[a, h, k, p, q, λ]in the same order as the fields ofAlternateEquinoctialElements, is stored in the table-level metadataSolutionof the outputDataFrame. It can be obtained usingmetadata(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,Tsit5requires 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 columntimein the outputDataFrame. It can be:sfor seconds,:minfor minutes,:hfor hours,:dfor days, or:yfor Julian years (365.25 days). (Default::y)verbose::Bool: Iftrue, a progress interface is shown instderrduring 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 usingDateTime.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 fieldsf107[sfu],f107_avg[sfu], andap[-].mean_elements: Mean Keplerian elements encoded usingKeplerianElements{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 functiontrue_anomaly.apogee_altitude: Mean apogee altitude [distance_unit].perigee_altitude: Mean perigee altitude [distance_unit].
DataFrameusing metadata. TheDataFramealso stores the following table-level metadata, which is used, for example, by the functionplot_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].
return_solutionistrue, theDataFramealso stores the rawODESolutionin the metadataSolution, which is not propagated byDataFrametransformations.
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: Ifinput_typeis not:meanor:osculating, ifdistance_unitis not:mor:km, or iftime_unitis not:s,:min,:h,:d, or:y.ArgumentError: Ifsatellite_mass,num_sampling_points_per_orbit,abstol,reltol, ortfis not positive, or ifsatellite_mean_area,C_d,C_r, orterminate_altitudeis negative.ArgumentError: If the initial mean perigee altitude is not greater thanterminate_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.289If 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);SatelliteAnalysis.decay_analysis__jacchia77_kwargs — Method
decay_analysis__jacchia77_kwargs() -> NamedTupleReturn 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.
This function only works after loading the package OrdinaryDiffEqAdamsBashforthMoulton.jl, as described in decay_analysis.
SatelliteAnalysis.decay_analysis__jacchia77_stela_kwargs — Method
decay_analysis__jacchia77_stela_kwargs() -> NamedTupleReturn 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.
This function only works after loading the package OrdinaryDiffEqAdamsBashforthMoulton.jl, as described in decay_analysis.
SatelliteAnalysis.decay_analysis__jr1971_kwargs — Method
decay_analysis__jr1971_kwargs() -> NamedTupleReturn 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.
This function only works after loading the package OrdinaryDiffEqAdamsBashforthMoulton.jl, as described in decay_analysis.
SatelliteAnalysis.design_sun_sync_ground_repeating_orbit — Method
design_sun_sync_ground_repeating_orbit(minimum_repetition::Int, maximum_repetition::Int; kwargs...) -> DataFrameList 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 keywordpretty_revs_per_dayisfalse, this column containsTuples 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.
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 outputDataFrame. It can be:degfor degrees or:radfor radians. (Default::deg)distance_unit::Symbol: The unit for all the distances in the outputDataFrame. It can be:mfor meters or:kmfor 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 outputDataFrame. (Default: 18)minimum_revs_per_day::Number: Minimum number of revolutions per day of the orbits in the outputDataFrame. (Default: 13)pretty_revs_per_day::Bool: Iftrue, 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 outputDataFrame. If it isnothing, 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 outputDataFrame. If it isnothing, 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 outputDataFrame. It can be:sfor seconds,:minfor minutes, or:hfor 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, ifeccentricityis not in the interval[0, 1), or ifangle_unit,distance_unit, ortime_unitis not one of the supported symbols.
SatelliteAnalysis.eclipse_time_summary — Method
eclipse_time_summary(orbp::OrbitPropagator; kwargs...) -> DataFrameCompute 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 isnothing, 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::sfor seconds (Default);:minfor minutes; or:hfor hours.
Returns
DataFrame: The function returns aDataFramewith four columns:date: Date of the analysis [UTC] encoded usingDate.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].
DataFrameusing metadata.
Extended Help
Throws
ArgumentError: Ifnum_daysis lower than 1, ifstepis not positive or not lower than the orbital period, or iftime_unitis 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)SatelliteAnalysis.fetch_country_polygons — Function
fetch_country_polygons(url = "https://pkgstore.datahub.io/core/geo-countries/countries/archive/23f420f929e0e09c39d916b8aaa166fb/countries.geojson"; kwargs...) -> StringFetch 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.
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 fromurleven if it already exists. (Default:false)
SatelliteAnalysis.find_crossing — Method
find_crossing(f::Function, t₀::Number, t₁::Number, s₀, s₁, vargs...; Δ = 1e-3, max = 100, kwargs...) -> TReturn 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.
Examples
julia> SatelliteAnalysis.find_crossing(
t -> (sin(t) > 0),
-0.3,
0.3,
false,
true;
Δ = 1e-10
)
6.984919309616089e-11SatelliteAnalysis.frozen_orbit — Method
frozen_orbit(a::Number, i::Number; kwargs...) -> Float64, Float64Compute 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].
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 objectAbstractGravityModelof the packageSatelliteToolboxGravityModels.jlfor more information. If it isnothing, 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 ingravity_modelwill be used. Otherwise, if it is lower than 3 or higher than thegravity_modelmaximum 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 dtThis orbit is called frozen. Refer to [1] for more information.
Throws
ArgumentError: If the inclinationiis 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)SatelliteAnalysis.ground_facility_accesses — Method
ground_facility_accesses(orbp, [(WGS84)]; kwargs...) -> DataFrameCompute 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.
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 bef_eci_to_ecef(r_i::AbstractVector, jd::Number) -> AbstractVectorand it must return the position vector
r_irepresented in the ECEF at the instantjd[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:anyi.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::sfor seconds (Default);:minfor minutes; or:hfor hours.
Returns
DataFrame: The function returns aDataFramewith three columns:access_beginning: Time of the access beginning [UTC] encoded usingDateTime.access_end: Time of the access end [UTC] encoded usingDateTime.duration: Duration of the access [time_unit].
DataFrameusing metadata.
Extended Help
Throws
ArgumentError: Ifstepis not positive, ifdurationis negative, or iftime_unitis 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.45933SatelliteAnalysis.ground_facility_gaps — Method
ground_facility_gaps(orbp, args...; duration::Number = 86400, initial_time::Number = 0, kwargs...) -> DataFrameCompute 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 aDataFramewith three columns:gap_beginning: Time of the gap beginning [UTC] encoded usingDateTime.gap_end: Time of the gap end [UTC] encoded usingDateTime.duration: Duration of the gap [time_unit].
DataFrameusing metadata.
Extended Help
Throws
ArgumentError: Ifstepis not positive, ifdurationis negative, or iftime_unitis 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.6088SatelliteAnalysis.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: Iftrue, we addNaNif 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: Ifsatellite_position_normis 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⠀ 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} -> TCompute 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].
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: Iforbit_cycleis not positive.
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} -> TCompute 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].
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: Iforbit_cycleis not positive.
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: Iftrue, we addNaNif 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 instantinitial_time + duration, even ifdurationis not a multiple ofstep. (Default: 86400)initial_time::Number: Initial time regarding the orbit propagatororbpepoch [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 bef_eci_to_ecef(r_i::AbstractVector, jd::Number) -> AbstractVectorand it must return the position vector
r_irepresented in the ECEF at the instantjd[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. Ifnothing, 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:ascendingfor only ascending passages,:descendingfor only descending passages, or:allfor both. (Default::all)
Extended Help
Throws
ArgumentError: Ifstepis not positive, ifdurationis negative, or iftrack_typesis 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⠀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} -> TCompute 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).
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.30052101658998SatelliteAnalysis.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) -> BoolCheck 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:trueif the satellite is inside the visibility circle, orfalseotherwise.
SatelliteAnalysis.lighting_condition — Method
lighting_condition(r_i::AbstractVector, s_i::AbstractVector) -> SymbolCompute 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].
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.
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.
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 functionmakie_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: Ifnis negative or greater than the number of colors in the palette, or ifvariantis not:darkor:light.ErrorException: If Makie.jl is not loaded.
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.ThemeReturn 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.
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.25makes all text 25% larger, which is useful when a figure is shrunk into a small slide area. (Default:1)mono_ticklabels::Bool: Iftrue, 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 pxThrows
ArgumentError: If the theme variant is not:darkor:light.ErrorException: If Makie.jl is not loaded.
SatelliteAnalysis.plot_decay_analysis — Method
plot_decay_analysis(df::DataFrame; kwargs...) -> Figure, AxisPlot 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.
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 columnspace_indicesofdf, used when the keywordshow_f107istrue. If it isnothing, 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 columnspace_indicesofdf, used when the keywordshow_f107istrue. If it isnothing, 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. Ifthemeis aMakie.Themeornothing, 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 isnothing, no mission name is added to the figure. (Default:nothing)mono_ticklabels::Bool: Iftrue, the tick labels are rendered using a monospaced font. This keyword only has effect ifthemeis aSymbol. (Default:false)panel_width::Union{Nothing, Real}: Width [px] of the column with the information panel and the legend. If it isnothing, the width scales with the figure width. (Default:nothing)satellite_mass::Union{Nothing, Number}: Satellite mass [kg] shown in the information panel. If it isnothing, the value is obtained from the metadataSatellite Massofdf. (Default:nothing)satellite_mean_area::Union{Nothing, Number}: Satellite mean area [m²] shown in the information panel. If it isnothing, the value is obtained from the metadataSatellite Mean Areaofdf. (Default:nothing)show_assumptions::Bool: Iftrue, the information panel shows a card with the analysis assumptions resolved from theDataFramemetadata written bydecay_analysis. (Default:true)show_dates::Bool: Iftrue, 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: Iftrue, the daily and the 81-day average 10.7 cm solar flux indices, extracted from the columnspace_indicesofdfusing the keywordsf107_getterandf107_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: Iftrueand the analysis detected a reentry, an annotation is added in the plot next to the reentry marker. It shows the estimated reentry date [UTC] whenshow_datesistrueand 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] whenshow_datesistrue; otherwise, no subtitle is added. If it isnothing, no subtitle is added to the figure. Any otherSymbolraises anArgumentError. (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 isnothing, the value is obtained from the metadataTerminate Altitudeofdf. (Default:nothing)theme::Union{Nothing, Symbol, Makie.Theme}: Theme used to style the figure, which is applied locally. If it is aSymbol, it selects the variant of the theme created by the functionSatelliteAnalysis.makie_theme, which can be:lightor:dark. If it is aMakie.Theme, this theme is applied. If it isnothing, 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 isnothing, the limits are computed automatically. (Default:nothing)ylims::Union{Nothing, Tuple}: Limits of the y-axis of the main plot. If it isnothing, 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: Ifdfis empty.ArgumentError: Ifdfdoes not have the columnstime,date,apogee_altitude, andperigee_altitude, or if the keywordshow_f107istrueanddfdoes not have the columnspace_indices.ArgumentError: If the keywordshow_f107istrueand bothf107_getterandf107_avg_getterarenothing, or if the getters cannot extract the values from the columnspace_indices.ArgumentError: If the theme variant inthemeis not:darkor:light.ArgumentError: If the keywordsubtitleis aSymbolother 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> figSatelliteAnalysis.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.
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.
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 isnothing, 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 ofvgf_vcto be plotted with the visibility circles. If this parameter isnothing, 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: Ifground_facility_namesorground_facilitiesis notnothingand its length differs from the length ofvgf_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"]
)SatelliteAnalysis.plot_ground_facility_visibility_circles — Method
plot_ground_facility_visibility_circles(vgf_vc::Vector{Vector{NTuple{2, T}}}; kwargs...) where {T <: Number} -> Figure, AxisPlot 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.
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.
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 isnothing, 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 ofvgf_vcto be plotted with the visibility circles. If this parameter isnothing, 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 aSymbol, it selects the variant of the theme created by the functionSatelliteAnalysis.makie_theme, which can be:lightor:dark. If it is aMakie.Theme, this theme is applied. If it isnothing, 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 inthemeis not:darkor:light.ArgumentError: Ifground_facility_namesorground_facilitiesis notnothingand its length differs from the length ofvgf_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> figSatelliteAnalysis.plot_ground_track! — Method
plot_ground_track!(ax::Axis, gt::Vector{NTuple{2, T}}; kwargs...) where {T <: Number} -> LinesPlot 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.
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.
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)SatelliteAnalysis.plot_ground_track — Method
plot_ground_track(gt::Vector{NTuple{2, T}}; kwargs...) where {T <: Number} -> Figure, AxisPlot 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.
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.
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 aSymbol, it selects the variant of the theme created by the functionSatelliteAnalysis.makie_theme, which can be:lightor:dark. If it is aMakie.Theme, this theme is applied. If it isnothing, 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 inthemeis not:darkor: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> figSatelliteAnalysis.plot_world_map! — Method
plot_world_map!(ax::Axis; kwargs...) -> PolyPlot 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.
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.
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.
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:darkor:light, we use the colors of the respective variant of the theme provided bySatelliteAnalysis.makie_theme. If it is aMakie.Themeornothing, 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: Ifthemeis aSymbolother than:darkor:light.
SatelliteAnalysis.plot_world_map — Method
plot_world_map(; kwargs...) -> Figure, AxisCreate 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.
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.
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 aSymbol, it selects the variant of the theme created by the functionSatelliteAnalysis.makie_theme, which can be:lightor:dark. If it is aMakie.Theme, this theme is applied. If it isnothing, 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 inthemeis not:darkor:light.
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, BoolCompute 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₂.
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: Iftrue, 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 isnothing,(√eps(T), √eps(T))will be used, whereTis the internal type for the computations. Notice that the residue functionf₁unit is [deg / day], whereas thef₂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:trueif the Newton-Raphson algorithm converged, orfalseotherwise.
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 ∂tusing the Newton-Raphson method with the presented equations.
Throws
ArgumentError: Ifangvelis not positive, ifeis not in the interval[0, 1), or if there is no Sun-synchronous orbit with the angular velocityangveland eccentricitye.
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.
SatelliteAnalysis.sun_sync_orbit_inclination — Method
sun_sync_orbit_inclination(a::T1, e::T2 = 0; kwargs...) where {T1 <: Number, T2 <: Number} -> T, BoolCompute 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₂.
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: Iftrue, no warnings will be printed. (Default:false)tolerance::Union{Nothing, Number}: Residue tolerance to verify if the numerical method has converged. If it isnothing,√eps(T)will be used, whereTis 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 axisaand eccentricitye.Bool:trueif the Newton-Raphson algorithm converged, orfalseotherwise.
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
∂tfor i using the Newton-Raphson method with the presented equations.
Throws
ArgumentError: Ifeis 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 axisaand eccentricitye.
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.
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, BoolCompute 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₂.
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: Iftrue, no warnings will be printed. (Default:false)tolerance::Union{Nothing, Number}: Residue tolerance to verify if the numerical method has converged. If it isnothing,√eps(T)will be used, whereTis 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 inclinationiand eccentricitye.Bool:trueif the Newton-Raphson algorithm converged, orfalseotherwise.
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
∂tfor a using the Newton-Raphson method with the presented equations.
Throws
ArgumentError: Ifeis not in the interval[0, 1), or if there is no Sun-synchronous orbit with the inclinationiand eccentricitye.
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.
SatelliteAnalysis.@decay_analysis__jacchia77 — Macro
@decay_analysis__jacchia77Keyword 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)
)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.
This macro only works after loading the package OrdinaryDiffEqAdamsBashforthMoulton.jl, as described in decay_analysis.
SatelliteAnalysis.@decay_analysis__jacchia77_stela — Macro
@decay_analysis__jacchia77_stelaKeyword 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)
)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.
This macro only works after loading the package OrdinaryDiffEqAdamsBashforthMoulton.jl, as described in decay_analysis.
SatelliteAnalysis.@decay_analysis__jr1971 — Macro
@decay_analysis__jr1971Keyword 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)
)This macro only works after loading the package OrdinaryDiffEqAdamsBashforthMoulton.jl, as described in decay_analysis.