I am trying to create a program that creates a top-down polar plot of the paths of satellites using 3 points: start azimuth and elevation, maximum azimuth and elevation, and end azimuth and elevation as it passes over the horizon. Similar to this but from a top-down view. Currently, I have been using spherical linear interpolation (SLERP) to create two great arcs from start -> max then max -> end, then connecting them together to create a single arc. However the issue that I'm having is that the arc doesn't look like a normal arc, there is a bump as it approaches the maximum point. The real graph should be smooth, I have a feeling that using the two SLERP lines is causing this bump. Is there a better equation to create a single, smooth great arc using 3 points that I am just missing? import numpy as np import matplotlib.pyplot as plt def spherical_to_cartesian(az_deg, el_deg, radius=1.0): """Convert spherical (azimuth, elevation, radius) to Cartesian coordinates.""" az = np.radians(az_deg) el = np.radians(el_deg) x = radius * np.cos(el) * np.sin(az) y = radius * np.cos(el) * np.cos(az) z = radius * np.sin(el) return np.array([x, y, z]) def slerp(v0, v1, t): """Perform spherical linear interpolation between two vectors.""" v0 = v0 / np.linalg.norm(v0) v1 = v1 / np.linalg.norm(v1) dot = np.clip(np.dot(v0, v1), -1.0, 1.0) omega = np.arccos(dot) if np.isclose(omega, 0): return v0 return (np.sin((1 - t) * omega) * v0 + np.sin(t * omega) * v1) / np.sin(omega) def interpolate_hemisphere_arc(start_az, start_el, mid_az, mid_el, end_az, end_el, samples=50, radius=1.0): """Generate an interpolated arc on the upper hemisphere between three az/el points.""" start = spherical_to_cartesian(start_az, start_el, radius) mid = spherical_to_cartesian(mid_az, mid_el, radius) end = spherical_to_cartesian(end_az, end_el, radius) path_xy = [] # Interpolate start → mid for t in np.linspace(0, 1, samples // 2 + 1): p = slerp(start, mid, t) path_xy.append((p[0], p[1])) # Interpolate mid → end (skip the duplicate mid point) for t in np.linspace(0, 1, samples // 2 + 1)[1:]: p = slerp(mid, end, t) path_xy.append((p[0], p[1])) return path_xy if __name__ == "__main__": # Test case: plot a single interpolated satellite arc path = interpolate_hemisphere_arc( start_az=169.67, start_el=0, mid_az=256.75, mid_el=75.92, end_az=345.34, end_el=0 ) xs, ys = zip(*path) xs = np.array(xs) ys = np.array(ys) r = 90 - 90 * np.sqrt(xs**2 + ys**2) theta = np.arctan2(xs, ys) plt.figure(figsize=(6, 6)) ax = plt.subplot(111, polar=True) ax.plot(theta, r) ax.set_theta_zero_location('N') ax.set_theta_direction(-1) ax.set_title("Top-Down Polar View of Interpolated Satellite Pass") ax.set_rlim(90.0, 0.0) plt.tight_layout() plt.show() Continue reading...