Repository: sunpy/sunpy

Issue:
Agree on solar ephemerids calculations
@wafels said: We should unify sun_pos.py and sunpy.sun but agree on which calculation to use on PR #452 

Missing calculations for sunpy.sun functions
Three functions are missing the mathematics to calculate them.
These seem to be:

* longitude_Sun_perigee
* true_latitude 
* apparent_latitude

We need to track down what they need to calculate from sources and implement that. 


Discussion:
The most accurate ones?

sunpy.sun breaks if time is not input, though time is set as None.  Should we set time_parse to today if None is input? It makes sense for me for the functions in sunpy.sun.

Also, solar_cycle_number does not make sense to me...  can be expressed as a simple equation like that? I don't see how it would work with the actual equation, it seems it would change cycle year after year every 28 years.

@dpshelio I would have to have a look at the API to see if parse_time(None) makes sense. It seems a little wonky. parse_time('today') would be better.

@Cadair  that's fine with me (and it's more clear), but then we need to fix the sun.py as the default is None, or parse_time(None) throw an exception.

@wafels @dpshelio @ehsteve @ayshih 

This need to be decided asap. It is a blocker on 0.3.

@Cadair, you moved this to 0.4... so it's not a blocker for 0.3 anymore, right?

I thought I would bump it because nothing was happening and we need to get 0.3 out of the door. If we can fix before release then all good.

It wasn't just this I bumped either, I went on a bit of a spree.

No problem @Cadair, I just wanted to be sure.  For all I read yesterday this could take us a bit longer to do...

ok folks @wafels @dpshelio @ehsteve @ayshih  this is getting anoying :p 

What is the plan here?

I propose moving sun_pos into sunpy.sun and dropping solar_semidiameter_angular_size.

it is used in line 33 in map.sources.soho.py

I have been comparing three different versions of the calculation of the apparent right ascension and apparent declination of the Sun as seen from earth.  These are

JPL - as calculated by http://ssd.jpl.nasa.gov/horizons.cgi . I am assuming that this one is the most accurate, and any calculation we implement in sunpy approximates the values from JPL.

sun.py - as calculated by sun.py in the sunpy master branch.

solar_ephemeris.py - as calculated by the function solar_ephemeris in https://github.com/wafels/sunpy/blob/0.3_diffrot/sunpy/sun/sun.py .

I am primarily interested in the apparent right ascension and apparent declination since these are the values that are required to implement solar rotation of locations on the sun's disk as seen from the Sun-Earth line.  Here are some results.  The RMS values comparing JPL to the two sunpy calculations are also shown.  The function solar_ephemeris provides much more accurate values than sun.py

I propose replacing the existing apparent right ascension and apparent declination calculations in sun.py with those in the solar_ephemeris function.  At the moment the solar_ephemeris function is a direct translation of sun_pos.py.  I will examine the accuracy of the other quantities calculated by the function solar_ephemeris and make a recommendation.

