Skip to content

Events & Visibility

Event detection and visibility analysis.

Event Detection

Events are detected when a function crosses zero. The crossing property indicates the direction:

  • "up": Function crosses from negative to positive
  • "down": Function crosses from positive to negative

Visibility Analysis

The VisibilityAnalysis class computes visibility intervals between ground stations and spacecraft, accounting for elevation constraints and optional body occultation. A Scenario groups spacecraft, ground stations, and a time interval together.

Quick Example

import lox_space as lox

# Find events on a trajectory
def altitude(state):
    """Returns altitude above reference radius."""
    x, y, z = state.position()
    r = (float(x)**2 + float(y)**2 + float(z)**2)**0.5
    return r - 6378000.0  # meters above Earth radius

step = lox.TimeDelta(10.0)  # 10-second step size
events = trajectory.find_events(altitude, step)
for event in events:
    print(f"{event.crossing()} crossing at {event.time()}")

# Find time intervals
intervals = trajectory.find_windows(altitude, step)
for iv in intervals:
    print(f"Interval: {iv.start()} to {iv.end()}, duration: {iv.duration()}")

# Visibility analysis
gs = lox.GroundStation("ESOC", ground_location, elevation_mask)
sc = lox.Spacecraft("ISS", lox.SGP4(tle))
scenario = lox.Scenario(start, end, spacecraft=[sc], ground_stations=[gs])
analysis = lox.VisibilityAnalysis(
    scenario,
    step=lox.TimeDelta(60),
    min_pass_duration=lox.TimeDelta(300),
)
results = analysis.compute(spk)

for iv in results.intervals("ESOC", "ISS"):
    print(f"Interval: {iv.start()} to {iv.end()}")

for p in results.passes("ESOC", "ISS"):
    print(f"Pass: {p.interval().start()} to {p.interval().end()}")

Event

Represents a detected event (zero-crossing of a function).

Events are detected when a monitored function crosses zero. The crossing direction indicates "up" (negative to positive) or "down" (positive to negative).

Methods:

  • crossing

    Return the crossing direction ("up" or "down").

  • time

    Return the time of this event.

crossing

crossing() -> str

Return the crossing direction ("up" or "down").

time

time() -> Time

Return the time of this event.


Interval

Represents a time interval between two times.

Intervals represent periods when certain conditions are met, such as visibility intervals between a ground station and spacecraft.

Methods:

  • contains

    Return whether this interval fully contains another interval.

  • contains_time

    Return whether this interval contains the given time.

  • duration

    Return the duration of this interval.

  • end

    Return the end time of this interval.

  • intersect

    Return the intersection of this interval with another.

  • is_empty

    Return whether this interval is empty (start >= end).

  • linspace

    Return a list of n evenly-spaced times within this interval.

  • overlaps

    Return whether this interval overlaps with another.

  • start

    Return the start time of this interval.

  • step_by

    Return a list of times spaced by the given step within this interval.

contains

contains(other: Interval) -> bool

Return whether this interval fully contains another interval.

contains_time

contains_time(time: Time) -> bool

Return whether this interval contains the given time.

duration

duration() -> TimeDelta

Return the duration of this interval.

end

end() -> Time

Return the end time of this interval.

intersect

intersect(other: Interval) -> Interval

Return the intersection of this interval with another.

is_empty

is_empty() -> bool

Return whether this interval is empty (start >= end).

linspace

linspace(n: int) -> list[Time]

Return a list of n evenly-spaced times within this interval.

Raises:

overlaps

overlaps(other: Interval) -> bool

Return whether this interval overlaps with another.

start

start() -> Time

Return the start time of this interval.

step_by

step_by(step: TimeDelta) -> list[Time]

Return a list of times spaced by the given step within this interval.

Raises:


find_events builtin

find_events(
    func: Callable[[Time], float], start: Time, end: Time, step: TimeDelta
) -> list[Event]

Find events where a function crosses zero.

Detects zero-crossings of a user-defined function of time.

