Перевод координат: реализация

Соберём формулы сферической тригонометрии в работающую функцию перевода RA/Dec в высоту/азимут.

Часовой угол (H) — угол между меридианом наблюдателя и объектом, равный звёздному времени минус RA. Он связывает «паспортные» координаты с локальным небом.

Формулы перевода

Чтобы перевести экваториальные координаты (склонение $\delta$, часовой угол $H$) в горизонтальные (высота $h$, азимут $A$) на широте $\varphi$, используют две формулы сферической тригонометрии:

$$\sin h = \sin\delta \sin\varphi + \cos\delta \cos\varphi \cos H$$

$$\cos A = \frac{\sin\delta - \sin h \sin\varphi}{\cos h \cos\varphi}$$

Первая даёт высоту напрямую через $\arcsin$. Вторая даёт косинус азимута; чтобы снять неоднозначность арккосинуса (он не различает восток и запад), смотрят на знак $\sin H$: если объект на западной стороне ($\sin H \gt 0$), азимут берут как $360° - A$.

Реализация

import math

def eq_to_horiz(ha_deg, dec_deg, lat_deg):
    """Часовой угол и склонение -> (высота, азимут) в градусах."""
    H = math.radians(ha_deg)
    d = math.radians(dec_deg)
    phi = math.radians(lat_deg)

    sin_alt = math.sin(d) * math.sin(phi) + math.cos(d) * math.cos(phi) * math.cos(H)
    alt = math.asin(sin_alt)

    cos_A = (math.sin(d) - math.sin(alt) * math.sin(phi)) / (math.cos(alt) * math.cos(phi))
    cos_A = max(-1.0, min(1.0, cos_A))  # защита от ошибок округления
    A = math.acos(cos_A)
    if math.sin(H) > 0:
        A = 2 * math.pi - A

    return math.degrees(alt), math.degrees(A)

# Объект: часовой угол 15°, склонение 20°, широта наблюдателя 55°
alt, az = eq_to_horiz(15.0, 20.0, 55.0)
print("Высота:", round(alt, 2), "град")
print("Азимут:", round(az, 2), "град")

Вывод:

Высота: 53.21 град
Азимут: 203.96 град

Как работает под капотом

Эти формулы — частный случай сферической теоремы косинусов, применённой к «астрономическому треугольнику»: его вершины — полюс мира, зенит и объект. Стороны треугольника — это $90° - \delta$, $90° - \varphi$ и $90° - h$, а углы — часовой угол $H$ и азимут $A$. Решая этот треугольник, мы и получаем перевод. Строчка cos_A = max(-1.0, min(1.0, cos_A)) — практический приём: из-за ошибок округления косинус может получиться чуть больше $1$ или меньше $-1$, и тогда math.acos упадёт. Зажимаем значение в допустимый диапазон.

Частые ошибки

  • Подставлять градусы в math.sin без перевода в радианы.
  • Игнорировать неоднозначность азимута — без проверки $\sin H$ восток перепутается с западом.
  • Не защитить acos от значений за пределами $[-1, 1]$ — программа упадёт на крайних случаях.

Итог

  • Перевод координат — это решение астрономического треугольника через $\sin$/$\cos$.
  • Высота берётся через $\arcsin$, азимут — через $\arccos$ плюс проверка знака $\sin H$.
  • Зажимайте аргумент acos в $[-1, 1]$, чтобы не словить ошибку округления.
Проверьте себя
1. Какая формула даёт высоту объекта?
Asin h = sin δ sin φ + cos δ cos φ cos H
Bh = δ + φ
Ch = 90 - H
Dcos h = sin δ
2. Зачем в коде стоит cos_A = max(-1.0, min(1.0, cos_A))?
AЧтобы ускорить расчёт
BЧтобы из-за округления значение не вышло за [-1,1] и acos не упал
CЧтобы перевести в радианы
DЭто бесполезная строка
3. Как снимают неоднозначность азимута, который даёт arccos?
AБерут модуль
BПроверяют знак sin(H): если положителен, A = 360° - A
CДелят на 2
DОкругляют до целого