Nutze Skyfield fuer praezisere Daemmerungsberechnung
This commit is contained in:
Vendored
+187
@@ -0,0 +1,187 @@
|
||||
"""Python class for a distant object with, at most, proper motion."""
|
||||
|
||||
from numpy import array, cos, empty, isnan, outer, sin, where
|
||||
from .constants import AU_KM, ASEC2RAD, C, C_AUDAY, DAY_S, T0
|
||||
from .functions import length_of
|
||||
from .relativity import light_time_difference
|
||||
from .timelib import Time
|
||||
from .units import Angle
|
||||
|
||||
class Star(object):
|
||||
"""The position in the sky of a star or other fixed object.
|
||||
|
||||
Each `Star` object specifies the position of a distant object. You
|
||||
should provide as a right ascension and declination relative to the
|
||||
ICRS (the recent improvement upon J2000). You can specify the
|
||||
coordinates using either floating point hours and degrees, or tuples
|
||||
that specify hour and degree fractions as minutes and seconds, or
|
||||
even full Skyfield :class:`~skyfield.units.Angle` objects (which can
|
||||
themselves be initialized using hours, degrees, or radians):
|
||||
|
||||
>>> barnard = Star(ra_hours=17.963471675, dec_degrees=4.69339088889)
|
||||
>>> barnard = Star(ra_hours=(17, 57, 48.49), dec_degrees=(4, 41, 36.20))
|
||||
>>> barnard = Star(ra=Angle(hours=17.963471675),
|
||||
... dec=Angle(degrees=4.69339088889))
|
||||
|
||||
For objects whose proper motion across the sky has been detected,
|
||||
you can supply velocities in milliarcseconds (mas) per year, and
|
||||
even a parallax and radial velocity if those are known:
|
||||
|
||||
>>> barnard = Star(ra_hours=(17, 57, 48.49803),
|
||||
... dec_degrees=(4, 41, 36.2072),
|
||||
... ra_mas_per_year=-798.71,
|
||||
... dec_mas_per_year=+10337.77,
|
||||
... parallax_mas=545.4,
|
||||
... radial_km_per_s=-110.6)
|
||||
|
||||
See `stars` for a guide to using a `Star` once you have created it.
|
||||
|
||||
"""
|
||||
au_km = AU_KM
|
||||
target = None
|
||||
|
||||
def __init__(self, ra=None, dec=None, ra_hours=None, dec_degrees=None,
|
||||
ra_mas_per_year=0.0, dec_mas_per_year=0.0,
|
||||
parallax_mas=0.0, radial_km_per_s=0.0, names=(), epoch=T0):
|
||||
|
||||
if ra_hours is not None:
|
||||
self.ra = Angle(hours=ra_hours)
|
||||
elif isinstance(ra, Angle):
|
||||
self.ra = ra
|
||||
else:
|
||||
raise TypeError('please provide either ra_hours=<float> or else'
|
||||
' ra=<skyfield.units.Angle object>')
|
||||
|
||||
if dec_degrees is not None:
|
||||
self.dec = Angle(degrees=dec_degrees)
|
||||
elif isinstance(dec, Angle):
|
||||
self.dec = dec
|
||||
else:
|
||||
raise TypeError('please provide either dec_degrees=<float> or else'
|
||||
' dec=<skyfield.units.Angle object>')
|
||||
|
||||
if isinstance(epoch, Time):
|
||||
epoch = epoch.tt
|
||||
# elif isinstance(epoch, float):
|
||||
# pass
|
||||
# else:
|
||||
# raise ValueError('the epoch= must be a Time object, or'
|
||||
# ' a floating point Barycentric Dynamical Time (TDB)')
|
||||
|
||||
self.ra_mas_per_year = ra_mas_per_year
|
||||
self.dec_mas_per_year = dec_mas_per_year
|
||||
self.parallax_mas = parallax_mas
|
||||
self.radial_km_per_s = radial_km_per_s
|
||||
self.epoch = epoch
|
||||
self.names = names
|
||||
|
||||
self._compute_vectors()
|
||||
|
||||
def __repr__(self):
|
||||
opts = []
|
||||
for name in ['ra', 'dec',
|
||||
'ra_mas_per_year', 'dec_mas_per_year',
|
||||
'parallax_mas', 'radial_km_per_s',
|
||||
'names', 'epoch']:
|
||||
value = getattr(self, name)
|
||||
if isinstance(value, Angle):
|
||||
value = value.degrees
|
||||
shape = getattr(value, 'shape', None)
|
||||
if shape:
|
||||
shapes = ','.join(str(n) for n in shape)
|
||||
opts.append('{0} shape={1}'.format(name, shapes))
|
||||
elif value:
|
||||
opts.append('{0}={1!r}'.format(name, value))
|
||||
return 'Star({0})'.format(', '.join(opts))
|
||||
|
||||
@classmethod
|
||||
def from_dataframe(cls, df):
|
||||
epoch = 1721045.0 + _unwrap(df['epoch_year']) * 365.25
|
||||
return cls(
|
||||
ra_hours=_unwrap(df['ra_hours']),
|
||||
dec_degrees=_unwrap(df['dec_degrees']),
|
||||
ra_mas_per_year=_unwrap(df.get('ra_mas_per_year', 0)),
|
||||
dec_mas_per_year=_unwrap(df.get('dec_mas_per_year', 0)),
|
||||
parallax_mas=_unwrap(df.get('parallax_mas', 0)),
|
||||
epoch=epoch,
|
||||
)
|
||||
|
||||
def _observe_from_bcrs(self, observer):
|
||||
position, velocity = self._position_au, self._velocity_au_per_d
|
||||
t = observer.t
|
||||
dt = light_time_difference(position, observer.xyz.au)
|
||||
if t.shape:
|
||||
position = (outer(velocity, t.tdb + dt - self.epoch).T + position).T
|
||||
else:
|
||||
position = position + velocity * (t.tdb + dt - self.epoch)
|
||||
if len(position.shape) > 1:
|
||||
if len(observer.xyz.au.shape) > 1:
|
||||
vector = position - observer.xyz.au
|
||||
vel = (observer.velocity.au_per_d.T - velocity).T
|
||||
else:
|
||||
vector = (position.T - observer.xyz.au).T
|
||||
vel = (observer.velocity.au_per_d - velocity.T).T
|
||||
else:
|
||||
vector = position - observer.xyz.au
|
||||
vel = (observer.velocity.au_per_d.T - velocity).T
|
||||
distance = length_of(vector)
|
||||
light_time = distance / C_AUDAY
|
||||
if len(position.shape) > 1 and not t.shape:
|
||||
tt = empty(position.shape[1:])
|
||||
tt.fill(t.tt)
|
||||
t = t.ts.tt_jd(tt)
|
||||
return vector, vel, t, light_time
|
||||
|
||||
def _compute_vectors(self):
|
||||
"""Compute the star's position as an ICRF position and velocity."""
|
||||
|
||||
# Use 1 gigaparsec for stars whose parallax is zero.
|
||||
|
||||
parallax = self.parallax_mas
|
||||
shape = getattr(parallax, 'shape', None)
|
||||
if shape:
|
||||
parallax = where(isnan(parallax), 0.0, parallax)
|
||||
parallax[parallax <= 0.0] = 1.0e-6
|
||||
elif parallax <= 0.0:
|
||||
parallax = 1.0e-6
|
||||
|
||||
# Convert right ascension, declination, and parallax to position
|
||||
# vector in equatorial system with units of au.
|
||||
|
||||
dist = 1.0 / sin(parallax * 1.0e-3 * ASEC2RAD)
|
||||
r = self.ra.radians
|
||||
d = self.dec.radians
|
||||
cra = cos(r)
|
||||
sra = sin(r)
|
||||
cdc = cos(d)
|
||||
sdc = sin(d)
|
||||
|
||||
self._position_au = array((
|
||||
dist * cdc * cra,
|
||||
dist * cdc * sra,
|
||||
dist * sdc,
|
||||
))
|
||||
|
||||
# Compute Doppler factor, which accounts for change in light
|
||||
# travel time to star.
|
||||
|
||||
k = 1.0 / (1.0 - self.radial_km_per_s / C * 1000.0)
|
||||
|
||||
# Convert proper motion and radial velocity to orthogonal
|
||||
# components of motion with units of au/day.
|
||||
|
||||
pmr = self.ra_mas_per_year / (parallax * 365.25) * k
|
||||
pmd = self.dec_mas_per_year / (parallax * 365.25) * k
|
||||
rvl = self.radial_km_per_s * DAY_S / self.au_km * k
|
||||
|
||||
# Transform motion vector to equatorial system.
|
||||
|
||||
self._velocity_au_per_d = array((
|
||||
- pmr * sra - pmd * sdc * cra + rvl * cdc * cra,
|
||||
pmr * cra - pmd * sdc * sra + rvl * cdc * sra,
|
||||
pmd * cdc + rvl * sdc,
|
||||
))
|
||||
|
||||
def _unwrap(value):
|
||||
"""Return floats untouched, but ask Series for their NumPy arrays."""
|
||||
return getattr(value, 'values', value)
|
||||
Reference in New Issue
Block a user