Parameters:

  • func

    (Callable[[Time], float]) –

    Function that takes a Time and returns a float.

  • start

    (Time) –

    Start time of the analysis period.

  • end

    (Time) –

    End time of the analysis period.

  • step

    (TimeDelta) –

    Step size for sampling the function.

Returns:

  • list[Event]

    List of Event objects at the detected zero-crossings.


find_windows builtin

find_windows(
    func: Callable[[Time], float], start: Time, end: Time, step: TimeDelta
) -> list[Interval]

Find time windows where a function is positive.

Finds all intervals where a user-defined function is positive. Windows are bounded by zero-crossings of the function.

Parameters:

  • func

    (Callable[[Time], float]) –

    Function that takes a Time and returns a float.

  • start

    (Time) –

    Start time of the analysis period.

  • end

    (Time) –

    End time of the analysis period.

  • step

    (TimeDelta) –

    Step size for sampling the function.

Returns:

  • list[Interval]

    List of Interval objects for intervals where the function is positive.


intersect_intervals builtin

intersect_intervals(a: list[Interval], b: list[Interval]) -> list[Interval]

Intersect two sorted lists of intervals.

Parameters:

Returns:

  • list[Interval]

    List of intervals representing the intersection.


union_intervals builtin

union_intervals(a: list[Interval], b: list[Interval]) -> list[Interval]

Compute the union of two sorted lists of intervals.

Parameters:

Returns:

  • list[Interval]

    List of merged intervals representing the union.


complement_intervals builtin

complement_intervals(intervals: list[Interval], bound: Interval) -> list[Interval]

Compute the complement of intervals within a bounding interval.

Parameters:

  • intervals

    (list[Interval]) –

    List of intervals to complement.

  • bound

    (Interval) –

    Bounding interval.

Returns:

  • list[Interval]

    List of gap intervals within the bound.


GroundStation

A named ground station for visibility analysis.

Wraps a ground location and elevation mask with an identifier.

Parameters:

  • id

    Unique identifier for this ground station.

  • location

    Ground station location.

  • mask

    Elevation mask defining minimum elevation constraints.

  • communication_systems

    Optional list of communication systems.

Examples:

>>> gs = lox.GroundStation("ESOC", ground_location, elevation_mask)

Methods:

body_fixed_frame

body_fixed_frame() -> Frame

Return the body-fixed frame.

communication_systems

communication_systems() -> list[CommunicationSystem]

Return the communication systems.

id

id() -> str

Return the asset identifier.

location

location() -> GroundLocation

Return the ground location.

mask

mask() -> ElevationMask

Return the elevation mask.

network_id

network_id() -> str | None

Return the network identifier, if assigned.


Spacecraft

A named spacecraft for visibility analysis.

Wraps an orbit source (propagator or pre-computed trajectory) with an identifier.

Parameters:

  • id

    Unique identifier for this spacecraft.

  • orbit

    Orbit source — an SGP4, Vallado, J2 propagator, or a pre-computed Trajectory.

  • max_slew_rate

    Optional maximum slew rate.

  • communication_systems

    Optional list of communication systems.

Examples:

>>> sc = lox.Spacecraft("ISS", lox.SGP4(tle))
>>> sc = lox.Spacecraft("SAT", trajectory)

Methods:

communication_systems

communication_systems() -> list[CommunicationSystem]

Return the communication systems.

constellation_id

constellation_id() -> str | None

Return the constellation identifier, if assigned.

id

id() -> str

Return the asset identifier.

imaging_payload

imaging_payload() -> ImagingPayload | None

Return the imaging payload, if set.

max_slew_rate

max_slew_rate() -> AngularRate | None

Return the maximum slew rate, if set.


Scenario

A scenario grouping spacecraft, ground stations, and a time interval.

Parameters:

  • start

    Start time of the scenario.

  • end

    End time of the scenario.

  • spacecraft

    List of Spacecraft objects.

  • ground_stations

    List of GroundStation objects.

Examples:

