Skip to main content

Navigation: Using Local Noon to Find Position

· 10 min read
Software Engineer

I was messing around with a fun navigation problem the other day and thought I'd share it. I was scrolling through a weather app on my phone when I came across the sunrise and sunset times and wanted to try calculating my longitude from these times.

I started with sunrise and sunset times from a weather app, but there are other (and better) ways to get that information. My preferred way is to use the United States Naval Observatory's website. The USNO site has a number of navigation/astronomy related tools, but the one we need for this is the sun and moon data for one day. Using Form A on that page, we can pull up the sun data for our location on a given day.

I redid the calculation to correspond to the day of this writing and looked up the sun data for Columbus, Ohio on December 31, 2017. It shows the following data:

| Sun | | :------------ |:-------------:| | Sunrise | 7:54 a.m. | | Sun transit | 12:35 p.m. | | Sunset | 5:17 p.m. |


We can compute our local noon by finding the time halfway between sunrise and sunset, but one of the nice things about using the USNO tool is that local noon (i.e. Sun transit) is provided.

Let's take a brief step back and explain what local noon actually is -- local noon is the time when the sun reaches its highest point in the sky. It's the midpoint of the day. Or, more technically, it is when your longitude line is directly beneath the sun. So by knowing when our local noon occurs, we know when our longitude line is directly under the sun.

We've determined our local noon time with a simple calculation (or looked it up), but it can also be observed using a sextant. This can be a way to be more accurate, but we'll see in a bit why there isn't much use in trying to be more accurate than this.

Calculating Longitude from Local Noon

From our local noon we know when our longitude passes directly under the sun. How does this help us figure out what our longitude is? Well, we need another piece of information. The local noon time for a known longitude. Then we can compare that time local noon time to our local noon time. Why is that useful? Because we know how fast the Earth rotates. This let's us compute our longitude. Let's step through it.

We can use the USNO sun data tool again to lookup local noon for known longitude. Since Columbus is in the Eastern time zone (for some reason), we will use Form B to lookup the local noon time at 75W (the longitude of the center of the Eastern time zone). We'll also set the time zone in the form to be 5 hours West of Greenwich so it will give us the times in Eastern time rather than UTC and we don't have to worry about converting between time zones.

We get a local noon time of 12:03. Now we take the difference between our local noon (12:35 p.m.) and local noon at 75W (12:03 p.m.): 32 minutes.

Knowing that Earth rotates 15 degrees per hour (1 rotation = 360 degrees per 24 hours), we can determine our offset from 75W.

offset=3260hours15/hour=8offset = \frac{-32}{60} hours \cdot 15^\circ/hour = -8^\circ

Note: We use -32 because our local noon occurs later than the known local noon. So our difference should really be computed as 12:03 - 12:35 giving us -32. So our computed offset is 8 degrees behind 75W. Now simple addition tells us our final longitude:

longitude=758=83longitude = -75 - 8 = -83^\circ

Our longitude is 83W. If we look up the actual longitude of Columbus, we find that it is 82.99W. Accurate to within .01 degree.

A Generalized Formula

Let's create a single formula for this calculation:

longitude=ϕknownϕoffsetϕoffset=tknowntlocal6015longitude = \phi_{known} - \phi_{offset} \\ \phi_{offset} = \frac{t_{known} - t_{local}}{60} \cdot 15

This gives us the final formula:

longitude=ϕknown(tknowntlocal6015)longitude = \phi_{known} - \Big(\frac{t_{known} - t_{local}}{60} \cdot 15\Big)

Where ϕknown\phi_{known} is the longitude of the known local noon being used, tknownt_{known} is the local noon time for the known longitude, and tlocalt_{local} is your local noon time.

Error in Longitude

Now let's take our formula and determine our possible error in our longitude calculation. We'll assume no error in our known longitude has no error. We can assume our local noon times have an error of plus or minus 30 seconds. Our local noon for our position could have an error of plus or minus 1 minute if we compute it from the sunrise/sunset times.

longitude=±0(±0.5min±0.5min6015)longitude = \pm0 - \Big(\frac{\pm 0.5 min - \pm 0.5 min}{60} \cdot 15\Big) longitude=±160hour15longitude = \pm \frac{1}{60} hour \cdot 15 longitude=±1560longitude = \pm \frac{15}{60} longitude=±14=0.25longitude = \pm \frac{1}{4} = 0.25^\circ

So we can see that our potential error is much higher than our computation.

In fact I had tried to calculate this with second accuracy rather than minute accuracy, which I did in an attempt to improve my result. I used Stellarium to simulate an observation. In this case, I was able to obtain second accuracy in my local noon time, but the local noon time for the known longitude is still only accurate to the nearest minute. So, I do improve my error by doing this (by half), but my final result of 83.12W was actually further off than my initial calculation.

In other words, the accuracy of my first answer was really just luck.

Calculating Latitude at Local Noon

We can also calculate our latitude using a local noon observation. We can take an observation of the sun at local noon and measure the elevation angle of the sun. In my case, I simulated an observation using Stellarium.

I observed the Sun's highest point to be 27147"27^\circ 1' 47". We can also lookup the Sun's declination at that time using the USNO's celestial navigation tool for our given day and our local noon time (in UTC). We find that the Sun's declination is S232.4S23^\circ 2.4'.

Finally we can compute our latitude using the following formula (which varies based on where you are and where the Sun is, but I found this video to be useful in understanding which equation to use):

