Sunset Calculation Using NOVAS

5 August 2014

Introduction

I want to catch the most beautiful sunset light on the beach. It can happen any time within 20 minutes before or after sunset. All I need is the sunset time for today.

Calculation

Current position of any astronomical object is defined by azimuth and altitude angles measured from the particular observer's location on Earth's surface.

Astronomical objects appear higher in the sky than they are in reality. It's because atmospheric refraction, caused by temperature, pressure, etc. The final calculation is far more complex when refraction and Earth's elliptical orbit is taken into account.

For the most accurate results I have used novas package. It's an Go interface to the Naval Observatory Vector Astrometry Software (NOVAS).

NOVAS is an integrated package of subroutines and functions for computing various commonly needed quantities in positional astronomy. The package can provide, in one or two subroutine or function calls, the instantaneous coordinates of any star or planet in a variety of coordinate systems. At a lower level, NOVAS also supplies astrometric utility transformations, such as those for precession, nutation, aberration, parallax, and the gravitational deflection of light. The computations are accurate to better than one milliarcsecond.

This program calculates sunset for given location.

package main

import (
    "fmt"
    "github.com/pebbe/novas"
    "time"
)

const (
    sundip = float64(-0.8)
)

func main() {

    // example: Rome, Italy
    latitude, longitude := 41.88333, 12.5

    now := novas.Now()

    // 13m elevation, 29°C, 1010 mbar air pressure 
    observer := novas.NewPlace(latitude, longitude, 13, 29, 1010)

    sun := novas.Sun()

    t0 := novas.Date(now.Year(), int(now.Month()), now.Day(), 0, 0, 0, 0, now.Location())

    // no refraction
    t1, _, err := sun.Set(t0, observer, sundip, time.Second, novas.REFR_NONE)
    if err != nil {
        fmt.Println(err)
    } else {
        fmt.Printf("Sunset (0): %s\n", t1)
    }

    // with refraction
    t2, _, err := sun.Set(t0, observer, sundip, time.Second, novas.REFR_PLACE)
    if err != nil {
        fmt.Println(err)
    } else {
        fmt.Printf("Sunset (R): %s\n", t2)
    }
}

Output times for Rome, Italy:

Sunset (0): 2014-08-05 20:23:39.43359375 +0200 CEST
Sunset (R): 2014-08-05 20:24:49.74609375 +0200 CEST

Two times are displayed, one with no refraction taken into account, and the other with refraction included into calculation. The refraction causes the difference of 70 seconds between sunset times.

Terrestrial problem: Sun goes behind a hill

For example, if there is a hill at 5km in front of sight, with relative height of 600m, how to find a dip point when the Sun goes behind a hill. The sundip point of -0.8° in the program's code should be compensated. An altitude approximation of the hill in this particular case is 6.8° viewed by observer. The final adjustment results in Sun dip point of 6.0°.

const (
    sundip = float64(6.0)
)

Output times for an adjusted Sun dip:

Sunset (0): 2014-08-05 19:44:39.78515625 +0200 CEST
Sunset (R): 2014-08-05 19:45:23.73046875 +0200 CEST

The Sun goes behind the hill more than 30 minutes sooner, comparing to the case when there are no significant terrestrial elements present. There should be only shadow at observer's location because of hill.

Summary

In order to compute accurate sunset time you need to determine precisely all location's parameters: latitude, longitude, elevation, temperature, and air pressure. And to watch the most beautiful light on the beach - get there 20 minutes before calculated sunset.

By one coder