Skip to main content

Observer Module

The Observer module manages observing locations with support for persistent storage, timezone handling, and seamless integration with all position-dependent calculations.

Overview

Your position on Earth fundamentally shapes what you see in the sky. The Observer module provides:

  • Location management with latitude, longitude, and elevation
  • Named observer profiles stored in TOML configuration
  • Timezone support for local time conversions
  • Integration with rise/set, transit, and visibility calculations

Quick Start

CLI Usage

# Add a new observer location
starward observer add "Backyard" 40.7128 -74.0060 --elevation 10 --timezone "America/New_York"

# List saved observers
starward observer list

# Show observer details
starward observer show "Backyard"

# Set default observer
starward observer default "Backyard"

# Remove an observer
starward observer remove "Backyard"

Python API

from starward.core.observer import Observer, ObserverManager

# Create an observer directly
greenwich = Observer.from_degrees(
name="Greenwich",
latitude=51.4772,
longitude=-0.0005,
elevation=62.0,
timezone="Europe/London"
)

# Use in calculations
from starward.core.sun import sunrise, sunset
from starward.core.time import jd_now

jd = jd_now()
rise = sunrise(greenwich, jd)
print(f"Sunrise at {greenwich.name}: {rise.to_datetime()}")

Creating Observers

From Decimal Degrees

# Northern hemisphere, eastern longitude
tokyo = Observer.from_degrees(
name="Tokyo",
latitude=35.6762,
longitude=139.6503,
elevation=40.0,
timezone="Asia/Tokyo"
)

# Southern hemisphere, western longitude
paranal = Observer.from_degrees(
name="Paranal",
latitude=-24.6253,
longitude=-70.4043,
elevation=2635.0,
timezone="America/Santiago"
)

Coordinate Conventions

ParameterRangeConvention
Latitude-90° to +90°+ = North, - = South
Longitude-180° to +180°+ = East, - = West
Elevation≥0 metersAbove sea level

Observer Properties

An Observer object provides:

obs = Observer.from_degrees("Test", 40.0, -74.0, elevation=100.0)

# Access properties
print(obs.name) # "Test"
print(obs.lat_deg) # 40.0
print(obs.lon_deg) # -74.0
print(obs.elevation) # 100.0
print(obs.timezone) # None or timezone string

# As Angle objects (for calculations)
print(obs.latitude) # Angle object
print(obs.longitude) # Angle object

Persistent Storage

Observer Manager

The ObserverManager handles saving and loading observer profiles:

from starward.core.observer import ObserverManager

# Get the manager (creates ~/.starward/ if needed)
manager = ObserverManager()

# Add an observer
obs = Observer.from_degrees("Home", 40.0, -74.0)
manager.add(obs)

# List all observers
for name in manager.list_names():
print(name)

# Get an observer by name
home = manager.get("Home")

# Set default observer
manager.set_default("Home")

# Get default observer
default = manager.get_default()

# Remove an observer
manager.remove("Home")

Configuration File

Observers are stored in ~/.starward/observers.toml:

# Default observer
default = "Home"

[observers.Home]
name = "Home"
latitude = 40.0
longitude = -74.0
elevation = 100.0
timezone = "America/New_York"

[observers.MaunaKea]
name = "Mauna Kea"
latitude = 19.8208
longitude = -155.4681
elevation = 4207.0
timezone = "Pacific/Honolulu"

Well-Known Observatories

Some famous observatory locations:

# Major observatories
mauna_kea = Observer.from_degrees(
"Mauna Kea", 19.8208, -155.4681, 4207.0, "Pacific/Honolulu"
)

paranal = Observer.from_degrees(
"Paranal (VLT)", -24.6253, -70.4043, 2635.0, "America/Santiago"
)

la_palma = Observer.from_degrees(
"Roque de los Muchachos", 28.7569, -17.8925, 2396.0, "Atlantic/Canary"
)

greenwich = Observer.from_degrees(
"Royal Observatory Greenwich", 51.4772, -0.0005, 62.0, "Europe/London"
)

Integration with Other Modules

Sun Module

from starward.core.sun import sunrise, sunset, solar_noon

rise = sunrise(observer, jd)
set_t = sunset(observer, jd)
noon = solar_noon(observer, jd)

Moon Module

from starward.core.moon import moonrise, moonset, moon_altitude

rise = moonrise(observer, jd)
alt = moon_altitude(observer, jd)

Visibility Module

from starward.core.visibility import (
target_altitude, transit_time, compute_visibility
)

alt = target_altitude(target_coord, observer, jd)
transit = transit_time(target_coord, observer, jd)
vis = compute_visibility(target_coord, observer, jd)

Coordinate Transformations

from starward.core.coords import HorizontalCoord

# ICRS to horizontal (requires observer location)
horiz = HorizontalCoord.from_icrs(
icrs_coord,
jd=jd,
lat=observer.latitude,
lon=observer.longitude
)

Elevation Effects

Higher elevation affects:

  1. Horizon: Geometric horizon is depressed below eye level
  2. Refraction: Slightly different atmospheric path
  3. Airmass: Thinner atmosphere means lower airmass at same zenith angle
# Observer at sea level vs mountain
sea_level = Observer.from_degrees("Beach", 40.0, -74.0, elevation=0)
mountain = Observer.from_degrees("Summit", 40.0, -74.0, elevation=3000)

# Rise/set times will differ slightly

Timezone Handling

Timezones use IANA timezone names (e.g., "America/New_York"):

obs = Observer.from_degrees(
"New York",
40.7128, -74.0060,
timezone="America/New_York"
)

# All internal times are UTC/JD
# Use timezone for display purposes

Serialization

Convert to dictionary for storage or transmission:

# To dictionary
d = observer.to_dict()
# {
# 'name': 'Home',
# 'latitude': 40.0,
# 'longitude': -74.0,
# 'elevation': 100.0,
# 'timezone': 'America/New_York'
# }

# From dictionary
obs = Observer.from_dict(d)

CLI Reference

# Add observer
starward observer add NAME LAT LON [--elevation M] [--timezone TZ]

# List observers
starward observer list [--json]

# Show observer
starward observer show NAME [--json]

# Set default
starward observer default NAME

# Remove observer
starward observer remove NAME

See Also