question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Astropy 4.3+ Produces Inaccurate Range Predictions via AltAz Calc

See original GitHub issue

Description

We regularly compare our radar Range measurements to ILRS ephems. Upon upgrading to Astropy 5.1, we started seeing very large residuals. We’ve tried different versions and found astropy 4.2 gives expected agreement, while astropy 4.3 and later give the unexpected behavior.

We believe that the astropy 4.3+ predictions are in error because we have internal residual analysis and comparison to other data sources (not using astropy) that do not show this issue.

Expected behavior

When we run it with astropy 4.2, we get nice small residuals like this:

(astropy5) mas@ip-192-168-4-110 scripts % python astropy_snippet_20220608.py
	Calculated measurement residual
		range: 0.1m
	Calculated measurement residual
		range: 12.4m
	Calculated measurement residual
		range: 17.8m

Actual behavior

When we run it with astropy 4.3, we get great big residuals like this:

(astropy5) mas@ip-192-168-4-110 scripts % python astropy_snippet_20220608.py
	Calculated measurement residual
		range: -112.2m
	Calculated measurement residual
		range: -99.9m
	Calculated measurement residual
		range: -94.4m

Steps to Reproduce

  1. Get some radar Range measurements
  2. Get ILRS Ephem predictions
  3. Create an EarthLocation for the radar location.
  4. Interpolate the ILRS ephem for every measurement timestamp.
  5. Create a SkyCoord object for the interpolated position.
  6. Do an AltAz transformation to get the Range prediction.
import numpy as np
import scipy.interpolate
import datetime
import dateutil.parser

import astropy.time, astropy.coordinates
import astropy.units as u
from astropy.utils import iers
iers.conf.iers_auto_url='https://maia.usno.navy.mil/ser7/finals2000A.all'

# Instrument:
inst = {
    'longitude': -85.479833,
    'latitude': 10.413333,
    'altitude': 23.0,
    }

measurements = [
    {
        'timestamp_measurement': dateutil.parser.parse('2022-06-08 08:18:45.103596+00'),
        'range_value': 1813723.24341158,
    },
    {
        'timestamp_measurement': dateutil.parser.parse('2022-06-08 08:18:44.983595+00'),
        'range_value':  1813538.3470108,
    },
    {
        'timestamp_measurement': dateutil.parser.parse('2022-06-08 08:18:44.926049+00'),
        'range_value':  1813449.3366306,
    },
]

ilrs_mjd = 59738
ilrs_secs = np.array([
    27900.00000, 28080.00000, 28260.00000, 28440.00000, 28620.00000,
    28800.00000, 28980.00000, 29160.00000, 29340.00000, 29520.00000,
    29700.00000, 29880.00000, 30060.00000, 30240.00000, 30420.00000,
    30600.00000, 30780.00000, 30960.00000, 31140.00000, 31320.00000,
    31500.00000, 31680.00000, 31860.00000, 32040.00000, 32220.00000,
    ])

ilrs_data = np.array([
    [-2741944.579,   -235689.755,  -7325387.829],
    [-2711657.122,  -1474364.598,  -7189654.207],
    [-2641154.833,  -2675083.522,  -6860757.255],
    [-2530855.876,  -3806852.586,  -6347386.337],
    [-2381441.653,  -4840435.015,  -5663181.834],
    [-2193903.565,  -5749124.122,  -4826398.133],
    [-1969601.044,  -6509460.381,  -3859440.304],
    [-1710326.586,  -7101871.185,  -2788282.056],
    [-1418372.400,  -7511212.894,  -1641776.504],
    [-1096593.106,  -7727194.734,   -450875.156],
    [ -748458.835,  -7744665.880,    752222.831],
    [ -378094.716,  -7563753.660,   1934963.517],
    [    9698.097,  -7189847.764,   3065344.786],
    [  409443.848,  -6633429.388,   4112807.145],
    [  815017.796,  -5909751.857,   5049077.091],
    [ 1219697.263,  -5038388.983,   5848936.440],
    [ 1616238.610,  -4042669.245,   6490897.504],
    [ 1996980.100,  -2949016.560,   6957766.909],
    [ 2353970.392,  -1786221.732,   7237086.985],
    [ 2679123.360,   -584665.510,   7321450.016],
    [ 2964396.995,    624488.873,   7208680.076],
    [ 3201992.320,   1810113.002,   6901878.965],
    [ 3384567.960,   2941919.905,   6409337.507],
    [ 3505465.893,   3991242.320,   5744316.504],
    [ 3558942.459,   4931767.385,   4924700.825],
    ])

