0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

天球は平面ではない ― RA方向に cos(Dec) が必要な理由

0
Last updated at Posted at 2026-06-06

はじめに

RA と Dec は天体の位置を表す座標です。

例えば、

  • SS 433

    • RA = 287.96°
    • Dec = +4.98°
  • Cas A

    • RA = 350.86°
    • Dec = +58.81°

のように表されます。

普段は平面上の座標のように扱ってしまいがちですが、RA と Dec は本来「天球上」の座標です。

そのため、

  • RA が 1°変化
  • Dec が 1°変化

は必ずしも同じ距離を意味しません。

今回はその理由を簡単に整理してみます。

地球の緯度・経度と同じ

RA と Dec は、

  • RA → 経度
  • Dec → 緯度

と思うとイメージしやすいです。

地球上でも、

  • 赤道で経度 1°
  • 北緯60°で経度 1°

では距離が違います。

北極に近づくほど経線同士が集まるからです。

天球上でもまったく同じことが起こります。

天球上で見てみる

下図は RA-Dec を球面上に描いたものです。

image.png

コードはこちら
import numpy as np
import matplotlib.pyplot as plt

# ============================================================
# RA-Dec celestial sphere
# ============================================================

def radec_to_xyz(ra_deg, dec_deg):
    """
    Convert RA-Dec coordinates to Cartesian coordinates
    on a unit sphere.

    Parameters
    ----------
    ra_deg : float or array-like
        Right ascension in degrees.
    dec_deg : float or array-like
        Declination in degrees.

    Returns
    -------
    x, y, z : float or array-like
        Cartesian coordinates on the unit sphere.
    """

    ra = np.deg2rad(ra_deg)
    dec = np.deg2rad(dec_deg)

    x = np.cos(dec) * np.cos(ra)
    y = np.cos(dec) * np.sin(ra)
    z = np.sin(dec)

    return x, y, z


# ============================================================
# Sphere surface
# ============================================================

ra_grid = np.linspace(0, 360, 361)
dec_grid = np.linspace(-90, 90, 181)

ra_rad = np.deg2rad(ra_grid)
dec_rad = np.deg2rad(dec_grid)

RA, DEC = np.meshgrid(ra_rad, dec_rad)

X = np.cos(DEC) * np.cos(RA)
Y = np.cos(DEC) * np.sin(RA)
Z = np.sin(DEC)


# ============================================================
# Object positions
# ============================================================

objects = {
    "SS 433": {
        "ra_deg": 287.9565,
        "dec_deg": 4.9827,
        "color": "crimson",
    },
    "Cas A": {
        "ra_deg": 350.8583,
        "dec_deg": 58.8114,
        "color": "tab:purple",
    },
}

for name in objects:
    ra_deg = objects[name]["ra_deg"]
    dec_deg = objects[name]["dec_deg"]
    x, y, z = radec_to_xyz(ra_deg, dec_deg)

    objects[name]["x"] = x
    objects[name]["y"] = y
    objects[name]["z"] = z


# ============================================================
# Figure
# ============================================================

fig = plt.figure(figsize=(8, 8))
ax = fig.add_subplot(111, projection="3d")

# Celestial sphere
ax.plot_surface(
    X, Y, Z,
    color="lightgray",
    alpha=0.10,
    edgecolor="none",
    shade=False,
)


# ============================================================
# Declination lines
# constant Dec: small circles parallel to celestial equator
# ============================================================

for dec_deg in [-60, -30, 0, 30, 60]:
    ra = np.linspace(0, 360, 721)
    dec = np.full_like(ra, dec_deg)

    x, y, z = radec_to_xyz(ra, dec)

    if dec_deg == 0:
        ax.plot(
            x, y, z,
            color="black",
            linewidth=1.8,
            alpha=0.85,
        )
    else:
        ax.plot(
            x, y, z,
            color="gray",
            linewidth=1.0,
            alpha=0.55,
        )

    # Dec label
    x_lab, y_lab, z_lab = radec_to_xyz(10, dec_deg)
    ax.text(
        1.06 * x_lab,
        1.06 * y_lab,
        1.06 * z_lab,
        f"Dec {dec_deg:+d}°",
        fontsize=8,
        color="dimgray",
    )


# ============================================================
# Right ascension lines
# constant RA: great circles through celestial poles
# ============================================================