>>> scenario = lox.Scenario(t0, t1, spacecraft=[sc], ground_stations=[gs])

Methods:

  • end

    Return the end time.

  • propagate

    Propagate all spacecraft, returning an Ensemble.

  • start

    Return the start time.

  • with_constellation

    Add a constellation to the scenario.

end

end() -> Time

Return the end time.

propagate

propagate() -> Ensemble

Propagate all spacecraft, returning an Ensemble.

Trajectories are transformed to ICRF using the default rotation provider.

start

start() -> Time

Return the start time.

with_constellation

with_constellation(constellation: Constellation) -> Scenario

Add a constellation to the scenario.

Converts each satellite into a Spacecraft using the constellation's selected propagator.


Ensemble

A collection of propagated trajectories keyed by spacecraft id.

Examples:

>>> ensemble = scenario.propagate()
>>> traj = ensemble.get("ISS")

Methods:

  • get

    Return the trajectory for a given spacecraft id.

get

get(id: str) -> Trajectory | None

Return the trajectory for a given spacecraft id.


VisibilityAnalysis

Computes ground-station-to-spacecraft and inter-satellite visibility.

Ground-to-space pairs are always computed when ground assets are present. Inter-satellite pairs are additionally computed when inter_satellite is set to True.

Parameters:

  • scenario

    Scenario containing spacecraft, ground stations, and time interval.

  • ensemble

    Optional pre-computed Ensemble. If not provided, the scenario is propagated automatically.

  • occulting_bodies

    Optional list of additional occulting bodies for line-of-sight checking. For inter-satellite visibility, the scenario's central body is always checked automatically.

  • step

    Optional time step for event detection (default: 60s).

  • min_pass_duration

    Optional minimum pass duration. Passes shorter than this value may be missed. Enables two-level stepping for faster detection.

  • inter_satellite

    If True, also compute inter-satellite visibility for all unique spacecraft pairs (default: False).

  • ground_space_filter

    Optional callable (GroundStation, Spacecraft) -> bool that receives a ground station and a spacecraft and returns whether the pair should be evaluated. Called once per candidate pair before the parallel phase.

  • inter_satellite_filter

    Optional callable (Spacecraft, Spacecraft) -> bool that receives two spacecraft and returns whether the pair should be evaluated. Called once per candidate pair before the parallel phase. When provided, inter-satellite visibility is automatically enabled.

  • min_range

    Optional minimum range constraint for inter-satellite pairs.

  • max_range

    Optional maximum range constraint for inter-satellite pairs.

Examples:

>>> scenario = lox.Scenario(t0, t1, spacecraft=[sc], ground_stations=[gs])
>>> analysis = lox.VisibilityAnalysis(scenario, step=lox.TimeDelta(60))
>>> results = analysis.compute(spk)

Methods:

  • compute

    Compute visibility intervals for all pairs.

compute

Compute visibility intervals for all pairs.

If no ensemble was provided at construction, the scenario is propagated automatically (trajectories transformed to ICRF).

Parameters:

  • ephemeris

    (SPK) –

    SPK ephemeris data.

Returns:


VisibilityResults

Results of a visibility analysis.

Provides access to visibility intervals and passes. Intervals (time windows) are computed eagerly; observables-rich Pass objects are computed on demand.

Methods:

all_intervals

all_intervals() -> dict[tuple[str, str], list[Interval]]

Return all intervals for all pairs.

Returns:

all_passes

all_passes() -> dict[tuple[str, str], list[Pass]]

Compute passes for all ground-to-space pairs.

Inter-satellite pairs are skipped.

Returns:

ground_space_intervals

ground_space_intervals() -> dict[tuple[str, str], list[Interval]]

Return intervals for ground-to-space pairs only.

Returns:

ground_space_pair_ids

ground_space_pair_ids() -> list[tuple[str, str]]

Return pair identifiers for ground-to-space pairs only.

inter_satellite_intervals

inter_satellite_intervals() -> dict[tuple[str, str], list[Interval]]