ilrs_time = astropy.time.Time(ilrs_mjd + ilrs_secs / 86400, format='mjd', scale='utc')
x = ilrs_data[:,0]
y = ilrs_data[:,1]
z = ilrs_data[:,2]

# instrument location
topo_loc = astropy.coordinates.EarthLocation(
    lat=inst['latitude']*u.deg, lon=inst['longitude']*u.deg, height=inst['altitude']*u.m
)

for meas in measurements:

    # measurements
    time_meas = meas['timestamp_measurement']
    ttime = astropy.time.Time(time_meas, format='datetime', scale='utc')
    trange = meas['range_value']

    # find closest point in time
    imin = abs(ilrs_time - ttime).argmin()

    # interpolate, 9 point
    tinterp = range(imin - 4, imin + 5)
    t0 = ilrs_time[tinterp][0]
    tl = (ilrs_time[tinterp] - t0).sec  # ilrs times
    teval = (ttime - t0).sec + np.array([-0.05, 0, 0.05])  # times to evaluate at
    px = scipy.interpolate.lagrange(tl, x[tinterp])
    py = scipy.interpolate.lagrange(tl, y[tinterp])
    pz = scipy.interpolate.lagrange(tl, z[tinterp])
    posi = np.array([px(teval), py(teval), pz(teval)])

    # position in ITRS
    dpos = astropy.coordinates.SkyCoord(
        x=posi[0, :], y=posi[1, :], z=posi[2, :],
        representation_type='cartesian',
        frame="itrs", unit="meter"
    )

    # position relative to site
    dpos_altaz = dpos.transform_to(
        astropy.coordinates.AltAz(location=topo_loc)
    )
    rs = dpos_altaz.distance.m

    # residuals
    r_resid = trange - rs[1]

    print('\tCalculated measurement residual')
    print('\t\trange: %2.1fm' % r_resid)

System Details

Please note that we have reproduced this in several environments.

We were able to reproduce it with the following environment:

Python 3.8.13 (default, Mar 16 2022, 20:38:02) 
[Clang 13.0.0 (clang-1300.0.29.30)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import platform; print(platform.platform())
macOS-11.6-x86_64-i386-64bit
>>> import sys; print("Python", sys.version)
Python 3.8.13 (default, Mar 16 2022, 20:38:02) 
[Clang 13.0.0 (clang-1300.0.29.30)]
>>> import numpy; print("Numpy", numpy.__version__)
Numpy 1.22.4
>>> import erfa; print("pyerfa", erfa.__version__)
pyerfa 2.0.0.1
>>> import astropy; print("astropy", astropy.__version__)
astropy 4.3
>>> import scipy; print("Scipy", scipy.__version__)
Scipy 1.8.0
>>> import matplotlib; print("Matplotlib", matplotlib.__version__)
Matplotlib 3.5.2
>>> 

Issue Analytics

  • State:open
  • Created a year ago
  • Comments:5 (4 by maintainers)

github_iconTop GitHub Comments

2reactions
mkbrewercommented, Jun 18, 2022

Since this is a recurring issue, I will raise a separate issue to propose the above more straightforward approach. If I get the go ahead, I will submit a pull request that will solve this problem once and for all.

0reactions
mkbrewercommented, Jun 17, 2022

Actually, it would be better to form the ITRS to AltAz matrix outside the loop.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Full Changelog — Astropy v5.2
Fixed a bug which caused numpy.interp to produce incorrect results when Masked arrays were ... Using these, AltAz calculations are now accurate down...
Read more >
astroplan Documentation - Read the Docs
Calculate rise/set/meridian transit times, alt/az positions for targets at ... astroplan makes heavy use of certain Astropy machinery, ...
Read more >
Full Changelog — Astropy v3.2.dev994
Changed to using astropy.table masked tables instead of NumPy masked arrays for tables with missing values. Added SExtractor table reader to astropy.io.ascii [# ......
Read more >
The Astropy Project: Building an Open-science Project and ...
PDF | The Astropy Project supports and fosters the development of open-source ... All modern astronomical research makes use of software in.
Read more >
pyobs - An Observatory Control System for Robotic Telescopes
It provides out-of-the-box support for many popular camera types while other hardware like telescopes, domes, and weather stations can easily be added via...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found