"""Leap-frog prediction algorithm for mechanical lag compensation. The Trav'ler dish has inherent mechanical lag — by the time the motors reach the commanded position, a satellite in motion has already moved on. This module applies a small predictive overshoot so the dish "leaps ahead" of the target, reducing tracking error during a pass. """ def apply_leapfrog( target_az: float, target_el: float, current_az: float, current_el: float, ) -> tuple[float, float]: """Apply predictive overshoot to compensate for mechanical lag. For each axis, if the delta exceeds a threshold, the target is nudged further in the direction of travel. This keeps the dish slightly ahead of fast-moving satellites. Args: target_az: Desired azimuth from tracking software (degrees). target_el: Desired elevation from tracking software (degrees). current_az: Last-known azimuth of the dish (degrees). current_el: Last-known elevation of the dish (degrees). Returns: Adjusted (azimuth, elevation) with overshoot applied. Note: The original upstream code had a copy-paste bug where the elevation delta adjustments modified target_az instead of target_el. See docs/bugs.md for details. """ # Azimuth compensation az_delta = target_az - current_az if abs(az_delta) > 2: target_az += 1.0 if az_delta > 0 else -1.0 elif abs(az_delta) > 1: target_az += 0.5 if az_delta > 0 else -0.5 # Elevation compensation (bug fix: original modified target_az here) el_delta = target_el - current_el if abs(el_delta) > 2: target_el += 1.0 if el_delta > 0 else -1.0 elif abs(el_delta) > 1: target_el += 0.5 if el_delta > 0 else -0.5 return target_az, target_el