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.

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.

test_linkBudget.test_linkBudget_very_long_distance()[source]

Test behavior with very long distances (deep space communication).

test_linkBudget.test_linkBudget_very_short_distance()[source]

Test behavior with very short distances (near-field concerns). Module should still compute valid FSPL.