1. 들어가는 글: 텍스트 말고 '그림'으로 보고 싶다
지난 포스팅에서 우리는 파이썬을 이용해 국제우주정거장(ISS)이 언제 서울 상공을 지나가는지, 그 시간표(AOS, TCA, LOS)를 예측해 보았습니다.
[Python 위성] 내일 우주정거장은 언제 보일까? 위성 관측 스케줄 예측 (Pass Prediction)
1. 들어가는 글: "언제 하늘을 봐야 할까?"지난 포스팅에서는 특정 순간에 위성이 보이는지(Visibility)를 판단하는 코드를 짰습니다.https://univ.tistory.com/5 [Python 위성] 내 머리 위를 지나갈까? 위성 가
univ.tistory.com
하지만 "방위각 300도에서 떠서 120도로 진다"라고 숫자로만 보면 감이 잘 오지 않습니다. "그래서 북쪽을 보라는 거야, 서쪽을 보라는 거야?"
이럴 때 필요한 것이 바로 스카이플롯(Skyplot), 혹은 레이더 차트라고 불리는 시각화 방식입니다. 지상 국 안테나가 하늘을 바라보는 시점으로, 위성의 이동 경로를 2차원 원형 차트에 그리는 것입니다.
오늘은 실제 위성 엔지니어들이 가장 많이 보는 화면인 Skyplot을 파이썬 Matplotlib으로 직접 구현해 보겠습니다.
pip install Matplotlib
2. 스카이플롯(Skyplot) 읽는 법
코드를 짜기 전에, 이 동그란 차트를 어떻게 읽는지부터 알아야 합니다.
- 가장자리 (테두리): 지평선(Elevation 0°)을 의미합니다. 위성은 여기서 나타나고 사라집니다.
- 중심 (Bullseye): 천정(Zenith, Elevation 90°), 즉 내 머리 꼭대기를 의미합니다.
- 방향 (Azimuth): 시계 방향으로 북(N, 0°)-동(E, 90°)-남(S, 180°)-서(W, 270°)를 나타냅니다.
즉, 차트의 가장자리에서 시작해 중심 쪽으로 선을 긋고 다시 가장자리로 나가는 선이 바로 위성의 비행 경로입니다.
3. 파이썬 구현: Matplotlib 극좌표계(Polar) 활용
이번 코드의 핵심은 일반적인 (x, y) 그래프가 아니라, (각도, 거리)를 사용하는 극좌표계(projection='polar')를 사용하는 것입니다.
지난번 예측 코드에서 가장 높이 뜨는(최대 고도) 패스 하나를 골라 그려보겠습니다.
import numpy as np
import matplotlib.pyplot as plt
from skyfield.api import load, EarthSatellite, wgs84
# 1. 위성 및 관측소 설정 (서울 기준 ISS)
line1 = '1 25544U 98067A 26008.88709191 .00008359 00000-0 15864-3 0 9991'
line2 = '2 25544 51.6333 8.0698 0007663 356.5554 3.5381 15.49180370547069'
ts = load.timescale()
satellite = EarthSatellite(line1, line2, 'ISS (ZARYA)', ts)
seoul = wgs84.latlon(37.5665, 126.9780)
# 2. 향후 24시간 중 '가장 높이 뜨는' 패스 찾기
t0 = ts.now()
t1 = ts.utc(t0.utc.year, t0.utc.month, t0.utc.day + 1)
times, events = satellite.find_events(seoul, t0, t1, altitude_degrees=10.0)
# 이벤트 목록에서 TCA(이벤트=1)의 고도가 가장 높은 인덱스 찾기
# (간단한 구현을 위해 루프 사용)
best_pass_idx = -1
max_alt = 0
for i in range(len(events)):
if events[i] == 1: # TCA
alt, _, _ = (satellite - seoul).at(times[i]).altaz()
if alt.degrees > max_alt:
max_alt = alt.degrees
best_pass_idx = i
if best_pass_idx == -1:
print("관측 가능한 패스가 없습니다.")
exit()
# 3. 해당 패스의 시작(AOS)부터 끝(LOS)까지 상세 데이터 생성
# best_pass_idx는 TCA이므로, 그 앞이 AOS, 그 뒤가 LOS임
aos_time = times[best_pass_idx - 1]
los_time = times[best_pass_idx + 1]
# AOS~LOS 사이를 촘촘하게 나눔 (초 단위)
duration_sec = int((los_time - aos_time) * 24 * 3600)
t_fine = ts.utc(aos_time.utc.year, aos_time.utc.month, aos_time.utc.day,
aos_time.utc.hour, aos_time.utc.minute,
np.arange(0, duration_sec))
# 위치 계산
diff = satellite - seoul
alt, az, distance = diff.at(t_fine).altaz()
# 4. Skyplot 그리기 (Polar Plot)
fig = plt.figure(figsize=(8, 8))
ax = fig.add_subplot(111, projection='polar')
# (중요) Matplotlib 기본 설정 변경
ax.set_theta_zero_location('N') # 북쪽(N)을 위로 설정
ax.set_theta_direction(-1) # 시계 방향으로 각도 증가
# 고도(Altitude)를 반지름(Radius)으로 변환
# 중심이 90도, 가장자리가 0도가 되도록 반전 (90 - Alt)
r = 90 - alt.degrees
theta = np.radians(az.degrees) # 방위각을 라디안으로 변환
# 궤적 그리기
ax.plot(theta, r, label='Satellite Path', color='blue', linewidth=2)
ax.plot(theta[0], r[0], 'go', label='AOS (Start)') # 시작점
ax.plot(theta[-1], r[-1], 'ro', label='LOS (End)') # 끝점
# 차트 꾸미기
ax.set_rlim(0, 90) # 반지름 범위 0~90
ax.set_yticklabels([]) # 내부 반지름 숫자 숨기기 (깔끔하게)
# 고도 격자 표시 (90, 60, 30도)
ax.set_yticks([0, 30, 60])
ax.set_yticklabels(['90°', '60°', '30°'], color='gray')
plt.title(f"ISS Skyplot (Max Alt: {max_alt:.1f}°)", y=1.08)
plt.legend(loc='lower right')
plt.show()
4. 코드 해설 및 주의할 점
일반 그래프와 달리 극좌표계(Polar)를 다룰 때는 몇 가지 '트릭'이 필요합니다.
① set_theta_zero_location('N') 수학시간에 배운 극좌표는 보통 오른쪽(East, 0도)이 기준입니다. 하지만 지상국에서는 북쪽(North)이 기준이므로, 0도의 위치를 위쪽으로 강제 변경해 주어야 합니다.
② set_theta_direction(-1) 수학에서는 각도가 반시계 방향으로 증가하지만, 방위각(Azimuth)은 시계 방향(북→동→남→서)으로 돌아갑니다. 그래서 방향을 -1로 뒤집어줍니다.
③ r = 90 - alt.degrees (가장 중요 ⭐) 이 부분이 핵심입니다.
- 일반적인 Polar 차트: 중심이 0, 바깥이 큰 숫자.
- Skyplot: 중심이 90도(머리 위), 바깥이 0도(지평선). 따라서 고도 값을 그대로 넣으면 안 되고, [90 - 고도]를 해서 뒤집어줘야 우리가 아는 모양의 차트가 나옵니다.
5. 결과 분석
코드를 실행하면 파란색 선이 원을 가로지르는 그래프가 나옵니다.

