test_linkBudget
Test Description
This unit test validates the linkBudget module which computes end-to-end
radio link budget between two antennas. The test writes directly to
AntennaLogMsgPayload messages to isolate the linkBudget module from
simpleAntenna dependencies.
Test Coverage
Free Space Path Loss (FSPL) calculations
Carrier-to-Noise Ratio (CNR) calculations
Pointing loss calculations
Frequency offset loss calculations
Atmospheric attenuation (space-to-ground links)
Space-to-space and space-to-ground link configurations
Antenna state handling (Tx/Rx/RxTx combinations)
Edge cases (no bandwidth overlap, grazing angles, extreme distances, etc.)
Robustness tests (invalid inputs, boundary conditions)
- test_linkBudget.apply_pointing_error(base_sigma, error_az_rad, error_el_rad)[source]
Apply pointing error to a base orientation.
- Parameters:
base_sigma – Base MRP orientation [s1, s2, s3]
error_az_rad – Azimuth error [rad] (rotation about Y in antenna frame)
error_el_rad – Elevation error [rad] (rotation about X in antenna frame)
- Returns:
New MRP with pointing error applied
- test_linkBudget.compute_antenna_derived_params(directivity_dB, k, P_Tx, eta_r, T_E, T_Ambient, T_sky, bandwidth)[source]
Compute derived antenna parameters for test setup.
- Parameters:
directivity_dB – Antenna directivity [dB]
k – HPBW ratio (az/el)
P_Tx – Transmit power [W]
eta_r – Radiation efficiency [-]
T_E – Equivalent noise temperature [K]
T_Ambient – Ambient temperature [K]
T_sky – Sky temperature [K]
bandwidth – Bandwidth [Hz]
- Returns:
dict with HPBW_az, HPBW_el, P_eirp_dB, G_rx_dB, P_N, T_S
- test_linkBudget.compute_bandwidth_overlap(f1, B1, f2, B2)[source]
Compute the overlapping bandwidth between two antennas.
- Parameters:
f1 – Center frequency of antenna 1 [Hz]
B1 – Bandwidth of antenna 1 [Hz]
f2 – Center frequency of antenna 2 [Hz]
B2 – Bandwidth of antenna 2 [Hz]
- Returns:
Overlapping bandwidth [Hz] (can be negative if no overlap)
- test_linkBudget.compute_cnr(P_eirp_dB, G_rx_dB, L_fspl, L_atm, L_point, L_freq, P_N_watts)[source]
Compute Carrier-to-Noise Ratio.
P_Rx [dBW] = P_eirp [dBW] + G_rx [dB] - L_fspl [dB] - L_atm [dB] - L_point [dB] - L_freq [dB] CNR = P_Rx / P_N (linear)
- Parameters:
P_eirp_dB – EIRP of transmitter [dBW]
G_rx_dB – Receiver antenna gain [dB]
L_fspl – Free space path loss [dB]
L_atm – Atmospheric loss [dB]
L_point – Pointing loss [dB]
L_freq – Frequency offset loss [dB]
P_N_watts – Noise power [W] (linear)
- Returns:
CNR (linear, dimensionless)
- test_linkBudget.compute_expected_overlap(f1, B1, f2, B2)[source]
Computes overlap bandwidth and overlap center frequency. Overlap region is intersection of [f - B/2, f + B/2] for each.
- test_linkBudget.compute_frequency_loss(B_overlap, B_min)[source]
Compute frequency offset loss.
- Parameters:
B_overlap – Overlapping bandwidth [Hz]
B_min – Smaller of the two bandwidths [Hz]
- Returns:
Frequency loss [dB] (positive or zero)
- test_linkBudget.compute_fspl(distance_m, frequency_Hz)[source]
Compute Free Space Path Loss in dB.
FSPL = 20*log10(4*pi*d/lambda) = 20*log10(4*pi*d*f/c)
- Parameters:
distance_m – Distance between antennas [m]
frequency_Hz – Operating frequency [Hz]
- Returns:
FSPL in [dB]
- test_linkBudget.compute_pointing_loss(theta_az, theta_el, HPBW_az, HPBW_el)[source]
Compute pointing loss for Gaussian beam pattern.
L_point = 10*log10(e)*4*ln(2) * (theta_az^2/HPBW_az^2 + theta_el^2/HPBW_el^2)
- Parameters:
theta_az – Azimuth pointing error [rad]
theta_el – Elevation pointing error [rad]
HPBW_az – Half-power beamwidth in azimuth [rad]
HPBW_el – Half-power beamwidth in elevation [rad]
- Returns:
Pointing loss [dB]
- test_linkBudget.compute_pointing_sigma(from_pos, to_pos)[source]
Compute MRP (sigma) to point antenna boresight (+Z) from from_pos toward to_pos.
The antenna frame convention is that +Z is the boresight direction. This function computes the MRP representing the rotation needed to align the antenna +Z axis with the direction from from_pos to to_pos.
- Parameters:
from_pos – Antenna position [m] (list or array of 3 elements)
to_pos – Target position [m] (list or array of 3 elements)
- Returns:
MRP sigma as list [s1, s2, s3]
- test_linkBudget.compute_spacecraft_position_from_central_angle(Re_m, alt_m, central_angle_rad)[source]
Returns ECI-like position for spacecraft given a ground station at [Re,0,0], with spacecraft on a circle of radius (Re+alt) rotated by central_angle about +Z.
Ground is fixed at +X axis.
- test_linkBudget.create_antenna_msg_payload(name='Antenna', environment=0, state=0, frequency=2200000000.0, bandwidth=5000000.0, directivity_dB=20.0, k=1.0, P_Tx=100.0, eta_r=0.6, T_E=50.0, T_Ambient=150.0, T_sky=5.0, position=[0.0, 0.0, 0.0], sigma=None, velocity=[0, 0, 0], r_AP_N=[0, 0, 0], nHat_LP_N=[0, 0, 1], target_position=None, pointing_error_az_deg=0.0, pointing_error_el_deg=0.0)[source]
Create an AntennaLogMsgPayload with computed derived values.
This allows tests to specify high-level parameters and automatically computes HPBW, P_eirp, P_N, etc.
- Parameters:
name – Antenna name string
environment – ENV_SPACE (0) or ENV_EARTH (1)
state – ANTENNA_OFF/RX/TX/RXTX
frequency – Operating frequency [Hz]
bandwidth – Bandwidth [Hz]
directivity_dB – Antenna directivity [dB]
k – HPBW ratio (az/el), 1.0 for symmetric beam
P_Tx – Transmit power [W]
eta_r – Radiation efficiency [0-1]
T_E – Equivalent noise temperature [K]
T_Ambient – Ambient temperature [K]
T_sky – Sky noise temperature [K]
position – Antenna position in inertial frame [m]
sigma – MRP orientation (overrides target_position if both given)
velocity – Antenna velocity [m/s]
r_AP_N – Position relative to planet (for ground stations) [m]
nHat_LP_N – Surface normal vector (for ground stations)
target_position – If provided, compute sigma to point toward this position
pointing_error_az_deg – Azimuth pointing error [degrees]
pointing_error_el_deg – Elevation pointing error [degrees]
- Returns:
(payload, params) tuple where payload is AntennaLogMsgPayload and params is dict of derived parameters
- test_linkBudget.linkBudgetTestFunction(ant1_state, ant2_state, link_type, distance_km, freq_offset_Hz, pointing_error_deg)[source]
Main test function for parameterized link budget tests.
- test_linkBudget.run_simulation(unitTestSim, duration_sec=1.0)[source]
Initialize and run simulation.
- test_linkBudget.setup_link_budget_sim(ant1_payload, ant2_payload, enable_atm=False)[source]
Set up a simulation with linkBudget module and two antenna messages.
- Parameters:
ant1_payload – AntennaLogMsgPayload for antenna 1
ant2_payload – AntennaLogMsgPayload for antenna 2
enable_atm – Enable atmospheric attenuation calculation
- Returns:
(unitTestSim, linkBudgetModule, linkDataLog)
- test_linkBudget.test_linkBudget(ant1_state, ant2_state, link_type, distance_km, freq_offset_Hz, pointing_error_deg)[source]
Validation Test Description
This unit test validates the link budget calculations between two antennas under various configurations including different antenna states, distances, pointing errors, and link types (space-to-space, space-to-ground).
Test Parameters
- Parameters:
ant1_state – State of antenna 1 (OFF/RX/TX/RXTX)
ant2_state – State of antenna 2 (OFF/RX/TX/RXTX)
link_type – Type of link (“space_space” or “space_ground”)
distance_km – Distance between antennas [km]
freq_offset_Hz – Frequency offset between antennas [Hz]
pointing_error_deg – Pointing error for antenna 1 [degrees]
- test_linkBudget.test_linkBudget_antenna_state_transitions()[source]
Test that CNR values correctly reflect antenna state combinations.
NOTE: CNR is set to 0.0 (not -1.0) when antenna is not in receive mode or when link is invalid, based on the linkValid flag behavior in the code.
- test_linkBudget.test_linkBudget_atmospheric_attenuation_elevation_dependence()[source]
Test that atmospheric attenuation increases as elevation decreases: ~90 deg (overhead) -> moderate elevation -> low elevation. Also checks that values remain finite and non-negative.
- test_linkBudget.test_linkBudget_atmospheric_attenuation_frequency_dependence()[source]
Test that atmospheric attenuation increases with frequency. Higher frequencies experience more atmospheric absorption.
- test_linkBudget.test_linkBudget_atmospheric_attenuation_low_elevation_stability()[source]
Low-elevation stability test to ensure attenuation does not blow up or become NaN/inf. Uses a central angle that produces ~2 deg elevation region.
- test_linkBudget.test_linkBudget_atmospheric_attenuation_space_ground()[source]
Test that atmospheric attenuation is computed for space-to-ground links when enabled.
- test_linkBudget.test_linkBudget_atmospheric_attenuation_space_space()[source]
Test that atmospheric attenuation is NOT computed for space-to-space links even when the flag is enabled.
- test_linkBudget.test_linkBudget_cnr_bookkeeping_with_atmos_pointing_and_freq_loss()[source]
Checks that CNR bookkeeping includes all losses (FSPL, pointing, frequency, atmospheric). Uses module-computed losses, recomputes CNR from TX/RX derived parameters, and compares.
- test_linkBudget.test_linkBudget_cnr_calculation()[source]
Validate CNR calculation against analytical formula.
Sets up a simple link with known parameters and verifies the CNR output matches the expected value.
- test_linkBudget.test_linkBudget_cnr_with_frequency_loss_partial_overlap()[source]
Numeric CNR truth check including frequency overlap loss. Uses partial overlap and computes FSPL at overlap-center frequency.
- test_linkBudget.test_linkBudget_cnr_with_pointing_loss()[source]
Numeric CNR truth check including pointing loss. Uses space-space link with a controlled pointing error.
- test_linkBudget.test_linkBudget_combined_pointing_errors()[source]
Test pointing loss with both azimuth and elevation errors.
- test_linkBudget.test_linkBudget_different_bandwidths()[source]
Test frequency overlap calculation with different bandwidths on each antenna.
- test_linkBudget.test_linkBudget_distance_calculation()[source]
Validate distance calculation between antenna positions.
- test_linkBudget.test_linkBudget_fspl_analytical()[source]
Validate FSPL calculation against analytical formula.
Tests multiple distance/frequency combinations to ensure FSPL = 20*log10(4*pi*d/lambda) is computed correctly.
- test_linkBudget.test_linkBudget_fspl_vs_distance()[source]
Verify FSPL increases by 6 dB when distance doubles (inverse square law).
- test_linkBudget.test_linkBudget_fspl_vs_frequency()[source]
Verify FSPL increases by 6 dB when frequency doubles.
- test_linkBudget.test_linkBudget_high_frequency()[source]
Test behavior at high frequencies (within ITU-R P.676 valid range: 1-1000 GHz).
- test_linkBudget.test_linkBudget_low_frequency()[source]
Test behavior at low frequencies (within ITU-R P.676 valid range: 1-1000 GHz).
- test_linkBudget.test_linkBudget_no_bandwidth_overlap()[source]
Test behavior when antennas have no overlapping bandwidth. CNR should be 0 to indicate link failure.
- test_linkBudget.test_linkBudget_output_message_consistency()[source]
Verify that output message fields are consistent between: - the recorder log arrays (linkDataLog.*) - the most recent output payload read directly Also checks distance / overlap bandwidth / overlap-center frequency consistency.
- test_linkBudget.test_linkBudget_output_message_structure()[source]
Verify all expected fields in the output message are populated.
- test_linkBudget.test_linkBudget_partial_bandwidth_overlap()[source]
Test behavior with partial bandwidth overlap. Should see frequency offset loss.
- test_linkBudget.test_linkBudget_pointing_loss()[source]
Validate pointing loss calculation for various off-axis angles.
- test_linkBudget.test_linkBudget_symmetric_bidirectional()[source]
Test that a bidirectional link (RXTX <-> RXTX) produces symmetric CNR values for identical antennas.