Matik.Org

Moon Pointer Part Four - Where in the World is the Moon?

In the previous chapters, we have set up the hardware and the programming environment. In this chapter, we look at the astronomical calculation that allow us to point at the right place in the sky.

Now, I will be honest - I don’t really know what I’m doing here. If your life depends on the proper moon position, it’s safer to go with an established astro library like pyephem or use an online API.

However, looking at the suncalc.js library, this really isn’t too hard.

  1. The first step is figuring out the moon coordinates relatively to the earth. These coordinates are called right ascension and declination instead of lat/lon. See formulas here.

    right ascension and declination for moon
  2. The second step is to figure out where the observer is and compute azimuth (i.e. direction on the compass) and altitude (0=horizon, 90 = directly overhead). The formulas for this are fairly complex and explained in this book by Jean Meeus. In addition to the (mostly trigonometric) functions, there’s also some corrections, like atmospheric refraction. A clear TODO is to compare results with other libraries like pyepehem or some other implementations, like this one.

    Azimuth calculation Altitude calculation

Anyway, I modified the suncalc.js library and reimplemented it in (micro)python. Github link here. It has a bunch more functions than I strictly need for the moon tracker, like moon illumination and rise/set times - you’re welcome.

Some words of warning:

  1. The formulas used work on the (fractional) number of days since 1/1/2000 in UTC, but get_moon_position() expects seconds since the Unix epoch, 1/1/1970, so the to_Days() function does the conversion for us.
    1. Times have to be converted from Unix or micropython time, which is seconds since start of 1/1/1970 (UTC) in the case of Unix, or from 1/1/2000 (UTC) in the case of micropython on an MCU board (but not the Unix ‘emulator’).

    2. Micropython’s time functions are not the same as ‘proper’ python’s. So, when you call these functions, make sure you are creating a timestamp in UTC, not localtime. Luckily, for the production setup, the GPS module reports UTC timestamps anyway, machine.RTC().datetime(t) expects t to be a tuple in GMT, and time.time() uses by default (.e. you haven’t connected to an ntpserver etc) the GMT or UTC time zone.

      We should probably clean up this API, preferably by just passing dates as seconds since 1/1/2000 and changing the callers.

  2. The formulas are only approximations - Meeus suggest there are over 100 components known, but we are only using the largest 3. Besides the fact that some terms have been left out, the formulas also are slowly drifting out of sync. There’s a NASA website that describes this drift, that can be compensated by a ‘delta-t’, currently at approximately 72 seconds, that a caller should add to the passed time stamp.

In the next and final chapter, we put everything together and try out the pointer.

Written on July 29, 2020