Analysis¶
Interference detection strategies and link budget calculations.
Strategies¶
InterferenceStrategy ¶
Bases: ABC
Abstract base class for interference detection strategies.
Each strategy implements a different method of determining whether a satellite causes interference and optionally how much.
The calculate method receives data that is common to every
trajectory in a simulation run: the antenna pointing, telescope
facility, and observation frequency. Model-specific configuration
(transmitter characteristics, atmospheric profiles, antenna gain
patterns, link-budget functions, etc.) should be provided via the
strategy's __init__ and stored on self.
Functions¶
calculate
abstractmethod
¶
calculate(
satellite_trajectory: SatelliteTrajectory,
antenna_trajectory: AntennaTrajectory,
facility: Facility,
frequency: FrequencyRange,
) -> InterferenceResult | None
Analyze a single satellite pass for interference.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
satellite_trajectory
|
SatelliteTrajectory
|
The satellite's path (times, az, alt, distance). |
required |
antenna_trajectory
|
AntennaTrajectory
|
Where the antenna is pointing over time. |
required |
facility
|
Facility
|
Telescope location and parameters. |
required |
frequency
|
FrequencyRange
|
Observation frequency. |
required |
Returns:
| Type | Description |
|---|---|
InterferenceResult | None
|
InterferenceResult if interference detected, None otherwise. |
Source code in src/sopp/analysis/strategies.py
GeometricStrategy ¶
Bases: InterferenceStrategy
Binary in/out-of-beam detection.
Determines interference by checking whether the angular separation between the satellite and antenna boresight is less than the beam radius. This is the original SOPP behavior.
SimpleLinkBudgetStrategy ¶
Bases: InterferenceStrategy
Simple link budget calculation using peak gains and FSPL.
Calculates received power at the telescope using the Friis equation
P_rx(dBW) = EIRP(dBW) - FSPL(dB) + G_rx(dBi)
This is a "Tier 1" worst-case estimate assuming: - Peak satellite EIRP (from transmitter) - Peak telescope gain (boresight) - Free space path loss only (no atmospheric effects)
Unlike GeometricStrategy, this returns results for all trajectory points, not just those within the beam. The caller can filter based on power level or use in conjunction with geometric filtering.
Requires
facility.receiver.peak_gain_dbi must be set.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
default_eirp_dbw
|
float | None
|
Default EIRP to use for satellites that have no transmitter configured. If not provided, satellites without a transmitter will be silently skipped (returns None, no interference detected). |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If facility.receiver.peak_gain_dbi is not set. |
Source code in src/sopp/analysis/strategies.py
NadirLinkBudgetStrategy ¶
Bases: InterferenceStrategy
Full link budget with angle-dependent transmitter EIRP and receive gain.
This is a "Tier 2" calculation: P_rx(dBW) = EIRP(θ_tx) - FSPL(dB) + G_rx(θ_rx)
where θ_tx is the nadir angle at the satellite (assuming nadir-pointing antenna) and θ_rx is the receiver off-axis angle.
For Tier 1 transmitters (constant eirp_dbw), the EIRP term is constant and this produces the same result as PatternLinkBudgetStrategy. For Tier 2 transmitters (power_dbw + antenna_pattern), the EIRP varies with the nadir angle.
Requires
facility.receiver.antenna_pattern must be set.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
default_eirp_dbw
|
float | None
|
Default EIRP to use for satellites that have no transmitter configured. If not provided, satellites without a transmitter will be silently skipped (returns None). |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If facility.receiver.antenna_pattern is not set. |
Source code in src/sopp/analysis/strategies.py
PatternLinkBudgetStrategy ¶
Bases: InterferenceStrategy
Link budget using telescope antenna pattern for realistic receive gain.
This is a "Tier 1.5" calculation: - Uses the telescope's antenna pattern to look up G_rx at the actual off-axis angle to the satellite (realistic receive gain) - Uses peak satellite EIRP (worst case for transmit side)
The off-axis angle is calculated as the angular separation between where the antenna is pointing and where the satellite is in the sky.
P_rx(dBW) = EIRP(dBW) - FSPL(dB) + G_rx(off_axis_angle)
This gives a more realistic estimate than SimpleLinkBudgetStrategy because it accounts for how much the satellite is in the telescope's sidelobes vs main beam.
Requires
facility.receiver.antenna_pattern must be set.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
default_eirp_dbw
|
float | None
|
Default EIRP to use for satellites that have no transmitter configured. If not provided, satellites without a transmitter will be silently skipped (returns None, no interference detected). |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If facility.receiver.antenna_pattern is not set. |
Source code in src/sopp/analysis/strategies.py
Link Budget¶
free_space_path_loss_db ¶
Calculate free space path loss in dB.
Uses the standard FSPL formula
FSPL(dB) = 20log10(d) + 20log10(f) - 147.55
where
d = distance in meters f = frequency in Hz 147.55 = 20log10(c/(4pi)) with c = speed of light
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
distance_m
|
float | ndarray
|
Distance between transmitter and receiver in meters. Can be a scalar or numpy array. |
required |
frequency_hz
|
float
|
Frequency in Hz. |
required |
Returns:
| Type | Description |
|---|---|
float | ndarray
|
Path loss in dB (positive value). Same shape as distance_m. |
Source code in src/sopp/analysis/link_budget.py
received_power_dbw ¶
received_power_dbw(
eirp_dbw: float,
distance_m: float | ndarray,
frequency_hz: float,
gain_rx_dbi: float,
) -> float | ndarray
Calculate received power using the Friis equation.
Uses the link budget formula
P_rx(dBW) = EIRP(dBW) - FSPL(dB) + G_rx(dBi)
This is a worst-case "Tier 1" estimate assuming: - Main beam alignment (peak gains at both ends) - No atmospheric losses - No polarization mismatch
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
eirp_dbw
|
float
|
Effective Isotropic Radiated Power in dBW. |
required |
distance_m
|
float | ndarray
|
Distance between transmitter and receiver in meters. Can be a scalar or numpy array. |
required |
frequency_hz
|
float
|
Frequency in Hz. |
required |
gain_rx_dbi
|
float
|
Receiver antenna gain in dBi. |
required |
Returns:
| Type | Description |
|---|---|
float | ndarray
|
Received power in dBW. Same shape as distance_m. |
Source code in src/sopp/analysis/link_budget.py
Geometry¶
calculate_angular_separation ¶
calculate_angular_separation(
az1: NDArray[float64],
alt1: NDArray[float64],
az2: NDArray[float64],
alt2: NDArray[float64],
) -> NDArray[float64]
Calculates the angular separation between two sets of coordinates.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
az1
|
NDArray[float64]
|
Azimuth of the first object in degrees. |
required |
alt1
|
NDArray[float64]
|
Altitude of the first object in degrees. |
required |
az2
|
NDArray[float64]
|
Azimuth of the second object in degrees. |
required |
alt2
|
NDArray[float64]
|
Altitude of the second object in degrees. |
required |
Returns:
| Type | Description |
|---|---|
NDArray[float64]
|
The angular separation in degrees. |
Source code in src/sopp/analysis/geometry.py
calculate_nadir_angle ¶
calculate_nadir_angle(
elevation_deg: NDArray[float64],
distance_km: NDArray[float64],
) -> NDArray[float64]
Calculate the nadir angle at the satellite for each trajectory point.
The nadir angle is the angle at the satellite between the nadir direction (toward Earth center) and the direction to the ground observer. For nadir-pointing satellite antennas, this equals the transmitter off-axis angle.
Derived from the law of sines on the Earth-center / satellite / observer triangle.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
elevation_deg
|
NDArray[float64]
|
Elevation of the satellite as seen from the ground, in degrees. |
required |
distance_km
|
NDArray[float64]
|
Slant range from observer to satellite in km. |
required |
Returns:
| Type | Description |
|---|---|
NDArray[float64]
|
Nadir angle in degrees. |