# Moon equatorial coordinates

It took some effort, but in the end, I successfully calculated the geographical point of the Sun. I assumed that I could do the same for the Moon.

My plan is:

1. Find RA and declination of the Moon
2. Find GHA of the Moon, using the same math as for the Sun

However, after following this article almost to the letter (except for precession and perturbations), my calculated answer is much different from this site. I've examined the article and my code many times, but can't see an error.

I use Swift programming language, but here it's merely a way to represent my calculations and results.

If anyone would like to try it for yourself, here's my code in text format:

import Foundation

extension Double {
return self * .pi / 180
}

var degrees: Double {
return self  * 180 / .pi
}

var rangedUpTo360: Double {
let multiples = (self/360).rounded(.down)
return self - 360*multiples
}

var rangedUpTo86400: Double {
let multiples = (self/86400).rounded(.down)
return self - 86400*multiples
}
}

extension Date {
var greenwich: Date {
return greenwichDate
}
}

class Astronomy {

static func julianDays(since: Date) -> Double {
return since.timeIntervalSince1970 / 86400 + 2_440_587.5
}

static func daysSinceJ2000(for date: Date) -> Double {
return julianDays(since: date) - 2_451_545
}

static func sunAxialTilt(for daysSinceJ200: Double) -> Double {
return 23.4393 - 3.563e-7 * daysSinceJ200
}

static func greenwichHourAngle(rightAscension: Double, date: Date) -> Double {
let greenwichTimeZone = TimeZone(secondsFromGMT: 0)!
var calendar = Calendar.current
calendar.timeZone = greenwichTimeZone
let components = calendar.dateComponents([.hour, .minute, .second], from: date)
let secondsOfDay = Double(components.hour!)*3600 + Double(components.minute!)*60 + Double(components.second!)

let centuriesSinceJ200 = daysSinceJ2000(for: date.greenwich) / 36525
let greenwichSiderealTime = 24110.54841 + 8640184.812866*centuriesSinceJ200 + 0.093104*pow(centuriesSinceJ200, 2) - 0.0000062*pow(centuriesSinceJ200, 3)
let earthSiderealRotationRate = 1.00273790935 + 5.9e-11*centuriesSinceJ200
let earthRotation = earthSiderealRotationRate*secondsOfDay
let gmstSeconds = greenwichSiderealTime + earthRotation
let gmstSecondsNormalized = gmstSeconds.rangedUpTo86400
let gmst = gmstSecondsNormalized / 3600 * 15
return gmst.rangedUpTo360 - rightAscension
}

static func moonPosition(on date: Date) -> (declination: Double, RA: Double, distance: Double) {
date
// day number
let d = daysSinceJ2000(for: date)
// longitude of the ascending node
var N = 125.1228 - 0.0529538083 * d // have to be normalized
if N < 0 {
N += 360
}
// inclination to the ecliptic (plane of the Earth's orbit)
let i = 5.1454
// argument of perihelion
var w = 318.0634 + 0.1643573223 * d // have to be normalized
w = w.rangedUpTo360
// semi-major axis, or mean distance from Sun
let a = 60.2666 // (Earth radii)
// eccentricity (0=circle, 0-1=ellipse, 1=parabola)
let e = 0.054900
// mean anomaly (0 at perihelion; increases uniformly with time)
var M = 115.3654 + 13.0649929509 * d // have to be normalized
M = M.rangedUpTo360
// eccentric anomaly
let E = M + e * sin(M.radians) * (1.0 + e * cos(M.radians))
let xv = a * (cos(E.radians) - e)
let yv = a * (sqrt(1.0 - e*e) * sin(E.radians))
// true anomaly (angle between position and perihelion)
let v = atan2(yv, xv).degrees
let r = sqrt(pow(xv, 2) + pow(yv, 2))
// geocentric ecliptical position
// equatorial coordinates
let ecl = sunAxialTilt(for: d)
let xE = xG
//right scension
var rA = atan2(yE, xE)
rA = rA.degrees
// declinatino
var dec = atan2(zE, sqrt(xE * xE + yE * yE) )
dec = dec.degrees
// geocentric distance
let rG = sqrt(xE * xE + yE * yE + zE * zE)
return (declination: dec, RA: rA, distance: rG)
}
}