![app_dec_compare](https://f.cloud.github.com/assets/983575/1841760/2a583758-74ad-11e3-8e44-b9ced16afd67.png)
![app_ra_compare](https://f.cloud.github.com/assets/983575/1841762/2e7d83d8-74ad-11e3-9fe1-641b26c4e992.png)

Nice one!! What the hell is that bug in the RA?

The apparent RA calculation requires an angle in degrees, but the function
used returns radians.  The pull request fixes this.

On Fri, Jan 3, 2014 at 4:20 PM, Stuart Mumford notifications@github.comwrote:

> Nice one!! What the hell is that bug in the RA?
> 
> —
> Reply to this email directly or view it on GitHubhttps://github.com/sunpy/sunpy/issues/472#issuecomment-31554624
> .

Where are we with this?

I still need to do some more checking.  I am planning on doing this as part
of the solar derotation package.  It won't get done in the next week as I'm
off to the SPD next week.

On Fri, May 30, 2014 at 10:41 AM, Stuart Mumford notifications@github.com
wrote:

> Where are we with this?
> 
> ## 
> 
> Reply to this email directly or view it on GitHub
> https://github.com/sunpy/sunpy/issues/472#issuecomment-44658319.

@Cadair above in here you said you preferred something like:

``` python
parse_time('today')
```

instead of `parse_time()` as I just PR-ed in #1042 ... 

@wafels would you put the code you used for the plots above in a gist? That would be useful for future testings.

@dpshelio 'today' is ambiguous. Shall we use the datetime standard instead (`parse_time('now')`).

@ehsteve see #1044 

@wafels you considered comparing to [PyEphem](http://rhodesmill.org/pyephem/tutorial.html#computations-for-particular-observers).

No.  I was comparing to the JPL Horizons calculator,
http://ssd.jpl.nasa.gov/?horizons

On Thu, Jun 12, 2014 at 12:06 PM, Steven Christe notifications@github.com
wrote:

> @wafels https://github.com/wafels you considered comparing to PyEphem
> http://rhodesmill.org/pyephem/tutorial.html#computations-for-particular-observers
> .
> 
> ## 
> 
> Reply to this email directly or view it on GitHub
> https://github.com/sunpy/sunpy/issues/472#issuecomment-45912174.

Here is what I get using pyephem. The amplitude seems to be slightly different. @wafels what location on Earth did you use (if any)?
![screen shot 2014-06-13 at 12 41 02 pm 1](https://cloud.githubusercontent.com/assets/739053/3272569/8aa32af6-f319-11e3-8fb6-ef960a99327d.png)

@ehsteve the RA and dec should be independent from the location.

@dpshelio yes you are, of course, right.

http://nbviewer.ipython.org/github/ehsteve/ipython-notebooks/blob/master/Solar%20Ephemeris.ipynb

OK. Nice notebook @ehsteve. So our calculation is wrong? Are we assuming that pyephem is right? I think the decision in the dev meeting was we should probably have this functionality in SunPy and be as accurate as possible.

What are we actually using this ra DEC position for in the code?

@Cadair presumably this functionality would be subsumed into the coordinates update. I think that what @wafels has implemented is probably the way to go.

@ehsteve you mean what @dpshelio has started in #1070?

I don't think this falls into @VaticanCameos's coordinates scope, at least not for now, though I will have a look over #1070 to check that.

This is getting too complicated to follow!

A neat new find. A web service that provides ephemeris info
Check it out!
http://sscweb.gsfc.nasa.gov/WebServices/helio/

and I've found this one today: http://bass2000.obspm.fr/ephem.php which aslo provides a [webservice](http://vo.imcce.fr/webservices/miriade/?ephemph)
They are going to be good for testing all I'm trying to write :)

@dpshelio why write anything if we can get it for free?

@ehsteve ... you may remember this comment the day Earth is hit by a solar storm and there's not internet connection around the world... and you have to calculate whether the next one coming after the first with a lot more strength will or won't hit us... then... just then you will remember the price of "free"  ;)

Since I've now fallen down this rabbit hole, I'll sum up what I've found:
- `sunpy.physics.differential_rotation` is more accurate than `sunpy.sun.sun`
- `sunpy.physics.differential_rotation` has errors in the RA and declination at the level of arcseconds, comparing against the Python library Skyfield (the successor to PyEphem)
- One source of discrepancies with the JPL Horizons calculator can be because it provides RA and declination in the J2000.0 epoch rather than the requested time

for solar position there is now http://docs.astropy.org/en/latest/api/astropy.coordinates.get_sun.html

The one thing the astropy version doesn't do (or at least it's not documented well enough for me to find) is provide other things from the ephemeris (like solar north pole angle wrt celestial north) that are useful for conversion to heliocentric coordinates from RA/dec.

Side note: Is it ever useful to have RA/dec that's **not** in a standard (J2000) epoch? This seems like it's returning highly ambiguous data...

@bwgref yes as far as I am aware there is no solar north functionality in astropy.

On a topic of RA/dec conversion, do you have information on how to do that transformation? and also any knowledge of doing anything like HPC or HG to ICRS conversions by chance?

@Cadair See [the notebook here](https://github.com/NuSTAR/nustar_pysolar/blob/master/convert_to_solar/Convert_To_Solar_Example.ipynb) for the simple way to go from RA/dec (J2000 ) to HPC based on the WCS info in a FITS header. It's a combination of astropy (to get the Sun center as a function of time) and sunpy (to get solar north).

Anything more advanced (i.e. any other solar coordinate systems) is beyond my ken.

@bwgref Do the Python and IDL versions of your conversion scripts agree?

@ayshih Yes. This is effectively a test of whether the combination of the astropy/sunpy ephemeris/north pole matches what I get from JPL Horizons, which I was previously loading in by hand to avoid ambiguities with the SSWIDL get_sun routines. The astropy solar coordinates match Horizons, and the sunpy north pole axis matches what I get from Horizons.

@bwgref Does JPL Horizons or any other source you know of give the position of solar north in ICRS or similar 'fixed' astro frame? 

@Cadair Yes, the JPL Horizons web API can spit out the North Pole location in RA/dec coordinates (I assume that's what you meant?). In principle this can be worked into an API (since you can access JPL Horizons via telnet), but...see your comment to @ayshih above. Though once you have the apparent solar radius, the north pole angle, and the position of the center of the Sun in RA/dec it should be relatively trivial to produce the RA/dec of the north pole, right?

@dpshelio and all. Do we have all the functionality we want now? Or are there still things that need implementing or checking?
pinging @dpshelio and @ayshih on this I guess?
Can I work on this issue @nabobalis ?
Err, probably not? Without a source of equations to implement, there is nothing to do until we get those first. I'd have a look at other issues. 

Resolving patch:
diff --git a/sunpy/sun/sun.py b/sunpy/sun/sun.py
--- a/sunpy/sun/sun.py
+++ b/sunpy/sun/sun.py
@@ -4,21 +4,29 @@
 import numpy as np
 
 import astropy.units as u
-from astropy.coordinates import Angle, Latitude, Longitude
+from astropy.coordinates import Angle, Latitude, Longitude, SkyCoord
+# Versions of Astropy that do not have *MeanEcliptic frames have the same frames
+# with the misleading names *TrueEcliptic
+try:
+    from astropy.coordinates import HeliocentricMeanEcliptic, GeocentricMeanEcliptic
+except ImportError:
+    from astropy.coordinates import HeliocentricTrueEcliptic as HeliocentricMeanEcliptic
+    from astropy.coordinates import GeocentricTrueEcliptic as GeocentricMeanEcliptic
+from astropy import _erfa as erfa
+from astropy.coordinates.builtin_frames.utils import get_jd12
 
 from sunpy.sun import constants
-from sunpy.time import julian_centuries, parse_time
+from sunpy.time import parse_time
 from sunpy.time.time import _variables_for_parse_time_docstring
 from sunpy.util.decorators import add_common_docstring
 
 __all__ = [
-    "print_params", "apparent_declination",
-    "apparent_rightascension", "apparent_obliquity_of_ecliptic", "true_declination",
-    "true_rightascension", "true_obliquity_of_ecliptic", "apparent_latitude", "true_latitude",
-    "apparent_longitude", "true_anomaly", "true_longitude",
-    "equation_of_center", "geometric_mean_longitude", "carrington_rotation_number", "mean_anomaly",
-    "longitude_sun_perigee", "mean_ecliptic_longitude", "eccentricity_sun_earth_orbit", "position",
-    "solar_semidiameter_angular_size", "solar_cycle_number"
+    "solar_cycle_number", "solar_semidiameter_angular_size", "carrington_rotation_number",
+    "position",
+    "true_longitude", "apparent_longitude", "true_latitude", "apparent_latitude",
+    "mean_obliquity_of_ecliptic", "true_rightascension", "true_declination",
+    "true_obliquity_of_ecliptic", "apparent_rightascension", "apparent_declination",
+    "print_params"
 ]
 
 
@@ -51,18 +59,16 @@ def solar_semidiameter_angular_size(t='now'):
     """
     # Import here to avoid a circular import
     from sunpy.coordinates import get_sunearth_distance
-    solar_semidiameter_rad = (constants.radius.to(u.AU)) / get_sunearth_distance(t)
+    solar_semidiameter_rad = constants.radius / get_sunearth_distance(t)
     return Angle(solar_semidiameter_rad.to(u.arcsec, equivalencies=u.dimensionless_angles()))
 
 
 @add_common_docstring(**_variables_for_parse_time_docstring())
-def position(t='now'):
+def position(t='now', equinox_of_date=True):
     """
-    Returns the position of the Sun (right ascension and declination) on the
-    celestial sphere using the equatorial coordinate system.
-
-    .. warning::
-        This function does not use the coordinates framework, so there may be inconsistencies.
+    Returns the apparent position of the Sun (right ascension and declination) on the
+    celestial sphere using the equatorial coordinate system, referred to the true equinox of date
+    (as default).  Corrections for nutation and aberration (for Earth motion) are included.
 
     Parameters
     ----------
@@ -70,88 +76,62 @@ def position(t='now'):
         A time (usually the start time) specified as a parse_time-compatible
         time string, number, or a datetime object.
 
-    Notes
-    -----
-    Based on formulae in "Astronomical Formulae for Calculators" by Meeus
+    equinox_of_date : `bool`
+        If True, output is referred to the true equinox of date.  Otherwise, output is referred to
+        the J2000.0 epoch.
     """
-    ra = true_rightascension(t)
-    dec = true_declination(t)
+    ra = apparent_rightascension(t, equinox_of_date=equinox_of_date)
+    dec = apparent_declination(t, equinox_of_date=equinox_of_date)
     return ra, dec
 
 
 @add_common_docstring(**_variables_for_parse_time_docstring())
-def eccentricity_sun_earth_orbit(t='now'):
+def carrington_rotation_number(t='now'):
     """
-    Returns the eccentricity of the Earth's orbit.
+    Return the Carrington Rotation number.
 
     .. warning::
-        This function does not use the coordinates framework, so there may be inconsistencies.
+        The accuracy of this function is under investigation.
 
     Parameters
     ----------
     t : {parse_time_types}
         A time (usually the start time) specified as a parse_time-compatible
         time string, number, or a datetime object.
-
-    Notes
-    -----
-    Based on formulae in "Astronomical Formulae for Calculators" by Meeus
     """
-    T = julian_centuries(t)
-    result = 0.016751040 - 0.00004180 * T - 0.0000001260 * T**2
+    jd = parse_time(t).jd
+    result = (1. / 27.2753) * (jd - 2398167.0) + 1.0
     return result
 
 
 @add_common_docstring(**_variables_for_parse_time_docstring())
-def mean_ecliptic_longitude(t='now'):
+def true_longitude(t='now'):
     """
-    Returns the mean ecliptic longitude of the Sun.
-
-    .. warning::
-        This function does not use the coordinates framework, so there may be inconsistencies.
+    Returns the Sun's true geometric longitude, referred to the mean equinox of date.  No
+    corrections for nutation or aberration are included.
 
     Parameters
     ----------
     t : {parse_time_types}
         A time (usually the start time) specified as a parse_time-compatible
         time string, number, or a datetime object.
-
-    Notes
-    -----
-    Based on formulae in "Astronomical Formulae for Calculators" by Meeus
     """
-    T = julian_centuries(t)
-    result = 279.696680 + 36000.76892 * T + 0.0003025 * T**2
-    result = result * u.deg
-    return Longitude(result)
-
-
-@add_common_docstring(**_variables_for_parse_time_docstring())
-def longitude_sun_perigee(t='now'):
-    """
-    Returns the current solar perigee.
+    time = parse_time(t)
 
-    .. warning::
-        This function does not return an accurate value.
+    # Calculate Earth's true geometric longitude and add 180 degrees for the Sun's longitude.
+    # This approach is used because Astropy's GeocentricMeanEcliptic includes aberration.
+    earth = SkyCoord(0*u.deg, 0*u.deg, 0*u.AU, frame='gcrs', obstime=time)
+    coord = earth.transform_to(HeliocentricMeanEcliptic(equinox=time))
+    lon = coord.lon + 180*u.deg
 
-    Parameters
-    ----------
-    t : {parse_time_types}
-        A time (usually the start time) specified as a parse_time-compatible
-        time string, number, or a datetime object.
-    """
-    # TODO: FIX THIS
-    return 1
+    return Longitude(lon)
 
 
 @add_common_docstring(**_variables_for_parse_time_docstring())
-def mean_anomaly(t='now'):
+def apparent_longitude(t='now'):
     """
-    Returns the mean anomaly (the angle through which the Sun has moved
-    assuming a circular orbit).
-
-    .. warning::
-        This function does not use the coordinates framework, so there may be inconsistencies.
+    Returns the Sun's apparent longitude, referred to the true equinox of date.  Corrections for
+    nutation and aberration (for Earth motion) are included.
 
     Parameters
     ----------
@@ -161,196 +141,127 @@ def mean_anomaly(t='now'):
 
     Notes
     -----
-    Based on formulae in "Astronomical Formulae for Calculators" by Meeus
+    The nutation model is IAU 2000A nutation with adjustments to match IAU 2006 precession.
     """
-    T = julian_centuries(t)
-    result = 358.475830 + 35999.049750 * T - 0.0001500 * T**2 - 0.00000330 * T**3
-    result = result * u.deg
-    return Longitude(result)
+    time = parse_time(t)
+    sun = SkyCoord(0*u.deg, 0*u.deg, 0*u.AU, frame='hcrs', obstime=time)
+    coord = sun.transform_to(GeocentricMeanEcliptic(equinox=time))
 
+    # Astropy's GeocentricMeanEcliptic already includes aberration, so only add nutation
+    jd1, jd2 = get_jd12(time, 'tt')
+    nut_lon, _ = erfa.nut06a(jd1, jd2)*u.radian
+    lon = coord.lon + nut_lon
 
-@add_common_docstring(**_variables_for_parse_time_docstring())
-def carrington_rotation_number(t='now'):
-    """
-    Return the Carrington Rotation number.
-
-    .. warning::
-        The accuracy of this function is under investigation.
-
-    Parameters
-    ----------
-    t : {parse_time_types}
-        A time (usually the start time) specified as a parse_time-compatible
-        time string, number, or a datetime object.
-    """
-    jd = parse_time(t).jd
-    result = (1. / 27.2753) * (jd - 2398167.0) + 1.0
-    return result
+    return Longitude(lon)
 
 
 @add_common_docstring(**_variables_for_parse_time_docstring())
-def geometric_mean_longitude(t='now'):
+def true_latitude(t='now'):
     """
-    Returns the geometric mean longitude of the Sun.
-
-    .. warning::
-        This function does not use the coordinates framework, so there may be inconsistencies.
+    Returns the Sun's true geometric latitude, referred to the mean equinox of date.  No
+    corrections for nutation or aberration are included.
 
     Parameters
     ----------
     t : {parse_time_types}
         A time (usually the start time) specified as a parse_time-compatible
         time string, number, or a datetime object.
-
-    Notes
-    -----
-    Based on formulae in "Astronomical Formulae for Calculators" by Meeus
-    """
-    T = julian_centuries(t)
-    result = 279.696680 + 36000.76892 * T + 0.0003025 * T**2
-    result = result * u.deg
-    return Longitude(result)
-
-
-@add_common_docstring(**_variables_for_parse_time_docstring())
-def equation_of_center(t='now'):
     """
-    Returns the Sun's equation of center.
-
-    .. warning::
-        This function does not use the coordinates framework, so there may be inconsistencies.
+    time = parse_time(t)
+    sun = SkyCoord(0*u.deg, 0*u.deg, 0*u.AU, frame='hcrs', obstime=time)
+    coord = sun.transform_to(GeocentricMeanEcliptic(equinox=time))
 
-    Parameters
-    ----------
-    t : {parse_time_types}
-        A time (usually the start time) specified as a parse_time-compatible
-        time string, number, or a datetime object.
+    # Astropy's GeocentricMeanEcliptic includes aberration from Earth motion, but the contribution
+    # is negligible
+    lat = coord.lat
 
-    Notes
-    -----
-    Based on formulae in "Astronomical Formulae for Calculators" by Meeus
-    """
-    T = julian_centuries(t)
-    mna = mean_anomaly(t)
-    result = ((1.9194600 - 0.0047890 * T - 0.0000140 * T**2) * np.sin(mna) +
-              (0.0200940 - 0.0001000 * T) * np.sin(2 * mna) + 0.0002930 * np.sin(3 * mna))
-    result = result * u.deg
-    return Angle(result)
+    return Latitude(lat)
 
 
 @add_common_docstring(**_variables_for_parse_time_docstring())
-def true_longitude(t='now'):
+def apparent_latitude(t='now'):
     """
-    Returns the Sun's true geometric longitude.
-
-    Referred to the mean equinox of date.
-
-    .. warning::
-        This function does not use the coordinates framework, so there may be inconsistencies.
+    Returns the Sun's apparent latitude, referred to the true equinox of date.  Corrections for
+    nutation and aberration (for Earth motion) are included.
 
     Parameters
     ----------
     t : {parse_time_types}
         A time (usually the start time) specified as a parse_time-compatible
         time string, number, or a datetime object.
-
-    Notes
-    -----
-    Based on formulae in "Astronomical Formulae for Calculators" by Meeus
-    """
-    # TODO: Should the higher accuracy terms from which app_long is derived be added to true_long?
-    result = equation_of_center(t) + geometric_mean_longitude(t)
-    return Longitude(result)
-
-
-@add_common_docstring(**_variables_for_parse_time_docstring())
-def true_anomaly(t='now'):
     """
-    Returns the Sun's true anomaly.
+    time = parse_time(t)
+    sun = SkyCoord(0*u.deg, 0*u.deg, 0*u.AU, frame='hcrs', obstime=time)
+    coord = sun.transform_to(GeocentricMeanEcliptic(equinox=time))
 
-    .. warning::
-        This function does not use the coordinates framework, so there may be inconsistencies.
+    # Astropy's GeocentricMeanEcliptic does not include nutation, but the contribution is negligible
+    lat = coord.lat
 
-    Parameters
-    ----------
-    t : {parse_time_types}
-        A time (usually the start time) specified as a parse_time-compatible
-        time string, number, or a datetime object.
-
-    Notes
-    -----
-    Based on formulae in "Astronomical Formulae for Calculators" by Meeus
-    """
-    result = mean_anomaly(t) + equation_of_center(t)
-    return Longitude(result)
+    return Latitude(lat)
 
 
 @add_common_docstring(**_variables_for_parse_time_docstring())
-def apparent_longitude(t='now'):
+def mean_obliquity_of_ecliptic(t='now'):
     """
-    Returns the apparent longitude of the Sun.
-
-    .. warning::
-        This function does not use the coordinates framework, so there may be inconsistencies.
+    Returns the mean obliquity of the ecliptic, using the IAU 2006 definition.  No correction for
+    nutation is included.
 
     Parameters
     ----------
     t : {parse_time_types}
         A time (usually the start time) specified as a parse_time-compatible
         time string, number, or a datetime object.
-
-    Notes
-    -----
-    Based on formulae in "Astronomical Formulae for Calculators" by Meeus
     """
-    T = julian_centuries(t)
-    omega = (259.18 - 1934.142 * T) * u.deg
-    true_long = true_longitude(t)
-    result = true_long - (0.00569 - 0.00479 * np.sin(omega)) * u.deg
-    return Longitude(result)
+    time = parse_time(t)
+    jd1, jd2 = get_jd12(time, 'tt')
+    obl = erfa.obl06(jd1, jd2)*u.radian
+    return Angle(obl, u.arcsec)
 
 
 @add_common_docstring(**_variables_for_parse_time_docstring())
-def true_latitude(t='now'):
+def true_rightascension(t='now', equinox_of_date=True):
     """
-    Returns the true latitude of the Sun.
-
-    Never more than 1.2 arcsec from 0, set to 0 here.
+    Returns the Sun's true geometric right ascension relative to Earth, referred to the mean equinox
+    of date (as default).  No corrections for nutation or aberration are included.  The correction
+    due to light travel time would be negligible, so the output is also the astrometric right
+    ascension.
 
     Parameters
     ----------
     t : {parse_time_types}
         A time (usually the start time) specified as a parse_time-compatible
         time string, number, or a datetime object.
-    """
-    # TODO: FIX THIS
-    return Latitude(0.0 * u.deg)
 
-
-@add_common_docstring(**_variables_for_parse_time_docstring())
-def apparent_latitude(t='now'):
+    equinox_of_date : `bool`
+        If True, output is referred to the mean equinox of date.  Otherwise, output is referred to
+        the J2000.0 epoch.
     """
-    Returns the apparent latitude of the Sun.
+    if equinox_of_date:
+        # Mean equinox of date
+        obl = mean_obliquity_of_ecliptic(t)  # excludes nutation
+        lon = true_longitude(t)
+        lat = true_latitude(t)
 
-    Set to 0 here.
+        # See Astronomical Algorithms (Meeus 1998 p.93)
+        y = np.sin(lon) * np.cos(obl) - np.tan(lat) * np.sin(obl)
+        x = np.cos(lon)
+        result = np.arctan2(y, x)
+    else:
+        # J2000.0 epoch
+        # Calculate Earth's true geometric right ascension relative to the Sun and add 180 degrees.
+        # This approach is used because Astropy's GCRS includes aberration.
+        earth = SkyCoord(0*u.deg, 0*u.deg, 0*u.AU, frame='gcrs', obstime=parse_time(t))
+        result = earth.hcrs.ra + 180*u.deg
 
-    Parameters
-    ----------
-    t : {parse_time_types}
-        A time (usually the start time) specified as a parse_time-compatible
-        time string, number, or a datetime object.
-    """
-    # TODO: FIX THIS
-    return Latitude(0.0 * u.deg)
+    return Longitude(result, u.hourangle)
 
 
 @add_common_docstring(**_variables_for_parse_time_docstring())
-def true_obliquity_of_ecliptic(t='now'):
+def true_declination(t='now', equinox_of_date=True):
     """
-    Returns the true obliquity of the ecliptic.
-
-    .. warning::
-        This function does not use the coordinates framework, so there may be inconsistencies.
+    Returns the Sun's true geometric declination relative to Earth, referred to the mean equinox
+    of date (as default).  No corrections for nutation or aberration are included.  The correction
+    due to light travel time would be negligible, so the output is also the astrometric declination.
 
     Parameters
     ----------
@@ -358,46 +269,33 @@ def true_obliquity_of_ecliptic(t='now'):
         A time (usually the start time) specified as a parse_time-compatible
         time string, number, or a datetime object.
 
-    Notes
-    -----
-    Based on formulae in "Astronomical Formulae for Calculators" by Meeus
+    equinox_of_date : `bool`
+        If True, output is referred to the mean equinox of date.  Otherwise, output is referred to
+        the J2000.0 epoch.
     """
-    T = julian_centuries(t)
-    result = 23.452294 - 0.0130125 * T - 0.00000164 * T**2 + 0.000000503 * T**3
-    return Angle(result, u.deg)
+    if equinox_of_date:
+        # Mean equinox of date
+        obl = mean_obliquity_of_ecliptic(t)  # excludes nutation
+        lon = true_longitude(t)
+        lat = true_latitude(t)
 
+        # See Astronomical Algorithms (Meeus 1998 p.93)
+        result = np.arcsin(np.sin(lat) * np.cos(obl) + np.cos(lat) * np.sin(obl) * np.sin(lon))
+    else:
+        # J2000.0 epoch
+        # Calculate Earth's true geometric declination relative to the Sun and multipy by -1.
+        # This approach is used because Astropy's GCRS includes aberration.
+        earth = SkyCoord(0*u.deg, 0*u.deg, 0*u.AU, frame='gcrs', obstime=parse_time(t))
+        result = -earth.hcrs.dec
 
-@add_common_docstring(**_variables_for_parse_time_docstring())
-def true_rightascension(t='now'):
-    """
-    Return the true right ascension of the Sun.
-
-    .. warning::
-        This function does not use the coordinates framework, so there may be inconsistencies.
-
-    Parameters
-    ----------
-    t : {parse_time_types}
-        A time (usually the start time) specified as a parse_time-compatible
-        time string, number, or a datetime object.
-
-    Notes
-    -----
-    Based on formulae in "Astronomical Formulae for Calculators" by Meeus
-    """
-    y = np.cos(true_obliquity_of_ecliptic(t)) * np.sin(true_longitude(t))
-    x = np.cos(true_longitude(t))
-    true_ra = np.arctan2(y, x)
-    return Longitude(true_ra.to(u.hourangle))
+    return Latitude(result, u.deg)
 
 
 @add_common_docstring(**_variables_for_parse_time_docstring())
-def true_declination(t='now'):
+def true_obliquity_of_ecliptic(t='now'):
     """
-    Return the true declination of the Sun.
-
-    .. warning::
-        This function does not use the coordinates framework, so there may be inconsistencies.
+    Returns the true obliquity of the ecliptic, using the IAU 2006 definition.  Correction for
+    nutation is included.
 
     Parameters
     ----------
@@ -407,19 +305,21 @@ def true_declination(t='now'):
 
     Notes
     -----
-    Based on formulae in "Astronomical Formulae for Calculators" by Meeus
+    The nutation model is IAU 2000A nutation with adjustments to match IAU 2006 precession.
     """
-    result = np.arcsin(np.sin(true_obliquity_of_ecliptic(t)) * np.sin(apparent_longitude(t)))
-    return Latitude(result.to(u.deg))
+    time = parse_time(t)
+    jd1, jd2 = get_jd12(time, 'tt')
+    obl = erfa.obl06(jd1, jd2)*u.radian
+    _, nut_obl = erfa.nut06a(jd1, jd2)*u.radian
+    obl += nut_obl
+    return Angle(obl, u.arcsec)
 
 
 @add_common_docstring(**_variables_for_parse_time_docstring())
-def apparent_obliquity_of_ecliptic(t='now'):
+def apparent_rightascension(t='now', equinox_of_date=True):
     """
-    Return the apparent obliquity of the ecliptic.
-
-    .. warning::
-        This function does not use the coordinates framework, so there may be inconsistencies.
+    Returns the Sun's apparent right ascension relative to Earth, referred to the true equinox
+    of date (as default).  Corrections for nutation or aberration (for Earth motion) are included.
 
     Parameters
     ----------
@@ -427,46 +327,33 @@ def apparent_obliquity_of_ecliptic(t='now'):
         A time (usually the start time) specified as a parse_time-compatible
         time string, number, or a datetime object.
 
-    Notes
-    -----
-    Based on formulae in "Astronomical Formulae for Calculators" by Meeus
-    """
-    omega = apparent_longitude(t)
-    result = true_obliquity_of_ecliptic(t) + (0.00256 * np.cos(omega)) * u.deg
-    return result
-
-
-@add_common_docstring(**_variables_for_parse_time_docstring())
-def apparent_rightascension(t='now'):
+    equinox_of_date : `bool`
+        If True, output is referred to the true equinox of date.  Otherwise, output is referred to
+        the J2000.0 epoch.
     """
-    Returns the apparent right ascension of the Sun.
-
-    .. warning::
-        This function does not use the coordinates framework, so there may be inconsistencies.
+    if equinox_of_date:
+        # True equinox of date
+        obl = true_obliquity_of_ecliptic(t)  # includes nutation
+        lon = apparent_longitude(t)
+        lat = apparent_latitude(t)
 
-    Parameters
-    ----------
-    t : {parse_time_types}
-        A time (usually the start time) specified as a parse_time-compatible
-        time string, number, or a datetime object.
+        # See Astronomical Algorithms (Meeus 1998 p.93)
+        y = np.sin(lon) * np.cos(obl) - np.tan(lat) * np.sin(obl)
+        x = np.cos(lon)
+        result = np.arctan2(y, x)
+    else:
+        # J2000.0 epoch
+        sun = SkyCoord(0*u.deg, 0*u.deg, 0*u.AU, frame='hcrs', obstime=parse_time(t))
+        result = sun.gcrs.ra
 
-    Notes
-    -----
-    Based on formulae in "Astronomical Formulae for Calculators" by Meeus
-    """
-    y = np.cos(apparent_obliquity_of_ecliptic(t)) * np.sin(apparent_longitude(t))
-    x = np.cos(apparent_longitude(t))
-    app_ra = np.arctan2(y, x)
-    return Longitude(app_ra.to(u.hourangle))
+    return Longitude(result, u.hourangle)
 
 
 @add_common_docstring(**_variables_for_parse_time_docstring())
-def apparent_declination(t='now'):
+def apparent_declination(t='now', equinox_of_date=True):
     """
-    Returns the apparent declination of the Sun.
-
-    .. warning::
-        This function does not use the coordinates framework, so there may be inconsistencies.
+    Returns the Sun's apparent declination relative to Earth, referred to the true equinox
+    of date (as default).  Corrections for nutation or aberration (for Earth motion) are included.
 
     Parameters
     ----------
@@ -474,20 +361,33 @@ def apparent_declination(t='now'):
         A time (usually the start time) specified as a parse_time-compatible
         time string, number, or a datetime object.
 
-    Notes
-    -----
-    Based on formulae in "Astronomical Formulae for Calculators" by Meeus
+    equinox_of_date : `bool`
+        If True, output is referred to the true equinox of date.  Otherwise, output is referred to
+        the J2000.0 epoch.
     """
-    ob = apparent_obliquity_of_ecliptic(t)
-    app_long = apparent_longitude(t)
-    result = np.arcsin(np.sin(ob)) * np.sin(app_long)
-    return Latitude(result.to(u.deg))
+    if equinox_of_date:
+        # True equinox of date
+        obl = true_obliquity_of_ecliptic(t)  # includes nutation
+        lon = apparent_longitude(t)
+        lat = apparent_latitude(t)
+
+        # See Astronomical Algorithms (Meeus 1998 p.93)
+        result = np.arcsin(np.sin(lat) * np.cos(obl) + np.cos(lat) * np.sin(obl) * np.sin(lon))
+    else:
+        # J2000.0 epoch
+        sun = SkyCoord(0*u.deg, 0*u.deg, 0*u.AU, frame='hcrs', obstime=parse_time(t))
+        result = sun.gcrs.dec
+
+    return Latitude(result, u.deg)
 
 
 @add_common_docstring(**_variables_for_parse_time_docstring())
 def print_params(t='now'):
     """
-    Print out a summary of Solar ephemeris.
+    Print out a summary of solar ephemeris. 'True' values are true geometric values referred to the
+    mean equinox of date, with no corrections for nutation or aberration.  'Apparent' values are
+    referred to the true equinox of date, with corrections for nutation and aberration (for Earth
+    motion).
 
     Parameters
     ----------
@@ -495,19 +395,22 @@ def print_params(t='now'):
         A time (usually the start time) specified as a parse_time-compatible
         time string, number, or a datetime object.
     """
-    # import here to avoid circular import
+    # Import here to avoid circular import
     from sunpy.coordinates.ephemeris import (get_sun_L0, get_sun_B0,
                                              get_sun_P, get_sunearth_distance)
 
     print('Solar Ephemeris for {} UTC\n'.format(parse_time(t).utc))
     print('Distance = {}'.format(get_sunearth_distance(t)))
     print('Semidiameter = {}'.format(solar_semidiameter_angular_size(t)))
-    print('True (long, lat) = ({}, {})'.format(true_longitude(t), true_latitude(t)))
-    print('Apparent (long, lat) = ({}, {})'.format(apparent_longitude(t), apparent_latitude(t)))
-    print('True (RA, Dec) = ({}, {})'.format(true_rightascension(t), true_declination(t)))
-    print('Apparent (RA, Dec) = ({}, {})'.format(apparent_rightascension(t),
-                                                 apparent_declination(t)))
-    print('Heliographic long. and lat of disk center = ({}, {})'.format(get_sun_L0(t),
-                                                                        get_sun_B0(t)))
-    print('Position angle of north pole in = {}'.format(get_sun_P(t)))
+    print('True (long, lat) = ({}, {})'.format(true_longitude(t).to_string(),
+                                               true_latitude(t).to_string()))
+    print('Apparent (long, lat) = ({}, {})'.format(apparent_longitude(t).to_string(),
+                                                   apparent_latitude(t).to_string()))
+    print('True (RA, Dec) = ({}, {})'.format(true_rightascension(t).to_string(),
+                                             true_declination(t).to_string()))
+    print('Apparent (RA, Dec) = ({}, {})'.format(apparent_rightascension(t).to_string(),
+                                                 apparent_declination(t).to_string()))
+    print('Heliographic long. and lat of disk center = ({}, {})'.format(get_sun_L0(t).to_string(),
+                                                                        get_sun_B0(t).to_string()))
+    print('Position angle of north pole = {}'.format(get_sun_P(t)))
     print('Carrington Rotation Number = {}'.format(carrington_rotation_number(t)))


Test patch:
diff --git a/sunpy/instr/tests/test_fermi.py b/sunpy/instr/tests/test_fermi.py
--- a/sunpy/instr/tests/test_fermi.py
+++ b/sunpy/instr/tests/test_fermi.py
@@ -24,35 +24,35 @@ def test_detector_angles():
     file = fermi.download_weekly_pointing_file(date)
     det = fermi.get_detector_sun_angles_for_date(date, file)
     assert len(det) == 13
-    assert_almost_equal(det['n0'][0].value, 21.73944, decimal=1)
-    assert_almost_equal(det['n1'][0].value, 30.62983, decimal=1)
-    assert_almost_equal(det['n2'][0].value, 74.67486, decimal=1)
-    assert_almost_equal(det['n3'][0].value, 30.46062, decimal=1)
-    assert_almost_equal(det['n4'][0].value, 73.89734, decimal=1)
-    assert_almost_equal(det['n5'][0].value, 58.99893, decimal=1)
-    assert_almost_equal(det['n6'][0].value, 47.31091, decimal=1)
-    assert_almost_equal(det['n7'][0].value, 70.63391, decimal=1)
-    assert_almost_equal(det['n8'][0].value, 106.30992, decimal=1)
-    assert_almost_equal(det['n9'][0].value, 70.07033, decimal=1)
-    assert_almost_equal(det['n10'][0].value, 106.97884, decimal=1)
-    assert_almost_equal(det['n11'][0].value, 121.09603, decimal=1)
+    assert_almost_equal(det['n0'][0].value, 21.79, decimal=1)
+    assert_almost_equal(det['n1'][0].value, 30.45, decimal=1)
+    assert_almost_equal(det['n2'][0].value, 74.44, decimal=1)
+    assert_almost_equal(det['n3'][0].value, 30.58, decimal=1)
+    assert_almost_equal(det['n4'][0].value, 73.93, decimal=1)
+    assert_almost_equal(det['n5'][0].value, 58.78, decimal=1)
+    assert_almost_equal(det['n6'][0].value, 47.56, decimal=1)
+    assert_almost_equal(det['n7'][0].value, 70.89, decimal=1)
+    assert_almost_equal(det['n8'][0].value, 106.54, decimal=1)
+    assert_almost_equal(det['n9'][0].value, 70.17, decimal=1)
+    assert_almost_equal(det['n10'][0].value, 106.95, decimal=1)
+    assert_almost_equal(det['n11'][0].value, 121.32, decimal=1)
 
     det2 = fermi.get_detector_sun_angles_for_time(
         parse_time('2012-02-15 02:00'), file)
     assert len(det2) == 13
     assert type(det2) == dict
-    assert_almost_equal(det2['n0'].value, 83.76092, decimal=1)
-    assert_almost_equal(det2['n1'].value, 66.65847, decimal=1)
-    assert_almost_equal(det2['n10'].value, 123.28952, decimal=1)
-    assert_almost_equal(det2['n11'].value, 170.69869, decimal=1)
-    assert_almost_equal(det2['n2'].value, 58.78532, decimal=1)
-    assert_almost_equal(det2['n3'].value, 66.69068, decimal=1)
-    assert_almost_equal(det2['n4'].value, 57.16402, decimal=1)
-    assert_almost_equal(det2['n5'].value, 9.04924, decimal=1)
-    assert_almost_equal(det2['n6'].value, 112.21230, decimal=1)
-    assert_almost_equal(det2['n7'].value, 127.35783, decimal=1)
-    assert_almost_equal(det2['n8'].value, 122.98894, decimal=1)
-    assert_almost_equal(det2['n9'].value, 126.95987, decimal=1)
+    assert_almost_equal(det2['n0'].value, 83.54, decimal=1)
+    assert_almost_equal(det2['n1'].value, 66.50, decimal=1)
+    assert_almost_equal(det2['n10'].value, 123.39, decimal=1)
+    assert_almost_equal(det2['n11'].value, 170.89, decimal=1)
+    assert_almost_equal(det2['n2'].value, 58.84, decimal=1)
+    assert_almost_equal(det2['n3'].value, 66.44, decimal=1)
+    assert_almost_equal(det2['n4'].value, 57.06, decimal=1)
+    assert_almost_equal(det2['n5'].value, 8.85, decimal=1)
+    assert_almost_equal(det2['n6'].value, 111.95, decimal=1)
+    assert_almost_equal(det2['n7'].value, 127.12, decimal=1)
+    assert_almost_equal(det2['n8'].value, 122.93, decimal=1)
+    assert_almost_equal(det2['n9'].value, 126.82, decimal=1)
 
 
 def test_met_to_utc():
diff --git a/sunpy/sun/tests/test_sun.py b/sunpy/sun/tests/test_sun.py
--- a/sunpy/sun/tests/test_sun.py
+++ b/sunpy/sun/tests/test_sun.py
@@ -1,3 +1,5 @@
+from astropy.coordinates import Angle
+from astropy.time import Time
 import astropy.units as u
 from astropy.tests.helper import assert_quantity_allclose
 
@@ -5,35 +7,27 @@
 
 
 def test_true_longitude():
-    # source: http://www.satellite-calculations.com/Satellite/suncalc.htm
-    # values are deviating a little because of lack of time parameter in
-    # true_longitude function
-    assert_quantity_allclose(sun.true_longitude("2002/12/23"), 270.978 * u.deg, atol=1.1 * u.deg)
-    assert_quantity_allclose(sun.true_longitude("2003/01/29"), 308.661 * u.deg, atol=1.1 * u.deg)
-    assert_quantity_allclose(sun.true_longitude("2004/05/12"), 51.617 * u.deg, atol=1.1 * u.deg)
-    assert_quantity_allclose(sun.true_longitude("2006/07/04"), 101.910 * u.deg, atol=1.1 * u.deg)
-    assert_quantity_allclose(sun.true_longitude("2007/09/16"), 172.767 * u.deg, atol=1.1 * u.deg)
-    assert_quantity_allclose(sun.true_longitude("2009/02/11"), 322.394 * u.deg, atol=1.1 * u.deg)
+    # Validate against a published value from the Astronomical Almanac (1992)
+    t = Time('1992-10-13', scale='tdb')
+    assert_quantity_allclose(sun.true_longitude(t), Angle('199d54m26.17s'), atol=0.1*u.arcsec)
 
 
-def test_apparent_declination():
-    assert_quantity_allclose(sun.apparent_declination("2002/12/22"), -22.964 * u.deg, atol=1 * u.deg)
-    assert_quantity_allclose(sun.apparent_declination("2003/1/12"), -21.743 * u.deg, atol=1 * u.deg)
-    assert_quantity_allclose(sun.apparent_declination("2004/02/13"), -13.478 * u.deg, atol=1 * u.deg)
-    assert_quantity_allclose(sun.apparent_declination("2005/12/3"), -22.152 * u.deg, atol=1 * u.deg)
-    assert_quantity_allclose(sun.apparent_declination("2013/02/26"), -8.547 * u.deg, atol=1 * u.deg)
-    assert_quantity_allclose(sun.apparent_declination("2014/05/1"), 15.141 * u.deg, atol=1 * u.deg)
+def test_apparent_longitude():
+    # Validate against a published value from the Astronomical Almanac (1992)
+    t = Time('1992-10-13', scale='tdb')
+    assert_quantity_allclose(sun.apparent_longitude(t), Angle('199d54m21.56s'), atol=0.1*u.arcsec)
+
 
+def test_true_latitude():
+    # Validate against a published value from the Astronomical Almanac (1992)
+    t = Time('1992-10-13', scale='tdb')
+    assert_quantity_allclose(sun.true_latitude(t), Angle('0.72s'), atol=0.05*u.arcsec)
 
-def test_mean_anomaly():
-    assert_quantity_allclose(sun.mean_anomaly("2002/12/12"), 337.538 * u.deg, atol=1 * u.deg)
-    assert_quantity_allclose(sun.mean_anomaly("2003/03/25"), 79.055 * u.deg, atol=1 * u.deg)
-    assert_quantity_allclose(sun.mean_anomaly("2005/06/05"), 150.492 * u.deg, atol=1 * u.deg)
-    assert_quantity_allclose(sun.mean_anomaly("2006/11/17"), 312.860 * u.deg, atol=1 * u.deg)
-    assert_quantity_allclose(sun.mean_anomaly("2008/07/29"), 203.933 * u.deg, atol=1 * u.deg)
-    assert_quantity_allclose(sun.mean_anomaly("2011/01/31"), 26.742 * u.deg, atol=1 * u.deg)
 
-# These values are tested from the functions after the integration of astropy.units
+def test_apparent_latitude():
+    # Validate against a published value from the Astronomical Almanac (1992)
+    t = Time('1992-10-13', scale='tdb')
+    assert_quantity_allclose(sun.apparent_latitude(t), Angle('0.72s'), atol=0.05*u.arcsec)
 
 
 def test_solar_cycle_number():
@@ -48,58 +42,67 @@ def test_solar_semidiameter_angular_size():
     assert_quantity_allclose(sun.solar_semidiameter_angular_size("2001/07/21"), 944.039007 * u.arcsec, atol=1e-3 * u.arcsec)
 
 
-def test_mean_ecliptic_longitude():
-    assert_quantity_allclose(sun.mean_ecliptic_longitude("2012/11/11"), 230.544 * u.deg, atol=1e-3 * u.deg)
-    assert_quantity_allclose(sun.mean_ecliptic_longitude("2101/04/29"), 36.811 * u.deg, atol=1e-3 * u.deg)
-    assert_quantity_allclose(sun.mean_ecliptic_longitude("2003/09/15"), 173.554 * u.deg, atol=1e-3 * u.deg)
+def test_mean_obliquity_of_ecliptic():
+    t = Time('1992-10-13', scale='tdb')
+    assert_quantity_allclose(sun.mean_obliquity_of_ecliptic(t), 84384.8*u.arcsec, atol=0.1*u.arcsec)
 
 
-def test_equation_of_center():
-    assert_quantity_allclose(sun.equation_of_center("2012/11/11"), -1.540 * u.deg, atol=1e-3 * u.deg)
-    assert_quantity_allclose(sun.equation_of_center("2014/05/27"), 1.178 * u.deg, atol=1e-3 * u.deg)
-    assert_quantity_allclose(sun.equation_of_center("2134/01/01"), -0.161 * u.deg, atol=1e-3 * u.deg)
+def test_true_rightascension():
+    assert_quantity_allclose(sun.true_rightascension("2012/11/11"), 226.548*u.deg, atol=1e-3*u.deg)
+    assert_quantity_allclose(sun.true_rightascension("2142/02/03"), 316.466*u.deg, atol=1e-3*u.deg)
+    assert_quantity_allclose(sun.true_rightascension("2013/12/11"), 258.150*u.deg, atol=1e-3*u.deg)
 
 
-def test_true_anomaly():
-    assert_quantity_allclose(sun.true_anomaly("2012/11/11"), 305.842 * u.deg, atol=1e-3 * u.deg)
-    assert_quantity_allclose(sun.true_anomaly("2242/06/29"), 170.010 * u.deg, atol=1e-3 * u.deg)
-    assert_quantity_allclose(sun.true_anomaly("2020/01/01"), 356.735 * u.deg, atol=1e-3 * u.deg)
+def test_true_rightascension_J2000():
+    # Validate against JPL HORIZONS output
+    t = Time('1992-10-13', scale='tdb')
+    assert_quantity_allclose(sun.true_rightascension(t, equinox_of_date=False),
+                             Angle('13h13m53.65s'), atol=0.01*u.arcsec)
 
 
-def test_apparent_longitude():
-    assert_quantity_allclose(sun.apparent_longitude("2012/11/11"), 228.994 * u.deg, atol=1e-3 * u.deg)
-    assert_quantity_allclose(sun.apparent_longitude("2014/05/27"), 65.648 * u.deg, atol=1e-3 * u.deg)
-    assert_quantity_allclose(sun.apparent_longitude("2134/02/12"), 323.066 * u.deg, atol=1e-3 * u.deg)
+def test_true_declination():
+    assert_quantity_allclose(sun.true_declination("2012/11/11"), -17.470*u.deg, atol=1e-3*u.deg)
+    assert_quantity_allclose(sun.true_declination("2245/12/01"), -21.717*u.deg, atol=1e-3*u.deg)
+    assert_quantity_allclose(sun.true_declination("2014/05/27"), 21.245*u.deg, atol=1e-3*u.deg)
+
+
+def test_true_declination_J2000():
+    # Validate against JPL HORIZONS output
+    t = Time('1992-10-13', scale='tdb')
+    assert_quantity_allclose(sun.true_declination(t, equinox_of_date=False),
+                             Angle('-7d49m20.8s'), atol=0.05*u.arcsec)
 
 
 def test_true_obliquity_of_ecliptic():
-    assert_quantity_allclose(sun.true_obliquity_of_ecliptic("2012/11/11"), 23.437 * u.deg, atol=1e-3 * u.deg)
-    assert_quantity_allclose(sun.true_obliquity_of_ecliptic("2132/12/29"), 23.421 * u.deg, atol=1e-3 * u.deg)
-    assert_quantity_allclose(sun.true_obliquity_of_ecliptic("2002/03/15"), 23.438 * u.deg, atol=1e-3 * u.deg)
+    t = Time('1992-10-13', scale='tdb')
+    assert_quantity_allclose(sun.true_obliquity_of_ecliptic(t), 84384.5*u.arcsec, atol=0.1*u.arcsec)
 
 
-def test_true_rightasenscion():
-    assert_quantity_allclose(sun.true_rightascension("2012/11/11"), 226.550 * u.deg, atol=1e-3 * u.deg)
-    assert_quantity_allclose(sun.true_rightascension("2142/02/03"), 316.466 * u.deg, atol=1e-3 * u.deg)
-    assert_quantity_allclose(sun.true_rightascension("2013/12/11"), 258.150 * u.deg, atol=1e-3 * u.deg)
+def test_apparent_rightascension():
+    # Validate against a published value from the Astronomical Almanac (1992)
+    t = Time('1992-10-13', scale='tdb')
+    assert_quantity_allclose(sun.apparent_rightascension(t), Angle('13h13m30.749s'),
+                             atol=0.01*u.arcsec)
 
 
-def test_true_declination():
-    assert_quantity_allclose(sun.true_declination("2012/11/11"), -17.467 * u.deg, atol=1e-3 * u.deg)
-    assert_quantity_allclose(sun.true_declination("2245/12/01"), -21.717 * u.deg, atol=1e-3 * u.deg)
-    assert_quantity_allclose(sun.true_declination("2014/05/27"), 21.245 * u.deg, atol=1e-3 * u.deg)
+def test_apparent_rightascension_J2000():
+    # Regression-only test
+    t = Time('1992-10-13', scale='tdb')
+    assert_quantity_allclose(sun.apparent_rightascension(t, equinox_of_date=False),
+                             Angle('13h13m52.37s'), atol=0.01*u.arcsec)
 
 
-def test_apparent_obliquity_of_ecliptic():
-    assert_quantity_allclose(sun.apparent_obliquity_of_ecliptic("2012/11/11"), 23.435 * u.deg, atol=1e-3 * u.deg)
-    assert_quantity_allclose(sun.apparent_obliquity_of_ecliptic("2014/05/27"), 23.438 * u.deg, atol=1e-3 * u.deg)
-    assert_quantity_allclose(sun.apparent_obliquity_of_ecliptic("2412/02/26"), 23.388 * u.deg, atol=1e-3 * u.deg)
+def test_apparent_declination():
+    # Validate against a published value from the Astronomical Almanac (1992)
+    t = Time('1992-10-13', scale='tdb')
+    assert_quantity_allclose(sun.apparent_declination(t), Angle('-7d47m01.74s'), atol=0.05*u.arcsec)
 
 
-def test_apparent_rightascension():
-    assert_quantity_allclose(sun.apparent_rightascension("2012/11/11"), 15.103 * u.hourangle, atol=1e-3 * u.hourangle)
-    assert_quantity_allclose(sun.apparent_rightascension("2013/12/13"), 17.356 * u.hourangle, atol=1e-3 * u.hourangle)
-    assert_quantity_allclose(sun.apparent_rightascension("2512/04/09"), 1.196 * u.hourangle, atol=1e-3 * u.hourangle)
+def test_apparent_declination_J2000():
+    # Regression-only test
+    t = Time('1992-10-13', scale='tdb')
+    assert_quantity_allclose(sun.apparent_declination(t, equinox_of_date=False),
+                             Angle('-7d49m13.09s'), atol=0.05*u.arcsec)
 
 
 def test_print_params():