style: fix prettier table formatting in wiki

This commit is contained in:
Aric Camarata 2026-03-08 17:30:54 -04:00
parent 0bf9e6eb16
commit b032fb596f
10 changed files with 184 additions and 170 deletions

View file

@ -14,10 +14,10 @@ async function initKernels(config?: KernelConfig): Promise<void>
```ts ```ts
interface KernelConfig { interface KernelConfig {
planetary?: KernelSource // DE442S source. Default: auto-download planetary?: KernelSource // DE442S source. Default: auto-download
leapSeconds?: KernelSource // LSK source. Default: auto-download leapSeconds?: KernelSource // LSK source. Default: auto-download
cacheDir?: string // Cache dir. Default: ~/.cache/moon-sighting cacheDir?: string // Cache dir. Default: ~/.cache/moon-sighting
checksumOverride?: string // SHA-256 override for de442s.bsp checksumOverride?: string // SHA-256 override for de442s.bsp
} }
type KernelSource = type KernelSource =
@ -45,13 +45,13 @@ async function getMoonSightingReport(
```ts ```ts
interface Observer { interface Observer {
lat: number // Geodetic latitude, degrees (north positive) lat: number // Geodetic latitude, degrees (north positive)
lon: number // Longitude, degrees (east positive) lon: number // Longitude, degrees (east positive)
elevation: number // Height above WGS84 ellipsoid, meters elevation: number // Height above WGS84 ellipsoid, meters
name?: string // Optional label name?: string // Optional label
deltaT?: number // Override TT - UT1, seconds deltaT?: number // Override TT - UT1, seconds
ut1utc?: number // Override UT1 - UTC, seconds (takes precedence over deltaT) ut1utc?: number // Override UT1 - UTC, seconds (takes precedence over deltaT)
pressure?: number // Atmospheric pressure, mbar (default 1013.25) pressure?: number // Atmospheric pressure, mbar (default 1013.25)
temperature?: number // Temperature, Celsius (default 15) temperature?: number // Temperature, Celsius (default 15)
} }
``` ```
@ -61,7 +61,7 @@ interface Observer {
```ts ```ts
interface SightingOptions { interface SightingOptions {
kernels?: KernelConfig kernels?: KernelConfig
bestTimeMethod?: 'heuristic' | 'optimized' // default: 'heuristic' bestTimeMethod?: 'heuristic' | 'optimized' // default: 'heuristic'
} }
``` ```
@ -75,15 +75,15 @@ interface MoonSightingReport {
// Event times // Event times
sunsetUTC: Date | null sunsetUTC: Date | null
moonsetUTC: Date | null moonsetUTC: Date | null
lagMinutes: number | null // moonset - sunset, minutes lagMinutes: number | null // moonset - sunset, minutes
bestTimeUTC: Date | null // T_sunset + 4/9 × lag bestTimeUTC: Date | null // T_sunset + 4/9 × lag
bestTimeWindowUTC: [Date, Date] | null // ±20 min around best time bestTimeWindowUTC: [Date, Date] | null // ±20 min around best time
// Body positions at best time // Body positions at best time
moonPosition: AzAlt | null // { azimuth, altitude } moonPosition: AzAlt | null // { azimuth, altitude }
sunPosition: AzAlt | null sunPosition: AzAlt | null
illumination: number | null // percent, 0100 illumination: number | null // percent, 0100
moonAge: number | null // hours since conjunction moonAge: number | null // hours since conjunction
// Crescent geometry at best time // Crescent geometry at best time
geometry: CrescentGeometry | null geometry: CrescentGeometry | null
@ -119,20 +119,20 @@ function getMoonPosition(
**Parameters:** **Parameters:**
| Parameter | Type | Description | | Parameter | Type | Description |
| --------- | ---- | ----------- | | ----------- | --------- | ------------------------------------------- |
| `date` | `Date?` | Date to evaluate. Defaults to now | | `date` | `Date?` | Date to evaluate. Defaults to now |
| `lat` | `number` | Geodetic latitude, degrees (north positive) | | `lat` | `number` | Geodetic latitude, degrees (north positive) |
| `lon` | `number` | Longitude, degrees (east positive) | | `lon` | `number` | Longitude, degrees (east positive) |
| `elevation` | `number?` | Height above ellipsoid, meters. Default: 0 | | `elevation` | `number?` | Height above ellipsoid, meters. Default: 0 |
**MoonPosition:** **MoonPosition:**
```ts ```ts
interface MoonPosition { interface MoonPosition {
azimuth: number // Degrees from North, clockwise (0360) azimuth: number // Degrees from North, clockwise (0360)
altitude: number // Apparent altitude, degrees (refraction applied) altitude: number // Apparent altitude, degrees (refraction applied)
distance: number // Earth center to Moon center, km distance: number // Earth center to Moon center, km
parallacticAngle: number // Angle between zenith and north pole as seen from Moon, radians parallacticAngle: number // Angle between zenith and north pole as seen from Moon, radians
} }
``` ```
@ -143,9 +143,9 @@ interface MoonPosition {
import { getMoonPosition } from 'moon-sighting' import { getMoonPosition } from 'moon-sighting'
const pos = getMoonPosition(new Date(), 51.5074, -0.1278, 10) const pos = getMoonPosition(new Date(), 51.5074, -0.1278, 10)
console.log(pos.azimuth) // 214.7 console.log(pos.azimuth) // 214.7
console.log(pos.altitude) // 38.2 console.log(pos.altitude) // 38.2
console.log(pos.distance) // 384400 console.log(pos.distance) // 384400
``` ```
--- ---
@ -160,18 +160,18 @@ function getMoonIllumination(date?: Date): MoonIlluminationResult
**Parameters:** **Parameters:**
| Parameter | Type | Description | | Parameter | Type | Description |
| --------- | ---- | ----------- | | --------- | ------- | --------------------------------- |
| `date` | `Date?` | Date to evaluate. Defaults to now | | `date` | `Date?` | Date to evaluate. Defaults to now |
**MoonIlluminationResult:** **MoonIlluminationResult:**
```ts ```ts
interface MoonIlluminationResult { interface MoonIlluminationResult {
fraction: number // Illuminated fraction, 0 (new moon) to 1 (full moon) fraction: number // Illuminated fraction, 0 (new moon) to 1 (full moon)
phase: number // Position in 01 cycle: 0=new, 0.25=first quarter, 0.5=full, 0.75=last quarter phase: number // Position in 01 cycle: 0=new, 0.25=first quarter, 0.5=full, 0.75=last quarter
angle: number // Position angle of bright limb midpoint, eastward from north, radians angle: number // Position angle of bright limb midpoint, eastward from north, radians
isWaxing: boolean // True when elongation is increasing (new moon toward full moon) isWaxing: boolean // True when elongation is increasing (new moon toward full moon)
} }
``` ```
@ -181,9 +181,9 @@ interface MoonIlluminationResult {
import { getMoonIllumination } from 'moon-sighting' import { getMoonIllumination } from 'moon-sighting'
const illum = getMoonIllumination() const illum = getMoonIllumination()
console.log(illum.fraction) // 0.143 console.log(illum.fraction) // 0.143
console.log(illum.phase) // 0.09 console.log(illum.phase) // 0.09
console.log(illum.isWaxing) // true console.log(illum.isWaxing) // true
``` ```
--- ---
@ -200,12 +200,12 @@ function getMoonPhase(date?: Date): MoonPhaseResult
```ts ```ts
interface MoonPhaseResult { interface MoonPhaseResult {
phase: MoonPhaseName // 'new-moon' | 'waxing-crescent' | ... | 'waning-crescent' phase: MoonPhaseName // 'new-moon' | 'waxing-crescent' | ... | 'waning-crescent'
phaseName: string // Display name, e.g. 'Waxing Crescent' phaseName: string // Display name, e.g. 'Waxing Crescent'
phaseSymbol: string // Moon emoji, e.g. '🌒' phaseSymbol: string // Moon emoji, e.g. '🌒'
illumination: number // 0100 percent illumination: number // 0100 percent
age: number // hours since last new moon age: number // hours since last new moon
elongationDeg: number // Moon - Sun ecliptic longitude, [0, 360) elongationDeg: number // Moon - Sun ecliptic longitude, [0, 360)
isWaxing: boolean isWaxing: boolean
nextNewMoon: Date nextNewMoon: Date
nextFullMoon: Date nextFullMoon: Date
@ -232,27 +232,27 @@ function getMoonVisibilityEstimate(
**Parameters:** **Parameters:**
| Parameter | Type | Description | | Parameter | Type | Description |
| --------- | ---- | ----------- | | ----------- | --------- | -------------------------------------------------------------------------------- |
| `date` | `Date?` | Observation time. Defaults to now. Use a post-sunset time for meaningful results | | `date` | `Date?` | Observation time. Defaults to now. Use a post-sunset time for meaningful results |
| `lat` | `number` | Geodetic latitude, degrees (north positive) | | `lat` | `number` | Geodetic latitude, degrees (north positive) |
| `lon` | `number` | Longitude, degrees (east positive) | | `lon` | `number` | Longitude, degrees (east positive) |
| `elevation` | `number?` | Height above ellipsoid, meters. Default: 0 | | `elevation` | `number?` | Height above ellipsoid, meters. Default: 0 |
**MoonVisibilityEstimate:** **MoonVisibilityEstimate:**
```ts ```ts
interface MoonVisibilityEstimate { interface MoonVisibilityEstimate {
V: number // Odeh V parameter: V = ARCV - f(W). Positive = crescent exceeds threshold V: number // Odeh V parameter: V = ARCV - f(W). Positive = crescent exceeds threshold
zone: OdehZone // 'A' | 'B' | 'C' | 'D' zone: OdehZone // 'A' | 'B' | 'C' | 'D'
description: string // Human-readable zone description description: string // Human-readable zone description
isVisibleNakedEye: boolean // True for zone A isVisibleNakedEye: boolean // True for zone A
isVisibleWithOpticalAid: boolean // True for zones A and B isVisibleWithOpticalAid: boolean // True for zones A and B
ARCL: number // Arc of light (elongation), degrees ARCL: number // Arc of light (elongation), degrees
ARCV: number // Arc of vision (Moon alt - Sun alt, airless), degrees ARCV: number // Arc of vision (Moon alt - Sun alt, airless), degrees
W: number // Topocentric crescent width, arc minutes W: number // Topocentric crescent width, arc minutes
moonAboveHorizon: boolean // True when Moon is above the horizon at the given time moonAboveHorizon: boolean // True when Moon is above the horizon at the given time
isApproximate: true // Always true: Meeus approximation, not DE442S isApproximate: true // Always true: Meeus approximation, not DE442S
} }
``` ```
@ -263,9 +263,9 @@ import { getMoonVisibilityEstimate } from 'moon-sighting'
// ~40 min after sunset in Mecca, day after new moon // ~40 min after sunset in Mecca, day after new moon
const est = getMoonVisibilityEstimate(new Date('2025-03-02T15:30:00Z'), 21.42, 39.83) const est = getMoonVisibilityEstimate(new Date('2025-03-02T15:30:00Z'), 21.42, 39.83)
console.log(est.zone) // 'A' through 'D' console.log(est.zone) // 'A' through 'D'
console.log(est.V) // Odeh V parameter console.log(est.V) // Odeh V parameter
console.log(est.isVisibleNakedEye) // true/false console.log(est.isVisibleNakedEye) // true/false
``` ```
--- ---
@ -275,22 +275,17 @@ console.log(est.isVisibleNakedEye) // true/false
Combined kernel-free snapshot: phase, position, illumination, and visibility estimate in one call. Combined kernel-free snapshot: phase, position, illumination, and visibility estimate in one call.
```ts ```ts
function getMoon( function getMoon(date?: Date, lat: number, lon: number, elevation?: number): MoonSnapshot
date?: Date,
lat: number,
lon: number,
elevation?: number,
): MoonSnapshot
``` ```
**MoonSnapshot:** **MoonSnapshot:**
```ts ```ts
interface MoonSnapshot { interface MoonSnapshot {
phase: MoonPhaseResult // getMoonPhase() result phase: MoonPhaseResult // getMoonPhase() result
position: MoonPosition // getMoonPosition() result position: MoonPosition // getMoonPosition() result
illumination: MoonIlluminationResult // getMoonIllumination() result illumination: MoonIlluminationResult // getMoonIllumination() result
visibility: MoonVisibilityEstimate // getMoonVisibilityEstimate() result visibility: MoonVisibilityEstimate // getMoonVisibilityEstimate() result
} }
``` ```
@ -300,11 +295,11 @@ interface MoonSnapshot {
import { getMoon } from 'moon-sighting' import { getMoon } from 'moon-sighting'
const moon = getMoon(new Date(), 51.5074, -0.1278, 10) const moon = getMoon(new Date(), 51.5074, -0.1278, 10)
console.log(moon.phase.phaseName) // 'Waxing Crescent' console.log(moon.phase.phaseName) // 'Waxing Crescent'
console.log(moon.phase.phaseSymbol) // '🌒' console.log(moon.phase.phaseSymbol) // '🌒'
console.log(moon.position.altitude) // degrees above horizon console.log(moon.position.altitude) // degrees above horizon
console.log(moon.illumination.fraction) // 0.0 to 1.0 console.log(moon.illumination.fraction) // 0.0 to 1.0
console.log(moon.visibility.zone) // 'A' through 'D' console.log(moon.visibility.zone) // 'A' through 'D'
``` ```
--- ---
@ -329,8 +324,8 @@ interface SunMoonEvents {
moonsetUTC: Date | null moonsetUTC: Date | null
sunriseUTC: Date | null sunriseUTC: Date | null
moonriseUTC: Date | null moonriseUTC: Date | null
civilTwilightEndUTC: Date | null // Sun at -6° civilTwilightEndUTC: Date | null // Sun at -6°
nauticalTwilightEndUTC: Date | null // Sun at -12° nauticalTwilightEndUTC: Date | null // Sun at -12°
astronomicalTwilightEndUTC: Date | null // Sun at -18° astronomicalTwilightEndUTC: Date | null // Sun at -18°
} }
``` ```
@ -369,11 +364,11 @@ async function verifyKernels(config?: KernelConfig): Promise<{
```ts ```ts
interface CrescentGeometry { interface CrescentGeometry {
ARCL: number // Elongation (Sun-Moon angular separation), degrees ARCL: number // Elongation (Sun-Moon angular separation), degrees
ARCV: number // Moon altitude - Sun altitude (airless), degrees ARCV: number // Moon altitude - Sun altitude (airless), degrees
DAZ: number // Sun azimuth - Moon azimuth, [-180, 180], degrees DAZ: number // Sun azimuth - Moon azimuth, [-180, 180], degrees
W: number // Topocentric crescent width, arc minutes W: number // Topocentric crescent width, arc minutes
lag: number // Moonset - sunset, minutes lag: number // Moonset - sunset, minutes
} }
``` ```
@ -381,13 +376,13 @@ interface CrescentGeometry {
```ts ```ts
interface YallopResult { interface YallopResult {
q: number // Continuous q parameter q: number // Continuous q parameter
category: YallopCategory // 'A' | 'B' | 'C' | 'D' | 'E' | 'F' category: YallopCategory // 'A' | 'B' | 'C' | 'D' | 'E' | 'F'
description: string description: string
isVisibleNakedEye: boolean // A or B isVisibleNakedEye: boolean // A or B
requiresOpticalAid: boolean // C or D requiresOpticalAid: boolean // C or D
isBelowDanjonLimit: boolean // F isBelowDanjonLimit: boolean // F
Wprime: number // W' used in q formula, arc minutes Wprime: number // W' used in q formula, arc minutes
} }
``` ```
@ -395,10 +390,10 @@ interface YallopResult {
```ts ```ts
interface OdehResult { interface OdehResult {
V: number // Continuous V parameter V: number // Continuous V parameter
zone: OdehZone // 'A' | 'B' | 'C' | 'D' zone: OdehZone // 'A' | 'B' | 'C' | 'D'
description: string description: string
isVisibleNakedEye: boolean // A isVisibleNakedEye: boolean // A
isVisibleWithOpticalAid: boolean // A or B isVisibleWithOpticalAid: boolean // A or B
} }
``` ```
@ -415,8 +410,8 @@ See the `getMoon` section above for the full definition.
```ts ```ts
interface AzAlt { interface AzAlt {
azimuth: number // Degrees from North, clockwise (0360) azimuth: number // Degrees from North, clockwise (0360)
altitude: number // Degrees above horizon (negative = below) altitude: number // Degrees above horizon (negative = below)
} }
``` ```
@ -425,13 +420,13 @@ interface AzAlt {
## Constants ## Constants
```ts ```ts
YALLOP_THRESHOLDS // { A: 0.216, B: -0.014, C: -0.160, D: -0.232, E: -0.293 } YALLOP_THRESHOLDS // { A: 0.216, B: -0.014, C: -0.160, D: -0.232, E: -0.293 }
ODEH_THRESHOLDS // { A: 5.65, B: 2.00, C: -0.96 } ODEH_THRESHOLDS // { A: 5.65, B: 2.00, C: -0.96 }
WGS84 // { a: 6378137.0, invF: 298.257223563, f, b, e2 } WGS84 // { a: 6378137.0, invF: 298.257223563, f, b, e2 }
YALLOP_DESCRIPTIONS // Record<YallopCategory, string> YALLOP_DESCRIPTIONS // Record<YallopCategory, string>
ODEH_DESCRIPTIONS // Record<OdehZone, string> ODEH_DESCRIPTIONS // Record<OdehZone, string>
``` ```
--- ---
*Previous: [Home](Home) | Next: [Architecture](Architecture)* _Previous: [Home](Home) | Next: [Architecture](Architecture)_

View file

@ -123,17 +123,17 @@ Target: a full sighting report (sunset + moonset + best-time geometry + Yallop +
A crescent sighting report's accuracy is limited by the worst source in the chain: A crescent sighting report's accuracy is limited by the worst source in the chain:
| Source | Contribution | | Source | Contribution |
| ------ | ------------ | | -------------------------------------------------- | --------------------------------------- |
| DE442S position error | < 1 km (~0.001 arcsec at Moon distance) | | DE442S position error | < 1 km (~0.001 arcsec at Moon distance) |
| IERS Q·R·W transform (with user-supplied EOP) | < 1 mas | | IERS Q·R·W transform (with user-supplied EOP) | < 1 mas |
| IERS Q·R·W transform (polynomial ΔT approximation) | < 5 arcsec | | IERS Q·R·W transform (polynomial ΔT approximation) | < 5 arcsec |
| WGS84 observer position | < 1 m (negligible in angle) | | WGS84 observer position | < 1 m (negligible in angle) |
| Bennett refraction (standard atmosphere) | < 1 arcmin for alt > 5° | | Bennett refraction (standard atmosphere) | < 1 arcmin for alt > |
| Bennett refraction (non-standard conditions) | up to 15 arcmin near horizon | | Bennett refraction (non-standard conditions) | up to 15 arcmin near horizon |
In practice, refraction uncertainty dominates all other error sources for crescent sighting near the horizon. In practice, refraction uncertainty dominates all other error sources for crescent sighting near the horizon.
--- ---
*Previous: [API Reference](API-Reference) | Next: [Crescent Visibility](Crescent-Visibility)* _Previous: [API Reference](API-Reference) | Next: [Crescent Visibility](Crescent-Visibility)_

View file

@ -48,14 +48,14 @@ This polynomial represents the minimum ARCV observed in historical crescent sigh
### Categories ### Categories
| Category | q range | Meaning | | Category | q range | Meaning |
| -------- | ------- | ------- | | -------- | ---------- | -------------------------------------------------- |
| A | q > +0.216 | Easily visible to the naked eye | | A | q > +0.216 | Easily visible to the naked eye |
| B | q > 0.014 | Visible under perfect conditions | | B | q > 0.014 | Visible under perfect conditions |
| C | q > 0.160 | May need optical aid to locate; naked eye possible | | C | q > 0.160 | May need optical aid to locate; naked eye possible |
| D | q > 0.232 | Optical aid necessary; naked eye not possible | | D | q > 0.232 | Optical aid necessary; naked eye not possible |
| E | q > 0.293 | Not visible even with telescope | | E | q > 0.293 | Not visible even with telescope |
| F | q ≤ 0.293 | Below Danjon limit; crescent cannot form | | F | q ≤ 0.293 | Below Danjon limit; crescent cannot form |
Category F corresponds to ARCL below roughly 7° (the Danjon limit), where the Moon is geometrically too close to the Sun for the crescent arc to sustain itself. Category F corresponds to ARCL below roughly 7° (the Danjon limit), where the Moon is geometrically too close to the Sun for the crescent arc to sustain itself.
@ -87,12 +87,12 @@ V = ARCV - (11.8371 - 6.3226·W + 0.7319·W² - 0.1018·W³)
### Zones ### Zones
| Zone | V range | Meaning | | Zone | V range | Meaning |
| ---- | ------- | ------- | | ---- | --------- | --------------------------------------------------------------------- |
| A | V ≥ 5.65 | Visible with naked eye | | A | V ≥ 5.65 | Visible with naked eye |
| B | V ≥ 2.00 | Visible with optical aid; may be naked eye under excellent conditions | | B | V ≥ 2.00 | Visible with optical aid; may be naked eye under excellent conditions |
| C | V ≥ 0.96 | Visible with optical aid only | | C | V ≥ 0.96 | Visible with optical aid only |
| D | V < 0.96 | Not visible even with optical aid | | D | V < 0.96 | Not visible even with optical aid |
### Key differences from Yallop ### Key differences from Yallop
@ -146,4 +146,4 @@ This approach requires additional atmospheric inputs (aerosol optical depth, hum
--- ---
*Previous: [Architecture](Architecture) | Next: [Ephemeris](Ephemeris)* _Previous: [Architecture](Architecture) | Next: [Ephemeris](Ephemeris)_

View file

@ -60,6 +60,7 @@ Each record covers a fixed time interval and stores coefficients for X, Y, Z:
``` ```
The polynomial degree n is derived from RSIZE (record size in doubles): The polynomial degree n is derived from RSIZE (record size in doubles):
``` ```
n = (RSIZE - 2) / 3 - 1 n = (RSIZE - 2) / 3 - 1
``` ```
@ -93,6 +94,7 @@ result = c_0 + x·b_1 - b_2
This produces the position. Velocity requires the derivative d(result)/dt, computed via the Chebyshev derivative recurrence, not by finite differencing, which would lose accuracy. This produces the position. Velocity requires the derivative d(result)/dt, computed via the Chebyshev derivative recurrence, not by finite differencing, which would lose accuracy.
Transforming from normalized domain back to physical time: Transforming from normalized domain back to physical time:
``` ```
x = (et - MID) / RADIUS x = (et - MID) / RADIUS
dx/dt = 1/RADIUS dx/dt = 1/RADIUS
@ -152,4 +154,4 @@ See [Validation](Validation) for the test methodology.
--- ---
*Previous: [Crescent Visibility](Crescent-Visibility) | Next: [Time Scales](Time-Scales)* _Previous: [Crescent Visibility](Crescent-Visibility) | Next: [Time Scales](Time-Scales)_

View file

@ -55,17 +55,17 @@ import { initKernels, getMoonSightingReport } from 'moon-sighting'
await initKernels() await initKernels()
const observer = { const observer = {
lat: 51.5074, // London lat: 51.5074, // London
lon: -0.1278, lon: -0.1278,
elevation: 10, // meters above WGS84 ellipsoid elevation: 10, // meters above WGS84 ellipsoid
name: 'London, UK', name: 'London, UK',
} }
const report = await getMoonSightingReport(new Date('2025-03-29'), observer) const report = await getMoonSightingReport(new Date('2025-03-29'), observer)
// Summary // Summary
console.log(report.yallop.category) // 'A' through 'F' console.log(report.yallop.category) // 'A' through 'F'
console.log(report.odeh.zone) // 'A' through 'D' console.log(report.odeh.zone) // 'A' through 'D'
console.log(report.guidance) console.log(report.guidance)
// Event times // Event times
@ -92,26 +92,26 @@ import { getMoonPhase, getMoonPosition, getMoonIllumination } from 'moon-sightin
// Phase name, illumination percent, and next new/full moon dates // Phase name, illumination percent, and next new/full moon dates
const phase = getMoonPhase() const phase = getMoonPhase()
console.log(phase.phase) // 'waxing-crescent' console.log(phase.phase) // 'waxing-crescent'
console.log(phase.illumination) // 23.4 console.log(phase.illumination) // 23.4
console.log(phase.age) // 4.2 (hours since last new moon) console.log(phase.age) // 4.2 (hours since last new moon)
console.log(phase.nextFullMoon) // Date console.log(phase.nextFullMoon) // Date
// Topocentric position: azimuth, altitude (refraction applied), distance // Topocentric position: azimuth, altitude (refraction applied), distance
// Accuracy: ~0.3° // Accuracy: ~0.3°
const pos = getMoonPosition(new Date(), 51.5074, -0.1278, 10) const pos = getMoonPosition(new Date(), 51.5074, -0.1278, 10)
console.log(pos.azimuth) // degrees from North, clockwise console.log(pos.azimuth) // degrees from North, clockwise
console.log(pos.altitude) // degrees above horizon console.log(pos.altitude) // degrees above horizon
console.log(pos.distance) // km from Earth center to Moon center console.log(pos.distance) // km from Earth center to Moon center
console.log(pos.parallacticAngle) // radians console.log(pos.parallacticAngle) // radians
// Illumination fraction and phase cycle position // Illumination fraction and phase cycle position
// Accuracy: ~0.5% on fraction // Accuracy: ~0.5% on fraction
const illum = getMoonIllumination() const illum = getMoonIllumination()
console.log(illum.fraction) // 01 (0=new, 1=full) console.log(illum.fraction) // 01 (0=new, 1=full)
console.log(illum.phase) // 01 cycle position (0=new, 0.5=full) console.log(illum.phase) // 01 cycle position (0=new, 0.5=full)
console.log(illum.angle) // bright limb position angle, radians console.log(illum.angle) // bright limb position angle, radians
console.log(illum.isWaxing) // true when moving toward full moon console.log(illum.isWaxing) // true when moving toward full moon
// All three accept an optional Date for historical or future queries // All three accept an optional Date for historical or future queries
const past = getMoonPhase(new Date('2024-01-01')) const past = getMoonPhase(new Date('2024-01-01'))
@ -127,7 +127,10 @@ import { initKernels, getSunMoonEvents } from 'moon-sighting'
await initKernels() await initKernels()
const events = await getSunMoonEvents(new Date('2025-03-29'), { const events = await getSunMoonEvents(new Date('2025-03-29'), {
lat: 21.4225, lon: 39.8262, elevation: 300, name: 'Mecca' lat: 21.4225,
lon: 39.8262,
elevation: 300,
name: 'Mecca',
}) })
console.log(events.sunsetUTC) console.log(events.sunsetUTC)
@ -173,7 +176,7 @@ await initKernels({
// IERS Bulletin A value for UT1-UTC (current, as of 2025-03) // IERS Bulletin A value for UT1-UTC (current, as of 2025-03)
await getMoonSightingReport(date, { await getMoonSightingReport(date, {
...observer, ...observer,
ut1utc: 0.0341, // seconds, from IERS Bulletin A ut1utc: 0.0341, // seconds, from IERS Bulletin A
}) })
``` ```
@ -202,4 +205,4 @@ npx moon-sighting benchmark
--- ---
*Previous: [Home](Home) | Next: [API Reference](API-Reference)* _Previous: [Home](Home) | Next: [API Reference](API-Reference)_

View file

@ -38,10 +38,12 @@ import { initKernels, getMoonSightingReport } from 'moon-sighting'
await initKernels() await initKernels()
const report = await getMoonSightingReport(new Date('2025-03-29'), { const report = await getMoonSightingReport(new Date('2025-03-29'), {
lat: 51.5074, lon: -0.1278, elevation: 10 lat: 51.5074,
lon: -0.1278,
elevation: 10,
}) })
console.log(report.yallop.category) // 'A' console.log(report.yallop.category) // 'A'
console.log(report.guidance) console.log(report.guidance)
``` ```

View file

@ -5,6 +5,7 @@
The library uses the WGS84 (World Geodetic System 1984) reference ellipsoid, which is the standard for GPS coordinates, Google Maps, and most modern mapping systems. The library uses the WGS84 (World Geodetic System 1984) reference ellipsoid, which is the standard for GPS coordinates, Google Maps, and most modern mapping systems.
Key constants: Key constants:
``` ```
a = 6378137.0 m (semi-major axis, equatorial radius) a = 6378137.0 m (semi-major axis, equatorial radius)
1/f = 298.257223563 (inverse flattening) 1/f = 298.257223563 (inverse flattening)
@ -45,6 +46,7 @@ Up = (cos φ cos λ, cos φ sin λ, sin φ)
``` ```
These are unit vectors. To convert a topocentric ECEF displacement Δ (in meters) to ENU: These are unit vectors. To convert a topocentric ECEF displacement Δ (in meters) to ENU:
``` ```
e = East · Δ e = East · Δ
n = North · Δ n = North · Δ
@ -67,6 +69,7 @@ Altitude is the angle above the horizontal plane: 0° = horizon, 90° = zenith,
The Moon's geocentric position (from the ephemeris) differs from its topocentric position (as seen by a surface observer) because the Moon is close enough that the baseline between Earth's center and the observer's surface position is significant. This is the diurnal parallax. The Moon's geocentric position (from the ephemeris) differs from its topocentric position (as seen by a surface observer) because the Moon is close enough that the baseline between Earth's center and the observer's surface position is significant. This is the diurnal parallax.
The correction is simply: The correction is simply:
``` ```
topocentric_direction = moon_ITRS observer_ITRS topocentric_direction = moon_ITRS observer_ITRS
``` ```
@ -103,6 +106,7 @@ Standard conditions: P = 1013.25 mbar, T = 15°C. The correction factors adjust
### Accuracy limits ### Accuracy limits
The Bennett formula is accurate to: The Bennett formula is accurate to:
- ~0.1 arcminute for h > 5° - ~0.1 arcminute for h > 5°
- ~0.5 arcminute for h = 2° - ~0.5 arcminute for h = 2°
- ~12 arcminutes for h < 2° - ~12 arcminutes for h < 2°
@ -114,16 +118,16 @@ This is why crescent sighting criteria use "airless" (refraction-free) altitudes
### When to apply refraction ### When to apply refraction
| Use case | Mode | | Use case | Mode |
|----------|------| | ------------------------------------ | ------------------- |
| Yallop ARCV input | Airless | | Yallop ARCV input | Airless |
| Odeh ARCV input | Airless | | Odeh ARCV input | Airless |
| Sunset/moonset threshold | Standard refraction | | Sunset/moonset threshold | Standard refraction |
| "Where to look" altitude output | Standard refraction | | "Where to look" altitude output | Standard refraction |
| Civil/nautical/astronomical twilight | Standard refraction | | Civil/nautical/astronomical twilight | Standard refraction |
moon-sighting computes both airless and apparent altitudes for each body position and uses the appropriate one for each purpose. moon-sighting computes both airless and apparent altitudes for each body position and uses the appropriate one for each purpose.
--- ---
*Previous: [Reference Frames](Reference-Frames) | Next: [Validation](Validation)* _Previous: [Reference Frames](Reference-Frames) | Next: [Validation](Validation)_

View file

@ -13,6 +13,7 @@ The IERS Conventions (2010) define the standard transformation:
``` ```
Where: Where:
- **GCRS** = Geocentric Celestial Reference System (essentially the inertial J2000 frame at Earth's center) - **GCRS** = Geocentric Celestial Reference System (essentially the inertial J2000 frame at Earth's center)
- **ITRS** = International Terrestrial Reference System (Earth-fixed frame, rotates with the solid Earth) - **ITRS** = International Terrestrial Reference System (Earth-fixed frame, rotates with the solid Earth)
- **Q(t)** = celestial motion matrix (precession + nutation) - **Q(t)** = celestial motion matrix (precession + nutation)
@ -31,6 +32,7 @@ The IAU 2006 precession model and IAU 2000A nutation model together parameterize
- **s:** CIO locator, a small angle that ensures continuity of the CIO position - **s:** CIO locator, a small angle that ensures continuity of the CIO position
The CIP X,Y series has: The CIP X,Y series has:
- A polynomial part (degree 5 in T = Julian centuries from J2000.0) - A polynomial part (degree 5 in T = Julian centuries from J2000.0)
- 1,306 luni-solar nutation terms - 1,306 luni-solar nutation terms
- 687 planetary nutation terms - 687 planetary nutation terms
@ -71,13 +73,13 @@ moon-sighting defaults to xp = yp = 0. Supply current values from IERS Bulletin
## IAU 2000A vs 2000B ## IAU 2000A vs 2000B
| Feature | 2000A | 2000B | | Feature | 2000A | 2000B |
|---------|-------|-------| | ---------------- | ------------- | ---------------- |
| Luni-solar terms | 1,306 | 77 | | Luni-solar terms | 1,306 | 77 |
| Planetary terms | 687 | 0 | | Planetary terms | 687 | 0 |
| Max error | < 0.1 mas | < 1 mas | | Max error | < 0.1 mas | < 1 mas |
| Computation | ~2× slower | fast | | Computation | ~2× slower | fast |
| Suitable for | moon sighting | approximate work | | Suitable for | moon sighting | approximate work |
For crescent sighting at the horizon where refraction dominates, 2000B is more than sufficient. moon-sighting defaults to 2000A for correctness; 2000B will be available as a compile-time option for size-sensitive builds. For crescent sighting at the horizon where refraction dominates, 2000B is more than sufficient. moon-sighting defaults to 2000A for correctness; 2000B will be available as a compile-time option for size-sensitive builds.
@ -96,13 +98,15 @@ See [Observer Model](Observer-Model) for the WGS84 and ENU computation details.
## Accuracy ## Accuracy
With user-supplied EOP (Earth orientation parameters from IERS Bulletin A): With user-supplied EOP (Earth orientation parameters from IERS Bulletin A):
- Azimuth/altitude accuracy: < 0.1 arcsecond (dominated by nutation model error) - Azimuth/altitude accuracy: < 0.1 arcsecond (dominated by nutation model error)
With polynomial ΔT approximation (no user EOP): With polynomial ΔT approximation (no user EOP):
- Azimuth/altitude accuracy: typically < 5 arcseconds, occasionally up to ~30 arcseconds in pathological ΔT errors - Azimuth/altitude accuracy: typically < 5 arcseconds, occasionally up to ~30 arcseconds in pathological ΔT errors
For comparison, the Moon's angular diameter is ~1800 arcseconds, and refraction uncertainty near the horizon is 600900 arcseconds. The frame transform is not the limiting factor for crescent sighting. For comparison, the Moon's angular diameter is ~1800 arcseconds, and refraction uncertainty near the horizon is 600900 arcseconds. The frame transform is not the limiting factor for crescent sighting.
--- ---
*Previous: [Time Scales](Time-Scales) | Next: [Observer Model](Observer-Model)* _Previous: [Time Scales](Time-Scales) | Next: [Observer Model](Observer-Model)_

View file

@ -106,4 +106,4 @@ The NAIF LSK (`naif0012.tls`) is a plain-text file in NAIF text kernel format. I
--- ---
*Previous: [Ephemeris](Ephemeris) | Next: [Reference Frames](Reference-Frames)* _Previous: [Ephemeris](Ephemeris) | Next: [Reference Frames](Reference-Frames)_

View file

@ -21,6 +21,7 @@ NASA NAIF's SPICE toolkit is the authoritative reference for reading JPL ephemer
Any deviation in the SPK Chebyshev evaluation from SPICE indicates a parsing or algorithm error in moon-sighting. Any deviation in the SPK Chebyshev evaluation from SPICE indicates a parsing or algorithm error in moon-sighting.
**How to compare:** **How to compare:**
```python ```python
import spiceypy as spice import spiceypy as spice
spice.furnsh('de442s.bsp') spice.furnsh('de442s.bsp')
@ -33,6 +34,7 @@ print(state[:3]) # position in km
``` ```
The moon-sighting equivalent: The moon-sighting equivalent:
```ts ```ts
const kernel = SpkKernel.fromFile('de442s.bsp') const kernel = SpkKernel.fromFile('de442s.bsp')
const ts = computeTimeScales(new Date('2025-03-29T20:00:00Z')) const ts = computeTimeScales(new Date('2025-03-29T20:00:00Z'))
@ -44,6 +46,7 @@ Expected agreement: < 1 meter (floating-point evaluation precision).
### JPL Horizons ### JPL Horizons
JPL Horizons is the online solar system ephemeris service. It uses the same JPL ephemerides and provides tabular output for: JPL Horizons is the online solar system ephemeris service. It uses the same JPL ephemerides and provides tabular output for:
- Apparent RA/Dec and az/alt for any observer and time - Apparent RA/Dec and az/alt for any observer and time
- Observer-centered quantities (elongation, illumination, phase angle) - Observer-centered quantities (elongation, illumination, phase angle)
- Rise/transit/set times - Rise/transit/set times
@ -52,6 +55,7 @@ Horizons uses SPICE internally, so it represents an independent end-to-end valid
**How to use for validation:** **How to use for validation:**
Go to https://ssd.jpl.nasa.gov/horizons/, select: Go to https://ssd.jpl.nasa.gov/horizons/, select:
- Target body: Moon (or Sun) - Target body: Moon (or Sun)
- Observer location: user-defined geodetic lat/lon/elevation - Observer location: user-defined geodetic lat/lon/elevation
- Time span: the date of interest - Time span: the date of interest
@ -61,15 +65,15 @@ Compare Horizons' output with moon-sighting's topocentric az/alt. Differences of
## Acceptance thresholds ## Acceptance thresholds
| Quantity | Expected error vs SPICE | Notes | | Quantity | Expected error vs SPICE | Notes |
|----------|------------------------|-------| | ---------------------------------- | ----------------------- | ------------------------------------------------------------------- |
| Geocentric position | < 1 m (< 0.001 arcsec) | SPK parsing precision | | Geocentric position | < 1 m (< 0.001 arcsec) | SPK parsing precision |
| Topocentric az/alt (with EOP) | < 0.1 arcsec | Frame transform precision | | Topocentric az/alt (with EOP) | < 0.1 arcsec | Frame transform precision |
| Topocentric az/alt (polynomial ΔT) | < 30 arcsec | ΔT polynomial error | | Topocentric az/alt (polynomial ΔT) | < 30 arcsec | ΔT polynomial error |
| ARCL | < 1 arcsec | Derived from positions | | ARCL | < 1 arcsec | Derived from positions |
| ARCV | < 30 arcsec | Dominated by ΔT uncertainty | | ARCV | < 30 arcsec | Dominated by ΔT uncertainty |
| Yallop q | < 0.005 | q is dimensionless; <0.005 difference = same category in most cases | | Yallop q | < 0.005 | q is dimensionless; <0.005 difference = same category in most cases |
| Sunset/moonset | < 10 seconds | Root-finding convergence | | Sunset/moonset | < 10 seconds | Root-finding convergence |
## Validation suite ## Validation suite
@ -98,4 +102,4 @@ Be cautious: ICOP records include weather and observer acuity information that t
--- ---
*Previous: [Observer Model](Observer-Model) | Next: [API Reference](API-Reference)* _Previous: [Observer Model](Observer-Model) | Next: [API Reference](API-Reference)_