- 초록색 점(AOS): 위성이 나타나는 지점입니다. 예를 들어 방위각이 270도(서쪽) 근처라면, 서쪽 하늘에서 위성이 뜬다는 뜻입니다.
- 빨간색 점(LOS): 위성이 사라지는 지점입니다.
- 중심과의 거리: 파란 선이 원의 중심(십자선 교차점)에 가까울수록, 위성이 내 머리 위 높게 지나간다는 뜻입니다. 중심을 관통한다면 정말 보기 드문 '대박 패스'입니다.
📊 이미지로 보는 스카이플롯 용어 해설(skyplot 이해가 어려운 분 들을 위한 추가 설명)
1. 가장자리 (테두리) = 지평선 (Elevation 0°)
- 설명: 차트의 가장 바깥쪽 큰 원은 고도 0도, 즉 지평선을 의미합니다.
- 이미지 적용: 위성 경로의 시작점인 초록색 점(AOS)과 끝점인 빨간색 점(LOS)이 정확히 이 가장자리 테두리 위에 찍혀 있는 것을 볼 수 있습니다. 위성이 지평선에서 나타나고 사라진다는 뜻입니다.
2. 중심 (Bullseye) = 천정 (Zenith, Elevation 90°)
- 설명: 차트의 정중앙 십자선 교차점은 내 머리 꼭대기, 즉 고도 90도를 의미합니다.
- 이미지 적용: 중심에 '90'이라는 숫자가 보입니다. 안쪽으로 들어올수록 30°, 60°, 90°로 고도가 높아집니다.
- 경로 해석: 파란색 경로선이 중심(90°)에 아주 가깝게 지나가는 것을 볼 수 있습니다. 제목에 Max Alt: 84.2°라고 되어 있듯이, 이 패스는 위성이 머리 바로 위까지 올라오는 아주 관측하기 좋은 패스입니다.
3. 방향 (Azimuth)
- 설명: 0°가 북쪽(N)이며, 시계 방향으로 각도가 증가합니다.
- 이미지 적용:
- 시작(AOS, 초록 점): 약 315°와 270° 사이, 대략 북서쪽(NW) 방면 지평선에서 위성이 나타납니다.
- 진행: 파란 선을 따라 점점 고도가 높아지며 머리 위(중심 부근)를 지나갑니다.
- 끝(LOS, 빨간 점): 약 135°와 180° 사이, 대략 남동쪽(SE) 방면 지평선으로 위성이 사라집니다.
[요약] 이 그림은 "국제우주정거장(ISS)이 북서쪽 하늘에서 나타나서, 내 머리 꼭대기 근처를 지나, 남동쪽 하늘로 사라지는 경로"를 보여주고 있습니다.
6. 마무리
이제 여러분은 단순히 "몇 시에 뜬다"를 넘어서, "서쪽 하늘에서 나타나서 머리 위를 지나 동쪽으로 사라진다"라고 구체적인 경로를 시각화할 수 있는 능력을 갖추게 되었습니다.
이것으로 기본적인 파이썬 위성 궤도 분석 시리즈(TLE 해석부터 시각화까지)를 마칩니다. 이 코드들을 잘 조합하면, 나만의 '위성 관제 대시보드'를 웹사이트로 만들거나 앱으로 개발할 수도 있습니다.
다음 시간에는 다시 SMAD 이론으로 돌아가서, 이 모든 위성들이 모여서 지구 전체를 감시하는 시스템인 '위성 성상(Constellation)' 설계에 대해 다뤄보겠습니다. (스타링크가 왜 수천 개의 위성을 쏘는지 알게 되실 겁니다!)
'우주공학 > Python' 카테고리의 다른 글
| [Python 위성] 내가 만드는 위성 카메라 계산기: GSD와 관측 폭(Swath) 자동 계산 (0) | 2026.01.13 |
|---|---|
| [Python 위성] 스타링크/GPS 처럼! 위성 성상(Constellation) 3D 시각화하기 (0) | 2026.01.12 |
| [Python 위성] 내일 우주정거장은 언제 보일까? 위성 관측 스케줄 예측 (Pass Prediction) (3) | 2026.01.09 |
| [Python 위성] 내 머리 위를 지나갈까? 위성 가시성(Visibility) 분석과 최저 고도각 (0) | 2026.01.07 |
| [Python 위성] 지상 궤적(Ground Track) 시각화: 위성 궤도는 왜 물결 모양일까? (0) | 2026.01.06 |