Source code for opengnc.mission_design.communications

"""
Link budget calculations and RF analysis tools.
"""

import numpy as np

C = 299792458.0






[docs] def calculate_doppler_shift( f_tx_hz: float, r_ecef_rx: np.ndarray, v_ecef_rx: np.ndarray, r_ecef_tx: np.ndarray, v_ecef_tx: np.ndarray, ) -> dict[str, float]: """ Calculate the Doppler shift for a signal sent from transmitter to receiver. Returns ------- dict[str, float] Received frequency and Doppler shift in hertz. """ r_rx = np.asarray(r_ecef_rx, dtype=float) v_rx = np.asarray(v_ecef_rx, dtype=float) r_tx = np.asarray(r_ecef_tx, dtype=float) v_tx = np.asarray(v_ecef_tx, dtype=float) if r_rx.shape != (3,) or v_rx.shape != (3,) or r_tx.shape != (3,) or v_tx.shape != (3,): raise ValueError("Positions and velocities must be vectors of length 3.") r_rel = r_rx - r_tx v_rel_vec = v_rx - v_tx distance = np.linalg.norm(r_rel) if distance == 0: return {"f_rx_hz": f_tx_hz, "doppler_shift_hz": 0.0} range_rate = float(np.dot(r_rel, v_rel_vec) / distance) doppler_shift_hz = -f_tx_hz * (range_rate / C) f_rx_hz = f_tx_hz + doppler_shift_hz return { "f_rx_hz": float(f_rx_hz), "doppler_shift_hz": float(doppler_shift_hz), }
[docs] def calculate_atmospheric_attenuation(elevation_deg: float, frequency_hz: float) -> float: """Calculate atmospheric attenuation using a simplified cosecant model.""" if frequency_hz < 3e9: a_zenith = 0.03 elif frequency_hz < 10e9: a_zenith = 0.05 elif frequency_hz < 18e9: a_zenith = 0.15 else: a_zenith = 0.35 elevation_rad = np.radians(max(elevation_deg, 5.0)) return float(a_zenith / np.sin(elevation_rad))