Return intervals for inter-satellite pairs only.

Returns:

inter_satellite_pair_ids

inter_satellite_pair_ids() -> list[tuple[str, str]]

Return pair identifiers for inter-satellite pairs only.

intervals

intervals(id1: str, id2: str) -> list[Interval]

Return visibility intervals for a specific pair.

Parameters:

  • id1

    (str) –

    First asset identifier (ground or space).

  • id2

    (str) –

    Second asset identifier (space).

Returns:

  • list[Interval]

    List of Interval objects, or empty list if pair not found.

num_pairs

num_pairs() -> int

Return the total number of pairs.

pair_ids

pair_ids() -> list[tuple[str, str]]

Return all pair identifiers.

passes

passes(ground_id: str, space_id: str) -> list[Pass]

Compute passes with observables for a specific ground-to-space pair.

This is more expensive than intervals() as it computes azimuth, elevation, range, and range rate for each time step.

Raises:

  • ValueError

    If the pair is an inter-satellite pair.

Parameters:

  • ground_id

    (str) –

    Ground asset identifier.

  • space_id

    (str) –

    Space asset identifier.

Returns:

  • list[Pass]

    List of Pass objects, or empty list if pair not found.

total_intervals

total_intervals() -> int

Return the total number of visibility intervals across all pairs.


PowerBudgetAnalysis

Power budget analysis for spacecraft in a scenario.

Computes eclipse intervals, sun beta angle, and solar flux for each spacecraft. The shadow model is cylindrical (umbra only) — penumbra is not modelled.

Parameters:

  • scenario

    Scenario containing spacecraft and time interval.

  • ensemble

    Optional pre-computed Ensemble.

  • step

    Optional time step for sampling / event detection (default: 60s).

  • spacecraft_ids

    Optional list of spacecraft ids to restrict the analysis.

Examples:

>>> analysis = lox.PowerBudgetAnalysis(scenario)
>>> results = analysis.compute()          # analytical Sun
>>> results = analysis.compute(ephemeris)  # SPK Sun

Methods:

  • compute

    Compute the power budget analysis.

compute

compute(ephemeris: SPK | None = None) -> PowerBudgetResults

Compute the power budget analysis.

Parameters:

  • ephemeris

    (SPK | None, default: None ) –

    Optional SPK ephemeris for Sun position. When omitted, an analytical model is used (valid for Earth-centred scenarios).

Returns:


PowerBudgetResults

Results of a power budget analysis.

Provides access to eclipse intervals, eclipse/sunlit fractions, beta-angle time series, and solar-flux time series for each spacecraft.

Methods:

beta_angles

beta_angles(id: str) -> TimeSeries | None

Return beta-angle time series (radians).

Parameters:

  • id

    (str) –

    Spacecraft identifier.

Returns:

  • TimeSeries | None

    TimeSeries of beta angles in radians, or None if id not found.

eclipse_fraction

eclipse_fraction(id: str) -> float | None

Return eclipse fraction (0 = fully sunlit, 1 = always eclipsed).

Parameters:

  • id

    (str) –

    Spacecraft identifier.

Returns:

  • float | None

    Eclipse fraction, or None if id not found.

eclipse_intervals

eclipse_intervals(id: str) -> list[Interval]

Return eclipse intervals for a specific spacecraft.

Parameters:

  • id

    (str) –

    Spacecraft identifier.

Returns:

  • list[Interval]

    List of Interval objects, or empty list if id not found.

solar_flux

solar_flux(id: str) -> TimeSeries | None

Return solar-flux time series (W/m²).

Parameters:

  • id

    (str) –

    Spacecraft identifier.

Returns:

  • TimeSeries | None

    TimeSeries of solar flux in W/m², or None if id not found.

sunlit_fraction

sunlit_fraction(id: str) -> float | None

Return sunlit fraction (1 - eclipse_fraction).

Parameters:

  • id

    (str) –

    Spacecraft identifier.

Returns:

  • float | None

    Sunlit fraction, or None if id not found.