latitude=zenithdeclinationlatitude = zenith - declination

Where zenith=90Hozenith = 90 - H_o (and HoH_o is the observed elevation). Using this formula, we calculate our latitude to be 39.94N.

Error in Latitude

Our formula above can be expressed as latitude=90Hodeclatitude = 90 - H_o - dec. We'll assume no error in our declination since we can look that up. So our only source of error is our measurement of the Sun's elevation. Assuming we can

Final Results

I mapped the final results to Google Earth with the margin of error. The image below shows the first calculation using only minute accuracy on the local noon times and assuming plus or minus .01 degree accuracy in my latitude measurement.

Results - Calculation 1

I then included the second calculation (where my error was decreased, but my answer was less accurate). This is shown in the image below.

Results - Calculation 2

I've worked out problems similar to this in my graduate course work, but in those cases we only cared about being close enough, with little to no emphasis on how close the answer actually was. What this process has shown is that it is impossible to determine longitude more accurate than about ±18\pm \frac{1}{8}^\circ without knowing the local noon time at a known point (i.e. my 75W point in my calculations above) to a higher accuracy than ±1\pm 1 minute.

Appendix - Coding It Up

The following scripts were used to calculate longitude and latitude, respectively. These are included and an appendix to the main article to show how the calculations were actually computed and allow others to reproduce the procedure with ease.

longitude.py

#!/usr/bin/env python
from __future__ import division
import datetime

################################################################################
# USER INPUTS -> Change these
################################################################################
# Local sunrise and sunset times
# Lookup using Form A at http://aa.usno.navy.mil/data/docs/RS_OneDay.php
sunrise = datetime.time(7, 54)
sunset = datetime.time(17, 17)
# Timezone longitude
# This number is the longitude line at the center of your timezone
# e.g. the Eastern time zone is located at 75W, this would be -75
timezone = -75
# Local noon for your time zone
# Lookup using Form B at http://aa.usno.navy.mil/data/docs/RS_OneDay.php
# Use time zone's longitude, 0 latitude, and the time zone's UTC offset
localnoon_tz = datetime.time(12, 03)
################################################################################
# END OF USER INPUTS
################################################################################

# Convert our time objects into datetime objects using today's date
# This allows us to easily calculate time deltas
today = datetime.datetime.today()
sunrise = datetime.datetime(today.year, today.month, today.day, sunrise.hour, sunrise.minute)
sunset = datetime.datetime(today.year, today.month, today.day, sunset.hour, sunset.minute)
localnoon_tz = datetime.datetime(today.year, today.month, today.day, localnoon_tz.hour, localnoon_tz.minute)

# Compute our local noon -> sunrise + time_delta
localnoon_delta = (sunset - sunrise)
localnoon = sunrise + datetime.timedelta(seconds=localnoon_delta.seconds/2.0)

# Print local noon info
print 'Local Noon: ', localnoon
print 'Local Noon @ TZ:', localnoon_tz

# Compute the difference between localnoon and localnoon for the timezone
delta = (localnoon_tz - localnoon).seconds
if delta > 60*60*12:
delta = -(60*60*24 - delta)

# Print time delta info
print 'Offset: ', abs(delta/60.0), 'minutes',
print 'east of' if delta > 0 else 'west of',
print abs(timezone), 'E' if timezone > 0 else 'W'

# Compute degree offset
fraction_of_hour = delta / (60.0 * 60.0)
degrees_per_hour = 15 # Earth's rotation
degrees = fraction_of_hour * degrees_per_hour

# Determine Longitude
longitude = timezone + degrees
E_or_W = 'E' if longitude > 0 else 'W'
print 'Longitude: {:.2f}{}'.format(abs(longitude), E_or_W)

latitude.py

#!/usr/bin/env python
################################################################################
# User Inputs -> CHANGE THESE
################################################################################
# Ho is the elevation angle of the sun at local noon (i.e. suns highest point)
# This is the observed elevation
Ho = 27 + 1.0/60.0
# Sun's declination
# Lookup declination for a given day at
# http://aa.usno.navy.mil/data/docs/celnavtable.php
dec = -(23 + 2.4/60.0)
# Assumed lattitude
# This is used to decide which method to calculate latitude.
# We have 3 cases:
# - You are in the opposite hemisphere as the sun
# - You are between the sun and the pole
# - You are between the sun and the equator
# This only becomes a problem if your assumption about latitude is off far
# enough to impact this calculation.
assumed_lat = 36
################################################################################
# END OF USER INPUTS
################################################################################

zenith = 90 - Ho

# Opposite Hemispheres
if ((assumed_lat > 0) and (dec <= 0)) or ((assumed_lat < 0) and (dec >= 0)):
lat = zenith - abs(dec)
method = 'latitude = zenith - declination'
# Same hemisphere
else:
# We are between sun and pole
if abs(assumed_lat) > abs(dec):
lat = zenith + abs(dec)
method = 'latitude = zenith + declination'
# We are between sun and equator
else:
lat = abs(dec) - zenith
method = 'latitude = declination - zenith'


given = 'Using assumed latitude of {:.2f}{}'
print given.format(assumed_lat, 'N' if assumed_lat >= 0 else 'S')
print 'Method Used: ', method
print 'Ho {:.2f}'.format(Ho)
print 'Zenith {:.2f}'.format(zenith)
print 'Dec. {:.2f}'.format(dec)
print 'Computed Latitude: {:.2f}{}'.format(lat, 'N' if assumed_lat > 0 else 'S')