skyfielders / python-skyfield

Elegant astronomy for Python
MIT License
1.41k stars 211 forks source link

ICRF from_altaz #158

Closed cbassa closed 6 years ago

cbassa commented 6 years ago

This probably is an issue with my understanding of the code, not the code itself, but I'm trying to figure out how to use the ICRF from_altaz attribute. My goal is to specify an ICRF position based on an alt, az and distance from a Topos observer location. Is the from_altaz attribute the correct approach to do this, and how does one provide the distance?

When running (with observer a Topos instance and t a timescale instance)

p=ICRF([0.0,0.0,0.0],observer_data=observer,t=t)
q=p.from_altaz(alt_degrees=30.0,az_degrees=30.0)

this AttributeError is thrown:

AttributeError: 'Topos' object has no attribute 'altaz_rotation'

brandon-rhodes commented 6 years ago

(Finally getting to this issue much later than I wanted to!:) To fully diagnose this issue, I'll need to see how your observer object is constructed. Usually I would say observer.at(t) to find out its location at a given moment — it looks like your code is creating a position at the Solar System barycenter (0,0,0)?

cbassa commented 6 years ago

I'm looking for a way to get a cartesian position in the ICRF, GCRS or another frame based on an azimuth, altitude and distance from the observer location. The goal is to check when that position (relative to the observer) enters and exits the Earth's shadow, as this would be the time when Earth orbiting satellites at that distance become invisible.

The reason for using ICRF is because it has the from_altaz attribute, but perhaps there's a different approach using skyfield. If it has a way of returning a rotation matrix from local horizontal coordinates to the GCRS frame then it would be easy to define the position in the GCRS.

For reference, this was the test I was doing.

#!/usr/bin/env python
from skyfield.positionlib import ICRF
from skyfield.api import load,Topos

ts=load.timescale()
t=ts.now()
observer=Topos(latitude_degrees=50.0,longitude_degrees=20.0,elevation_m=10.0)
p=ICRF([0.0,0.0,0.0],observer_data=observer,t=t)
q=p.from_altaz(alt_degrees=30.0,az_degrees=30.0)

print(p,q)
brandon-rhodes commented 6 years ago

Interesting — I'll think about whether from_altaz() should be moved from ICRS on to one of its subclasses to clarify the interface. It's normally used on a Geocentric location like you get from calling at() on a Topos:

#!/usr/bin/env python
from skyfield.positionlib import ICRF
from skyfield.api import load,Topos

ts = load.timescale()
t = ts.now()
observer = Topos(latitude_degrees=50.0,longitude_degrees=20.0,elevation_m=10.0)
p = observer.at(t)
q = p.from_altaz(alt_degrees=30.0, az_degrees=30.0)
print(q.position.km)

But this code provides no way of controlling distance — from_altaz() hard-codes an arbitrary distance of 0.1 au, to put the object "kind of far away but not so far that any other plants could have refracted it." I suppose I should add a distance= argument to the method — would that make it more useful to you?

cbassa commented 6 years ago

Ah, I see I had missed/misinterpreted the r = 0.1 statement. I guess it's not clear to me what the from_altaz() function is trying to achieve if the distance is not given as an argument, so for me it would indeed make the code more useful if that's added.

It's now also clear to me that the Topos.at(t).observer_data.altaz_rotation returns the rotation matrix I was looking for, so I can make a function myself if needed.

brandon-rhodes commented 6 years ago

Its purpose is to let alt/az be turned into RA/dec. Most users have no use for a distance argument, as most users trying to identify an object whose alt/az they measured don't have any way to know the distance (either because they object is far out in the Solar System or galaxy, or because even though it's close they didn't have the equipment to measure its range by radar).

Which brings up the interesting question of how you yourself are measuring distances for your inputs :)

cbassa commented 6 years ago

Your explanation makes sense.

I'm not measuring a distance per se, but for a given alt/az I'll determine the distance a satellite orbiting at a certain orbital altitude (say 800km) would have in that direction. That cartesian position in the GCRS frame would then be used to determine when it enters and exists the shadow.