Lunar & Solar

The LunarSolar class computes lunar and solar ephemeris time series for a given location — including positions, lunar illumination fraction, and day/night/twilight flags — using PyEphem.

class ecosound.environment.lunarsolar.LunarSolar(verbose: bool = True)[source]

Bases: object

Class for computing lunar and solar ephemeris at a fixed location.

All quantities are derived geometrically from the observer’s position and time using PyEphem. Atmospheric refraction is disabled (pressure=0) for clean, deterministic altitude values.

Parameters:

verbose – Print progress messages (default: True).

timeseries

Most recent ephemeris time series from get_timeseries(). Dimension: time. Coordinates: time, lat, lon. None until first call.

Type:

xr.Dataset | None

Examples

>>> from ecosound.environment import LunarSolar
>>> ls = LunarSolar()

# Fetch by explicit time range at hourly resolution >>> ds = ls.get_timeseries(lat=42.5, lon=-70.0, … start_dt=”2015-08-01”, end_dt=”2015-08-31”, freq=”1h”) >>> ls.plot_timeseries()

# Match the time axis of another dataset (e.g. HMD 1-minute data) >>> ls.get_timeseries(lat=42.5, lon=-70.0, time_ref=hmd.ds)

# Merge with HMD acoustic data >>> ds_combined = xr.merge([hmd.ds, ls.timeseries])

SYNODIC_PERIOD_DAYS = 29.53059
CIVIL_TWILIGHT_ALT = -6.0
NAUTICAL_TWILIGHT_ALT = -12.0
ASTRONOMICAL_TWILIGHT_ALT = -18.0
get_timeseries(lat: float, lon: float, start_dt: datetime | Timestamp | str | None = None, end_dt: datetime | Timestamp | str | None = None, freq: str = '1h', time_ref: Dataset | None = None) Dataset[source]

Compute lunar and solar ephemeris at a fixed location for a time range.

The time axis can be specified either as a regular grid (start_dt, end_dt, freq) or by passing another xr.Dataset via time_ref, in which case the exact timestamps of that dataset are used (freq is ignored). This allows direct merging without reindexing when working with HMD, NECOFS, or ERA5 datasets.

The result is always stored in self.timeseries and always returned:

ls.get_timeseries(lat, lon, start_dt=”2015-08-01”, end_dt=”2015-08-31”) ds = ls.get_timeseries(lat, lon, time_ref=hmd.ds)

Parameters:
  • lat – Latitude (decimal degrees, WGS84).

  • lon – Longitude (decimal degrees, WGS84, negative west).

  • start_dt – Start of the time range (inclusive). Accepts datetime, pd.Timestamp, or ISO 8601 string. Ignored if time_ref is provided.

  • end_dt – End of the time range (inclusive). Ignored if time_ref is provided.

  • freq – Time step for the regular grid (default “1h”). Any pandas frequency string is accepted (e.g. “6min”, “30min”, “1D”). Ignored when time_ref is provided.

  • time_ref – Optional xr.Dataset whose time coordinate defines the timestamps to compute. When provided, start_dt, end_dt, and freq are ignored.

Returns:

Solar data variables:
  • sun_altitude_deg (time): Solar altitude above horizon (°). Negative = below horizon.

  • sun_azimuth_deg (time): Solar azimuth (°, 0=N, 90=E).

  • is_day (time): Bool — sun altitude > 0°.

  • is_civil_twilight (time): Bool — -6° < sun altitude ≤ 0°.

  • is_nautical_twilight (time): Bool — -12° < sun altitude ≤ -6°.

  • is_night (time): Bool — sun altitude ≤ -12°.

Lunar data variables:
  • moon_altitude_deg (time): Lunar altitude above horizon (°).

  • moon_azimuth_deg (time): Lunar azimuth (°, 0=N, 90=E).

  • moon_illumination_pct (time): Fraction of lunar surface lit (%). 0 = new moon, 100 = full moon.

  • moon_phase (time): Fractional lunar cycle [0, 1). 0 = new moon, 0.25 = first quarter, 0.5 = full moon, 0.75 = last quarter.

  • is_moon_up (time): Bool — moon altitude > 0°.

Coordinates:
  • time : datetime64 UTC

  • lat : observer latitude (scalar)

  • lon : observer longitude (scalar)

Return type:

xr.Dataset with dimension time, also stored in self.timeseries

Raises:
  • ImportError – If PyEphem is not installed.

  • ValueError – If neither time_ref nor both start_dt/end_dt are given.

plot_timeseries(figsize: tuple = (12, 8), display: bool = True, filename: str | None = None) None[source]

Plot the lunar and solar ephemeris stored in self.timeseries.

Produces a figure with three stacked subplots sharing the time axis:
  1. Solar altitude with colour-coded day/twilight/night background

  2. Lunar altitude with above-horizon shading

  3. Lunar illumination (%) with new/full moon markers

Parameters:
  • figsize – Figure size as (width, height) in inches (default: (12, 8)).

  • display – Show the figure on screen (default: True).

  • filename – If provided, save the figure to this path. Default: None.

Raises:

RuntimeError – If get_timeseries() has not been called yet.