Astronomy.moonPosition(on: Date().greenwich)

• How big are the errors that you are seeing ? I compared theskylive.com link you gave and the apparent Moon position it gave for Greenwich at 2019-02-09 16:52 UTC was off by (2.8,-37.2) arcminutes in RA,Dec respectively compared to JPL HORIZONS and SLALIB. As noted in the njsas.org article, you need the perturbations included to get the position better than 2 degrees - the Moon is so close and moves relatively quickly that small errors in time etc get magnified. Lunar motion theory is surprisingly complicated – astrosnapper Feb 9 '19 at 18:03
• @astrosnapper My code returns these values for Feb 9, 2019 at 8:16 PM: - RA: -0.5199 - Dec: -5.1769 While the website returns: - RA: 15.56 - Dec: 1.073 If it were to the lack of perturbation calculations, shouldn't the difference be in 2 degrees range? Somewhere I read that if atan2 returns a negative number in the calculations, I need to add .pi to it. Is it so? And does it mean I have to add 3.14 or 180? I tried though, but it results in a much bigger error. – bitemybyte Feb 9 '19 at 20:57
• Here's what I get using njsas's formulae for your datetime (assuming it's UTC , for the geocenter and without the perturbations): N=115.460502, i=5.1454, w=25.416300,a=60.2666,e=0.0549, M=240.048858 (N,i,w,M are in degrees, a in Earth radii, e unitless). xg,yg,zg are (60.938805003268435, 9.606098833264198, -5.326251364267174) and obliquity of the ecliptic, ecl=23.436812725124444 degrees. This gives RA=0.17750561458751776, Dec= -0.017218433367563225 (both radians) or 00h40m40.88s -00d 59' 11.56". HORIZONS gives: 01 03 06.19 +01 09 42.9 so ~2deg out in Dec – astrosnapper Feb 10 '19 at 19:28
• One thing to be careful is whether your quantities are in the right units. In the njsas formulae many things are done in degrees initially but there seems to be some missing conversions to radians when used in trig functions. For the eccentric anomaly, E, both the sin(M) and cos(M) need conversions. Similarly the use of E in the xv,yv formulae (Sec. 6) need converting as does the use of N and i in the formula for 3D position (Sec. 7) and ecl in the conversion from ecliptic to equatorial (Sec. 12). – astrosnapper Feb 10 '19 at 19:36
• Hm, for the same date (Feb 9 20:16) I get these results: d=6979.2194; N=115.5465; i=same; w=25.1492; a=same; e=same; M=218.8182; E=218.7853; xg,yg zg=(62.5865, -2.7821, -4.9766); ecl=23.4368; RA=-0.0091580905076487; declination=-0.09038631707987221; Which is different on more then 2 degrees from yours. Would you mind sharing what was your d, E, xV, yV and v? I believe I've handled the conversions properly, as all the sin/cos inputs in my code get converted to radians. ".degrees" and ".radians" in my code convert the value to from rad to degrees and from degrees to rad respectfully – bitemybyte Feb 11 '19 at 18:27

It's a bit late but hopefully it will help others in the future.

The calculations can be found on this site, article from Keith Burnett (keith@xylem.demon.co.uk)

The first problem is that you use J2000 as time reference but it's not what the site takes as time reference!

"Get the days to Dec 31st 0h 2000 - note, this is NOT same as J2000"

So you have to do :

let d = daysSinceJ2000(for: date) + 1.5


The second problem is you are missing one degrees to radians conversion when you calculate E, it should be

let E = M.radians + e * sin(M.radians) * (1.0 + e * cos(M.radians))


The third problem is the calculation of the declination, it should be arctan, not arctan2 :

var dec = atan(zE / sqrt(xE * xE + yE * yE) )


On a side note, when you do :

var N = 125.1228 - 0.0529538083 * d // have to be normalized
if N < 0 {
N += 360
}


N is still negative, to put a negative value within (0,360) I did

N = range(N)

func range(x: Double) -> Double{
if x >= 0 {
return x
}
else {
return range(x: x + 360)
}
}


For positive values, you can just use

M = M.truncatingRemainder(dividingBy: 360)


Although I don't think it's really crucial for the calculations, I tried without and it worked fine

Cheers, Lucas