for ra_deg in np.arange(0, 360, 30):
    dec = np.linspace(-90, 90, 361)
    ra = np.full_like(dec, ra_deg)

    x, y, z = radec_to_xyz(ra, dec)

    ax.plot(
        x, y, z,
        color="gray",
        linewidth=0.8,
        alpha=0.40,
    )

    # RA label on equator
    x_lab, y_lab, z_lab = radec_to_xyz(ra_deg, 0)
    ax.text(
        1.13 * x_lab,
        1.13 * y_lab,
        1.13 * z_lab,
        f"{ra_deg:d}°",
        fontsize=8,
        color="dimgray",
        ha="center",
        va="center",
    )


# ============================================================
# Highlight object positions
# ============================================================

for name, info in objects.items():
    ra_deg = info["ra_deg"]
    dec_deg = info["dec_deg"]
    color = info["color"]

    x0 = info["x"]
    y0 = info["y"]
    z0 = info["z"]

    # Constant Dec line through the object
    ra = np.linspace(0, 360, 721)
    dec = np.full_like(ra, dec_deg)

    x, y, z = radec_to_xyz(ra, dec)

    ax.plot(
        x, y, z,
        color=color,
        linewidth=2.0,
        alpha=0.75,
        label=f"{name}: Dec = {dec_deg:.2f}°",
    )

    # Constant RA line through the object
    dec = np.linspace(-90, 90, 361)
    ra = np.full_like(dec, ra_deg)

    x, y, z = radec_to_xyz(ra, dec)

    ax.plot(
        x, y, z,
        color=color,
        linewidth=1.8,
        alpha=0.75,
        linestyle="--",
        label=f"{name}: RA = {ra_deg:.2f}°",
    )

    # Object marker
    ax.scatter(
        x0, y0, z0,
        s=120,
        color=color,
        edgecolor="black",
        linewidth=0.8,
        zorder=10,
    )

    ax.text(
        1.10 * x0,
        1.10 * y0,
        1.10 * z0,
        name,
        color=color,
        fontsize=12,
        weight="bold",
    )


# ============================================================
# Celestial poles and reference directions
# ============================================================

ax.scatter(0, 0, 1, color="black", s=30)
ax.scatter(0, 0, -1, color="black", s=30)

ax.text(
    0, 0, 1.12,
    "North celestial pole\nDec = +90°",
    ha="center",
    fontsize=9,
)

ax.text(
    0, 0, -1.12,
    "South celestial pole\nDec = -90°",
    ha="center",
    fontsize=9,
)

# RA = 0 direction
ax.quiver(
    0, 0, 0,
    1.05, 0, 0,
    color="black",
    arrow_length_ratio=0.06,
    linewidth=1.2,
)

ax.text(
    1.18, 0, 0,
    "RA = 0°",
    fontsize=10,
    ha="center",
)

ax.text(
    0, 1.18, 0,
    "RA = 90°",
    fontsize=10,
    ha="center",
)


# ============================================================
# Appearance
# ============================================================

ax.set_box_aspect([1, 1, 1])
ax.set_axis_off()

# View angle
ax.view_init(elev=22, azim=35)

ax.legend(
    loc="upper left",
    frameon=False,
    fontsize=8,
)

plt.tight_layout()
plt.show()

コードの実行は Google Colab からもお試しいただけます;
https://colab.research.google.com/drive/17gEJpXyjQ6KxL89m4IJK8AkwqdCDfbue?usp=sharing

赤道に対応する Dec=0° の円が最も大きく、北極に近づくにつれて円が小さくなっていることが分かります。

SS 433 は赤道付近にありますが、Cas A はかなり高い Dec にあります。

そのため Cas A の方が、同じ RA の変化に対する実際の移動距離が短くなります。

なぜ cos(Dec) が出てくるのか

Dec が δ の場所では、その緯度の円の半径は

r = \cos\delta

になります。

つまり、

\rm{RA}方向の距離
=
赤道での距離 × \cos(\rm {Dec})

です。

小さな角度差で考えると、

\Delta s_{\rm RA}
\simeq
\cos\delta \,\Delta\alpha

となります。

SS 433 と Cas A

SS 433 では

  • Dec = +4.98°
  • cos(Dec) ≈ 0.996

です。ほぼ 1 なので、RA方向の縮みはほとんどありません。

一方 Cas A では

  • Dec = +58.81°
  • cos(Dec) ≈ 0.518

です。つまり、Cas A のRAで1°動くというのは実際には約0.52°しか移動しません。

まとめ

RA と Dec は平面座標ではなく、球面上の座標です。

そのため高い Dec では、

\Delta s_{\rm RA}
\simeq
\cos\delta\,\Delta\alpha

となり、RA方向の距離は縮みます。

Cas A のような高 Dec の天体では特に効いてくるので、位置ずれや見かけの運動を扱うときには注意したいところです。

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?