Astropy 4.3+ Produces Inaccurate Range Predictions via AltAz Calc
See original GitHub issueDescription
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
- Get some radar Range measurements
- Get ILRS Ephem predictions
- Create an EarthLocation for the radar location.
- Interpolate the ILRS ephem for every measurement timestamp.
- Create a SkyCoord object for the interpolated position.
- 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:
- Created a year ago
- Comments:5 (4 by maintainers)
Top 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 >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
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.
Actually, it would be better to form the ITRS to
AltAz
matrix outside the loop.