Exemplo n.º 1
0
def test_latlon_and_subpoint_methods(ts, angle):
    t = ts.utc(2020, 11, 3, 17, 5)
    g = wgs84.latlon(angle, 2 * angle, elevation_m=1234.0)
    pos = g.at(t)

    def check_lat(lat):
        assert abs(g.latitude.mas() - lat.mas()) < 0.1

    def check_lon(lon):
        assert abs(g.longitude.mas() - lon.mas()) < 0.1

    def check_height(h):
        assert abs(g.elevation.m - h.m) < 1e-7

    lat, lon = wgs84.latlon_of(pos)
    check_lat(lat)
    check_lon(lon)

    height = wgs84.height_of(pos)
    check_height(height)

    g = wgs84.geographic_position_of(pos)
    check_lat(g.latitude)
    check_lon(g.longitude)
    check_height(g.elevation)

    g = wgs84.subpoint(pos)  # old deprecated method name
    check_lat(g.latitude)
    check_lon(g.longitude)
    check_height(g.elevation)

    g = wgs84.subpoint_of(pos)
    check_lat(g.latitude)
    check_lon(g.longitude)
    assert g.elevation.m == 0.0
Exemplo n.º 2
0
def session_plan_set_moonless_astro_twilight(session_plan_id):
    session_plan = SessionPlan.query.filter_by(id=session_plan_id).first()
    _check_session_plan(session_plan)

    t1, t2 = _get_twighligh_component(session_plan, 1)

    if t1 and t2:
        ts = load.timescale()
        _, latitude, longitude, _ = _get_location_info_from_session_plan(
            session_plan)
        observer = wgs84.latlon(latitude, longitude)
        tz_info = _get_session_plan_tzinfo(session_plan)
        ldate_start = tz_info.localize(session_plan.for_date +
                                       timedelta(hours=0))
        ldate_end = tz_info.localize(session_plan.for_date +
                                     timedelta(hours=48))
        start_t = ts.from_datetime(ldate_start)
        end_t = ts.from_datetime(ldate_end)
        eph = load('de421.bsp')
        f = almanac.risings_and_settings(eph, eph['Moon'], observer)
        t, y = almanac.find_discrete(start_t, end_t, f)

        if t1 and t2:
            rise_sets = []
            moon_rise, moon_set = None, None
            for i in range(len(y)):
                if y[i]:
                    moon_rise = t[i].astimezone(tz_info)
                else:
                    moon_set = t[i].astimezone(tz_info)
                    rise_sets.append((moon_rise, moon_set))
                    moon_rise, moon_set = None, None
            if moon_rise or moon_set:
                rise_sets.append((moon_rise, moon_set))

            for moon_rise, moon_set in rise_sets:
                if not moon_rise:
                    moon_rise = ldate_start
                if not moon_set:
                    moon_set = ldate_end
                if moon_set < t1 or moon_rise > t2:
                    continue
                if moon_rise < t1 and moon_set > t2:
                    t1, t2 = None, None
                    break
                if moon_rise > t1:
                    t2 = moon_rise
                else:
                    t1 = moon_set
            if t1 and t2 and t1 > t2:
                t1, t2 = None, None

    if t1 and t2:
        session['planner_time_from'] = t1.strftime(SCHEDULE_TIME_FORMAT)
        session['planner_time_to'] = t2.strftime(SCHEDULE_TIME_FORMAT)

    session['is_backr'] = True
    return redirect(
        url_for('main_sessionplan.session_plan_schedule',
                session_plan_id=session_plan.id))
Exemplo n.º 3
0
def _convert_radec_to_altaz(ra, dec, lon, lat, height, time):
    """Convert a single position.

    This is done for easy code sharing with other tools.
    Skyfield does support arrays of positions.
    """
    load = Loader('.')
    # Skyfield uses FTP URLs, but FTP doesn't work on Github Actions so
    # we use alternative HTTP URLs.
    load.urls['finals2000A.all'] = 'https://datacenter.iers.org/data/9/'
    load.urls['.bsp'] = [
        ('*.bsp',
         'https://naif.jpl.nasa.gov/pub/naif/generic_kernels/spk/planets/')
    ]

    radec = Star(ra=Angle(degrees=ra), dec=Angle(degrees=dec))

    earth = load(EPHEMERIS)['earth']
    location = earth + wgs84.latlon(longitude_degrees=lon,
                                    latitude_degrees=lat,
                                    elevation_m=height * 1000.0)

    ts = load.timescale(builtin=False)
    with load.open('finals2000A.all') as f:
        finals_data = iers.parse_x_y_dut1_from_finals_all(f)
    iers.install_polar_motion_table(ts, finals_data)
    obstime = ts.from_astropy(Time(time, scale='utc'))

    alt, az, _ = location.at(obstime).observe(radec).apparent().altaz(
        pressure_mbar=0)

    return dict(az=az.degrees, alt=alt.degrees)
Exemplo n.º 4
0
def _get_twighligh_component(session_plan, comp):
    ts = load.timescale()
    _, latitude, longitude, _ = _get_location_info_from_session_plan(
        session_plan)
    observer = wgs84.latlon(latitude, longitude)
    tz_info = _get_session_plan_tzinfo(session_plan)
    ldate1 = tz_info.localize(session_plan.for_date + timedelta(hours=12))
    ldate2 = tz_info.localize(session_plan.for_date + timedelta(hours=36))
    t1 = ts.from_datetime(ldate1)
    t2 = ts.from_datetime(ldate2)
    eph = load('de421.bsp')
    t, y = almanac.find_discrete(t1, t2,
                                 almanac.dark_twilight_day(eph, observer))

    index1 = None
    index2 = None
    for i in range(len(y)):
        if y[i] == comp:
            if index1 is None:
                index1 = i + 1
            elif index2 is None:
                index2 = i
    if index1 is None or index2 is None:
        return None, None
    return t[index1].astimezone(tz_info), t[index2].astimezone(tz_info)
Exemplo n.º 5
0
def test_radec_and_altaz_angles_and_rates():
    # HORIZONS test data in Skyfield repository: authorities/radec-altaz-rates
    ts = load.timescale()
    t = ts.utc(2021, 2, 3)

    # Start with a sanity check: verify that RA and dec agree.

    top = wgs84.latlon(35.1844866, 248.347300, elevation_m=2106.9128)
    planets = load('de421.bsp')
    a = (planets['earth'] + top).at(t).observe(planets['mars']).apparent()
    frame = framelib.true_equator_and_equinox_of_date
    dec, ra, distance, dec_rate, ra_rate, range_rate = (
        a.frame_latlon_and_rates(frame))

    arcseconds = 3600.0
    assert abs((ra.degrees - 40.75836) * arcseconds) < 0.04
    assert abs((dec.degrees - 17.16791) * arcseconds) < 0.005
    assert abs(distance.m - 1.21164331503552 * AU_M) < 120.0

    # Angle rates of change.

    assert round(dec_rate.arcseconds.per_hour, 5) == 25.61352
    assert round(ra_rate.arcseconds.per_hour * cos(dec.radians),
                 4) == round(75.15571, 4)  # TODO: get last digit to agree?
    assert abs(range_rate.km_per_s - 16.7926932) < 2e-5
Exemplo n.º 6
0
def test_polar_motion_when_computing_altaz_coordinates(ts):
    latitude = 37.3414
    longitude = -121.6429
    elevation = 1283.0
    ra_hours = 5.59
    dec_degrees = -5.45

    xp_arcseconds = 11.0
    yp_arcseconds = 22.0
    ts.polar_motion_table = [0.0], [xp_arcseconds], [yp_arcseconds]

    t = ts.utc(2020, 11, 12, 22, 16)
    top = wgs84.latlon(latitude, longitude, elevation)

    pos = Apparent.from_radec(ra_hours, dec_degrees, epoch=t)
    pos.t = t
    pos.center = top

    alt, az, distance = pos.altaz()

    # To generate the test altitude and azimuth below:
    # from novas.compat import equ2hor, make_on_surface
    # location = make_on_surface(latitude, longitude, elevation, 0, 0)
    # (novas_zd, novas_az), (rar, decr) = equ2hor(
    #     t.ut1, t.delta_t, xp_arcseconds, yp_arcseconds, location,
    #     ra_hours, dec_degrees, 0,
    # )
    # novas_alt = 90.0 - novas_zd
    # print(novas_alt, novas_az)

    novas_alt = -58.091983295564205
    novas_az = 1.8872567543791035

    assert abs(alt.degrees - novas_alt) < 1.9e-9
    assert abs(az.degrees - novas_az) < 1.3e-7
Exemplo n.º 7
0
 def observer(
     self,
     lat: float,
     lon: float,
     elevationMeters: Optional[float] = None,
 ) -> VectorFunction:
     """Return a VectorFunction representing a terrestrial observer."""
     return self.earth.position + wgs84.latlon(
         lat, lon, elevation_m=elevationMeters or 0)
Exemplo n.º 8
0
    def skyfield_site(self, spice_kernel):
        """Return a skyfield VectorSum for this location on 'earth' (starting
        from wgs84).  The spice_kernel is the thing one might get from
        jpllib.SpiceKernel(emphemeris_filename).

        """
        from skyfield.api import wgs84
        earth = spice_kernel['earth']
        return earth + wgs84.latlon(self.lat, self.lon, self.elev)
Exemplo n.º 9
0
def test_latitude_longitude_elevation_str_and_repr():
    w = wgs84.latlon(36.7138, -112.2169, 2400.0)
    assert str(w) == ('WGS84 latitude +36.7138 N'
                      ' longitude -112.2169 E elevation 2400.0 m')
    assert repr(w) == ('<GeographicPosition WGS84 latitude +36.7138 N'
                       ' longitude -112.2169 E elevation 2400.0 m>')

    w = wgs84.latlon([1.0, 2.0], [3.0, 4.0], [5.0, 6.0])
    assert str(w) == ('WGS84 latitude [+1.0000 +2.0000] N'
                      ' longitude [3.0000 4.0000] E'
                      ' elevation [5.0 6.0] m')
    assert repr(w) == '<GeographicPosition {0}>'.format(w)

    w = wgs84.latlon(arange(6.0), arange(10.0, 16.0), arange(20.0, 26.0))
    assert str(w) == ('WGS84 latitude [+0.0000 +1.0000 ... +4.0000 +5.0000] N'
                      ' longitude [10.0000 11.0000 ... 14.0000 15.0000] E'
                      ' elevation [20.0 21.0 ... 24.0 25.0] m')
    assert repr(w) == '<GeographicPosition {0}>'.format(w)
Exemplo n.º 10
0
    def loadObserver(self, lat, long):
        '''

        :param lat:
        :param long:
        :return:
        '''
        self.observer = wgs84.latlon(lat, long)
        return
Exemplo n.º 11
0
def test_lst():
    ts = load.timescale()
    ts.delta_t_table = [-1e99, 1e99], [69.363285] * 2  # from finals2000A.all
    t = ts.utc(2020, 11, 27, 15, 34)
    top = wgs84.latlon(0.0, 0.0)
    expected = 20.0336663100  # see "authorities/horizons-lst"
    actual = top.lst_hours_at(t)
    difference_mas = (actual - expected) * 3600 * 15 * 1e3
    horizons_ra_offset_mas = 51.25
    difference_mas -= horizons_ra_offset_mas
    assert abs(difference_mas) < 1.0
Exemplo n.º 12
0
def test_wgs84_velocity_matches_actual_motion():
    # It looks like this is a sweet spot for accuracy: presumably a
    # short enough fraction of a second that the vector does not time to
    # change direction much, but long enough that the direction does not
    # get lost down in the noise.
    factor = 300.0

    ts = load.timescale()
    t = ts.utc(2019, 11, 2, 3, 53, [0, 1.0 / factor])
    jacob = wgs84.latlon(36.7138, -112.2169)
    p = jacob.at(t)
    velocity1 = p.position.km[:, 1] - p.position.km[:, 0]
    velocity2 = p.velocity.km_per_s[:, 0]
    assert length_of(velocity2 - factor * velocity1) < 0.0007
Exemplo n.º 13
0
def test_itrs_xyz_attribute_and_itrf_xyz_method():
    top = wgs84.latlon(45.0, 0.0, elevation_m=constants.AU_M - constants.ERAD)

    x, y, z = top.itrs_xyz.au
    assert abs(x - sqrt(0.5)) < 2e-7
    assert abs(y - 0.0) < 1e-14
    assert abs(z - sqrt(0.5)) < 2e-7

    ts = load.timescale()
    t = ts.utc(2019, 11, 2, 3, 53)
    x, y, z = top.at(t).itrf_xyz().au
    assert abs(x - sqrt(0.5)) < 1e-4
    assert abs(y - 0.0) < 1e-14
    assert abs(z - sqrt(0.5)) < 1e-4
Exemplo n.º 14
0
def test_wgs84_subpoint(ts, angle):
    t = ts.utc(2018, 1, 19, 14, 37, 55)
    # An elevation of 0 is more difficult for the routine's accuracy
    # than a very large elevation.
    top = wgs84.latlon(angle, angle, elevation_m=0.0)
    p = top.at(t)
    b = wgs84.subpoint(p)

    error_degrees = abs(b.latitude.degrees - angle)
    error_mas = 60.0 * 60.0 * 1000.0 * error_degrees
    assert error_mas < 0.1

    error_degrees = abs(b.longitude.degrees - angle)
    error_mas = 60.0 * 60.0 * 1000.0 * error_degrees
    assert error_mas < 0.1
Exemplo n.º 15
0
def test_wgs84_round_trip_with_polar_motion(ts, angle):
    t = ts.utc(2018, 1, 19, 14, 37, 55)
    ts.polar_motion_table = [0.0], [0.003483], [0.358609]

    top = wgs84.latlon(angle, angle, elevation_m=0.0)
    p = top.at(t)
    b = wgs84.subpoint(p)

    error_degrees = abs(b.latitude.degrees - angle)
    error_mas = 60.0 * 60.0 * 1000.0 * error_degrees
    assert error_mas < 0.1

    error_degrees = abs(b.longitude.degrees - angle)
    error_mas = 60.0 * 60.0 * 1000.0 * error_degrees
    assert error_mas < 0.1
Exemplo n.º 16
0
def test_radec_and_altaz_angles_and_rates():
    # HORIZONS test data in Skyfield repository: authorities/radec-altaz-rates
    ts = load.timescale()
    t = ts.utc(2021, 2, 3)
    top = wgs84.latlon(35.1844866, 248.347300, elevation_m=2106.9128)
    planets = load('de421.bsp')
    a = (planets['earth'] + top).at(t).observe(planets['mars']).apparent()

    # First, verify RA and declination.

    frame = framelib.true_equator_and_equinox_of_date
    dec, ra, distance, dec_rate, ra_rate, range_rate = (
        a.frame_latlon_and_rates(frame))

    arcseconds = 3600.0
    assert abs((ra.degrees - 40.75836) * arcseconds) < 0.04
    assert abs((dec.degrees - 17.16791) * arcseconds) < 0.005
    assert abs(distance.m - 1.21164331503552 * AU_M) < 120.0

    # Verify RA and declination rates of change.

    assert round(dec_rate.arcseconds.per_hour, 5) == 25.61352
    assert round(ra_rate.arcseconds.per_hour * cos(dec.radians),
                 4) == round(75.15571, 4)  # TODO: get last digit to agree?
    assert abs(range_rate.km_per_s - 16.7926932) < 2e-5

    # Verify altitude and azimuth.

    frame = top
    alt, az, distance, alt_rate, az_rate, range_rate = (
        a.frame_latlon_and_rates(frame))

    assert round(alt.degrees, 4) == 65.2758
    assert round(az.degrees, 4) == 131.8839
    assert abs(distance.m - 1.21164331503552 * AU_M) < 120.0

    # Verify altitude and azimuth rates of change.

    assert abs(range_rate.km_per_s - 16.7926932) < 2e-5
    assert round(alt_rate.arcseconds.per_minute, 2) == 548.66
    assert round(az_rate.arcseconds.per_minute * cos(alt.radians), 2) == 663.55
Exemplo n.º 17
0
    def rise_and_set_time(self, satellite):
        """
        Accepts a satellite, returns the next rise and set time for that satellite
        as a tuple of datetimes
        """

        # create skyfield latlon
        loc = wgs84.latlon(self.lat, self.lon)

        # create timescale
        ts = load.timescale()
        t0, t1 = ts.from_datetimes(self.time_window(1))

        # get events where satellite reaches altitude at location in time window
        times, _ = satellite.find_events(
            loc, t0, t1, altitude_degrees=self.altitude_degrees)

        # get rise and sent time for first event
        rise_time = times[0].utc_datetime()
        set_time = times[2].utc_datetime()

        return (rise_time, set_time)
Exemplo n.º 18
0
    def _get_times(self, now: datetime) -> (datetime, datetime):
        midnight = now.replace(hour=0, minute=0, second=0, microsecond=0)
        next_midnight = midnight + timedelta(days=1)

        ts = load.timescale()
        t0 = ts.from_datetime(midnight)
        t1 = ts.from_datetime(next_midnight)
        eph = load_file(config['DE421_PATH'])
        bluffton = wgs84.latlon(config['COORDINATES']['N'] * N, config['COORDINATES']['E'] * E)
        f = almanac.dark_twilight_day(eph, bluffton)
        times, events = almanac.find_discrete(t0, t1, f)

        result = []
        previous_e = None
        for t, e in zip(times, events):
            if e == 4:
                result.append(t.astimezone(self.zone))
            if previous_e == 4:
                result.append(t.astimezone(self.zone))
            previous_e = e

        return result[0], result[1]
Exemplo n.º 19
0
def skyfield_trial(df):
    antares_northing = 4742381.9
    antares_easting = 268221.6
    antares_height = -2500  # m     (guessed, probably similar to orca)
    antares_utm_zone_number = 32
    antares_utm_zone_letter = "N"
    antares_utm_zone = "{num}{let}".format(num=antares_utm_zone_number, let=antares_utm_zone_letter)
    antares_latitude, antares_longitude = utm.to_latlon(antares_easting, antares_northing, antares_utm_zone_number, antares_utm_zone_letter)
    ts = api.load.timescale()
    evt_time=np.array(df['DateMJD'])+ 2400000.5    #from mjd to jd
    #print(evt_time)
    t = ts.tt_jd(evt_time)#now()
    print(len(t))
    alt=(180/np.pi)*(np.pi/2-np.arccos(np.array(df['TantraZenith'])))
    azi=(180/np.pi)*(np.array(df['TantraAzimuth']))
    geographic =wgs84.latlon(latitude_degrees=antares_latitude, longitude_degrees=antares_longitude,elevation_m=antares_height)
    #for a in range(len(evt_time)):
    observer = geographic.at(t[:100])
    print(observer)
    pos = observer.from_altaz(alt_degrees=alt[:100], az_degrees=azi[:100])
    galactic = pos.galactic_latlon()
    print(galactic)
    return 0
Exemplo n.º 20
0
def is_sun_visible(latitude=None, longitude=None, date_time=None, dawn_dusk=False):
    """
    Determine if sun is above horizon at for a list of times.

    Parameters
    ----------
    latitude : int, float
        Latitude in degrees north positive. Must be a scalar.
    longitude : int, float
        Longitude in degrees east positive. Must be a scalar.
    date_time : datetime.datetime, numpy.array.datetime64, list of datetime.datetime
        Datetime with timezone, datetime with no timezone in UTC, or numpy.datetime64
        format in UTC. Can be a single datetime object or list of datetime objects.
    dawn_dusk : boolean
        If set to True, will use skyfields dark_twilight_day function to calculate sun up
        Returns a list of int's instead of boolean.
        0 - Dark of Night
        1 - Astronomical Twilight
        2 - Nautical Twilight
        3 - Civil Twilight
        4 - Sun Is Up

    Returns
    -------
    result : list
        List matching size of date_time containing True/False if sun is above horizon.
    """

    sf_dates = None

    # Check if datetime object is scalar and if has no timezone.
    if isinstance(date_time, datetime):
        if date_time.tzinfo is None:
            sf_dates = [date_time.replace(tzinfo=pytz.UTC)]
        else:
            sf_dates = [date_time]

    # Check if datetime objects in list have timezone. If not add.
    if isinstance(date_time, (list, tuple)) and isinstance(date_time[0], datetime):
        if isinstance(date_time[0], datetime) and date_time[0].tzinfo is not None:
            sf_dates = date_time
        else:
            sf_dates = [ii.replace(tzinfo=pytz.UTC) for ii in date_time]

    # Convert datetime64 to datetime with timezone.
    if type(date_time).__module__ == np.__name__ and np.issubdtype(date_time.dtype, np.datetime64):
        sf_dates = datetime64_to_datetime(date_time)
        sf_dates = [ii.replace(tzinfo=pytz.UTC) for ii in sf_dates]

    if sf_dates is None:
        raise ValueError('The date_time values entered into is_sun_visible() '
                         'do not match input types.')

    ts = load.timescale()
    eph = load_file(skyfield_bsp_file)

    t0 = ts.from_datetimes(sf_dates)
    location = wgs84.latlon(latitude, longitude)
    if dawn_dusk:
        f = almanac.dark_twilight_day(eph, location)
    else:
        f = almanac.sunrise_sunset(eph, location)

    sun_up = f(t0)

    eph.close()

    return sun_up
Exemplo n.º 21
0
# Use 30-seconds (aka a half-a-minute) (0.5 of (24 hrs * 60 minutes))
ti_increment = (0.5/(24*60))
# Decrement time from "now"
t1 = t0 - ti_increment
##print(t1)

# Get local timezone
tz = tz.tzlocal()


print("Current time:",t0.utc_strftime('%Y-%m-%d %H:%M:%S'), "UTC")
tilocal = t0.astimezone(tz).strftime("%Y-%m-%d %H:%M:%S")
print("Current time:",tilocal,"Local")
print()

qth = wgs84.latlon(Lat1, Lon1)

# Satellite name(s) are arguments[2+]
for i in range(satarg,numargs):
    sat = sys.argv[i]
    ##print("\nSat: ",sat)

    by_name = {sat.name: sat for sat in satellites}
    #satellite = by_name['ISS (ZARYA)']
    satellite = by_name[sat]
    ##print(satellite)

    difference = satellite - qth


    # Find az/el "a few seconds ago"
Exemplo n.º 22
0
def get_solar_azimuth_elevation(latitude=None, longitude=None, time=None, library='skyfield',
                                temperature_C='standard', pressure_mbar='standard'):
    """
    Calculate solar azimuth, elevation and solar distance.


    Parameters
    ----------
    latitude : int, float
        Latitude in degrees north positive. Must be a scalar.
    longitude : int, float
        Longitude in degrees east positive. Must be a scalar.
    time : datetime.datetime, numpy.datetime64, list, numpy.array
        Time in UTC. May be a scalar or vector. datetime must be timezone aware.
    library : str
        Library to use for making calculations. Options include ['skyfield']
    temperature_C : string or list of float
        If library is 'skyfield' the temperature in degrees C at the surface for
        atmospheric compensation of the positon of the sun. Set to None for no
        compensation or 'standard' for standard model with a standard temperature.
    pressure_mbar : string or list of float
        If library is 'skyfield' the pressure in milibars at the surface for
        atmospheric compensation of the positon of the sun. Set to None for no
        compensation or 'standard' for standard model with a standard pressure.

    Returns
    -------
    result : tuple of float
        Values returned are a tuple of elevation, azimuth and distance. Elevation and
        azimuth are in degrees, with distance in Astronomical Units.

    """

    result = {'elevation': None, 'azimuth': None, 'distance': None}

    if library == 'skyfield':
        planets = load_file(skyfield_bsp_file)
        earth, sun = planets['earth'], planets['sun']

        if isinstance(time, datetime) and time.tzinfo is None:
            time = time.replace(tzinfo=pytz.UTC)

        if isinstance(time, (list, tuple)) and time[0].tzinfo is None:
            time = [ii.replace(tzinfo=pytz.UTC) for ii in time]

        if type(time).__module__ == np.__name__ and np.issubdtype(time.dtype, np.datetime64):
            time = time.astype('datetime64[s]').astype(int)
            if time.size > 1:
                time = [datetime.fromtimestamp(tm, timezone.utc) for tm in time]
            else:
                time = [datetime.fromtimestamp(time, timezone.utc)]

        if not isinstance(time, (list, tuple, np.ndarray)):
            time = [time]

        ts = load.timescale()
        t = ts.from_datetimes(time)
        location = earth + wgs84.latlon(latitude * N, longitude * W)
        astrometric = location.at(t).observe(sun)
        alt, az, distance = astrometric.apparent().altaz(temperature_C=temperature_C,
                                                         pressure_mbar=pressure_mbar)
        result = (alt.degrees, az.degrees, distance.au)
        planets.close()

    return result
Exemplo n.º 23
0
def get_sunrise_sunset_noon(latitude=None, longitude=None, date=None, library='skyfield',
                            timezone=False):
    """
    Calculate sunrise, sunset and local solar noon times.

    Parameters
    ----------
    latitude : int, float
        Latitude in degrees north positive. Must be a scalar.
    longitude : int, float
        Longitude in degrees east positive. Must be a scalar.
    date : (datetime.datetime, numpy.datetime64, list of datetime.datetime,
            numpy.array of numpy.datetime64, string, list of string)
        Date(s) to return sunrise, sunset and noon times spaning the first date to last
        date if more than one provided. May be a scalar or vector. If entered as a string must follow
        YYYYMMDD format.
    library : str
        Library to use for making calculations. Options include ['skyfield']
    timezone : boolean
        Have timezone with datetime.

    Returns
    -------
    result : tuple of three numpy.array
        Tuple of three values sunrise, sunset, noon. Values will be a list.
        If no values can be calculated will return empty list. If the date is within
        polar night will return empty lists. If spans the transition to polar day
        will return previous sunrise or next sunset outside of date range provided.
    """

    sunrise, sunset, noon = np.array([]), np.array([]), np.array([])

    if library == 'skyfield':
        ts = load.timescale()
        eph = load_file(skyfield_bsp_file)
        sf_dates = []

        # Parse datetime object
        if isinstance(date, datetime):
            if date.tzinfo is None:
                sf_dates = [date.replace(tzinfo=pytz.UTC)]
            else:
                sf_dates = [date]

        if isinstance(date, (list, tuple)) and isinstance(date[0], datetime):
            if date[0].tzinfo is not None:
                sf_dates = date
            else:
                sf_dates = [ii.replace(tzinfo=pytz.UTC) for ii in date]

        # Parse string date
        if isinstance(date, str):
            sf_dates = [datetime.strptime(date, '%Y%m%d').replace(tzinfo=pytz.UTC)]

        # Parse list of string dates
        if isinstance(date, (list, tuple)) and isinstance(date[0], str):
            sf_dates = [datetime.strptime(dt, '%Y%m%d').replace(tzinfo=pytz.UTC) for dt in date]

        # Convert datetime64 to datetime
        if type(date).__module__ == np.__name__ and np.issubdtype(date.dtype, np.datetime64):
            sf_dates = datetime64_to_datetime(date)
            sf_dates = [ii.replace(tzinfo=pytz.UTC) for ii in sf_dates]

        # Function for calculating solar noon
        # Convert location into skyfield location object
        location = wgs84.latlon(latitude, longitude)
        # Set up function to indicate calculating locatin of Sun from Earth
        f = almanac.meridian_transits(eph, eph['Sun'], location)
        # Set up dates to be start of day and end of day so have a range
        t0 = sf_dates[0]
        t0 = t0.replace(hour=0, minute=0, second=0)
        t1 = sf_dates[-1]
        t1 = t1.replace(hour=23, minute=59, second=59)
        # Convert times from datetime to skyfild times
        t0 = ts.from_datetime(t0)
        t1 = ts.from_datetime(t1)
        # Calculate Meridian Transits. n contains times and x contains 1 and 0's
        # indicating when transit time is above or below location.
        n, x = almanac.find_discrete(t0, t1, f)

        # Determine if time is during daylight
        f = almanac.sunrise_sunset(eph, location)
        sun_up = f(n)

        # Filter out times when sun is below location or in polar night
        n = n[(x == 1) & sun_up]
        noon = n.utc_datetime()
        if noon.size == 0:
            return sunrise, sunset, noon

        # Calcuate sunrise and sunset times. Calcuate over range 12 less than minimum
        # noon time and 12 hours greater than maximum noon time.
        t0 = min(noon) - timedelta(hours=12)
        t1 = max(noon) + timedelta(hours=12)
        t0 = ts.from_datetime(t0)
        t1 = ts.from_datetime(t1)
        f = almanac.sunrise_sunset(eph, location)
        t, y = almanac.find_discrete(t0, t1, f)
        times = t.utc_datetime()
        sunrise = times[y == 1]
        sunset = times[y == 0]

        # Fill in sunrise and sunset if asked to during polar day
        if len(noon) > 0 and (y.size == 0 or len(sunrise) != len(sunset)):
            t0 = min(noon) - timedelta(days=90)
            t1 = max(noon) + timedelta(days=90)
            t0 = ts.from_datetime(t0)
            t1 = ts.from_datetime(t1)
            t, yy = almanac.find_discrete(t0, t1, f)
            times = t.utc_datetime()
            # If first time is sunset and/or last time is sunrise filter
            # from times
            if yy[0] == 0:
                yy = yy[1:]
                times = times[1:]
            if yy[-1] == 1:
                yy = yy[:-1]
                times = times[:-1]

            # Extract sunrise times
            temp_sunrise = times[yy == 1]
            # Extract sunset times
            temp_sunset = times[yy == 0]
            # Look for index closest to first noon time to get the time of last sunrise
            # since we are in polar day.
            diff = temp_sunrise - min(noon)
            sunrise_index = np.max(np.where(diff < timedelta(seconds=1)))
            # Look for index closest to last noon time to get the time of first sunset
            # since we are in polar day.
            diff = max(noon) - temp_sunset
            sunset_index = np.min(np.where(diff < timedelta(seconds=1))) + 1
            sunrise = temp_sunrise[sunrise_index: sunset_index]
            sunset = temp_sunset[sunrise_index: sunset_index]

        eph.close()

    if timezone is False:
        for ii in range(0, sunset.size):
            sunrise[ii] = sunrise[ii].replace(tzinfo=None)
            sunset[ii] = sunset[ii].replace(tzinfo=None)
        for ii in range(0, noon.size):
            noon[ii] = noon[ii].replace(tzinfo=None)

    return sunrise, sunset, noon
Exemplo n.º 24
0
"""ISS.ipynb

Automatically generated by Colaboratory.

Original file is located at
    https://colab.research.google.com/drive/1BVxhugAbx3J9ZZYsVpuDxFoPjtdHehz1
"""

!pip install skyfield
from skyfield.api import load, wgs84
import pytz
import pylab as pl
import matplotlib.pyplot as plt
ts = load.timescale()
eastern = pytz.timezone('US/Eastern')
raleigh = wgs84.latlon(+35.78, -78.64, elevation_m=100)

"""[space station orbital elements (NORAD)](http://celestrak.com/NORAD/elements/stations.txt)

"""

stations_url = 'http://celestrak.com/NORAD/elements/stations.txt'
satellites = load.tle_file(stations_url)
print('Loaded', len(satellites), 'satellites')

by_name = {sat.name: sat for sat in satellites}
satellite = by_name['ISS (ZARYA)']
print(satellite)
print(satellite.epoch.utc_jpl())
print(satellite)
Exemplo n.º 25
0
import os

os.environ["NUMBA_DISABLE_JIT"] = "1"

import numpy as np
from radio_dreams.interferometer import (
    enh_xyz,
    gauss_kernel,
    radec_lmn,
    read_layout,
    uv_degrid,
    xyz_uvw,
)
from skyfield.api import wgs84

mwa_geo = wgs84.latlon(-26.703319, 116.670815, 337.83)
freq = 200e6

# Save the path to this directory
dirpath = os.path.dirname(__file__)

# Obtain path to directory with test_data
test_data = os.path.abspath(os.path.join(dirpath, "./test_data"))


def test_read_layout():
    """Check read values match data."""

    layout = read_layout(layout_path=f"{test_data}/test_mwa.txt")

    assert layout.shape[0] == 3
Exemplo n.º 26
0
def my_position():
    my_coordinates = wgs84.latlon(Latitude, Longitude, elevation_m=(Elevation/3.281)) #My Coordinates
    return my_coordinates
Exemplo n.º 27
0
def run_clock():
    #initialize skyfield stuff
    eph = load('de421.bsp')
    sun = eph['sun']
    moon = eph['moon']
    mercury = eph['mercury']
    venus = eph['venus']
    earth = eph['earth']
    mars = eph['mars']
    jupiter = eph['JUPITER BARYCENTER']
    saturn = eph['SATURN BARYCENTER']
    uranus = eph['URANUS BARYCENTER']
    neptune = eph['NEPTUNE BARYCENTER']
    planets = [
        sun, moon, mercury, venus, mars, jupiter, saturn, uranus, neptune
    ]
    ts = load.timescale()

    # define variables
    # lat = 38.9072
    # lon = 77.0369
    config_data = read_config()
    #define city just by lat/lon for almanac lookup
    city = wgs84.latlon(
        float(config_data['lat']) * N,
        float(config_data['lon']) * W)
    names = [
        'sun', 'moon', 'mercury', 'venus', 'mars', 'jupiter', 'saturn',
        'uranus', 'neptune'
    ]

    #initialize neopixel
    pixel_pin = board.D18
    n = 81
    ORDER = neopixel.RGBW
    pixels = neopixel.NeoPixel(pixel_pin, n, brightness=1, pixel_order=ORDER)
    # LED list for each light
    LED = [(0, 0, 0, 25), (0, 0, 0, 25), (0, 0, 0, 25), (0, 0, 0, 25),
           (0, 0, 0, 25), (0, 0, 0, 25), (0, 0, 0, 25), (0, 0, 0, 25),
           (0, 0, 0, 25)]

    now = int(time.time())  # return time since the Epoch
    print('current unix timestamp:', now)
    logging.info('current unix timestamp: %s' % now)
    now_local = time.localtime(now)
    now_local_str = " ".join(map(str, now_local))

    print('local time string:', now_local_str)
    logging.info('local time string: %s' % now_local_str)

    planet_list = make_planet_list(ts, planets, city, eph, names)

    for i in range(len(names)):

        #clear LEDs at boot
        pixels[i * 9] = (0, 0, 0, 0)
        pixels[i * 9 + 1] = (0, 0, 0, 0)
        pixels[i * 9 + 2] = (0, 0, 0, 0)
        pixels[i * 9 + 3] = (0, 0, 0, 0)
        pixels[i * 9 + 4] = (0, 0, 0, 0)
        pixels[i * 9 + 5] = (0, 0, 0, 0)
        pixels[i * 9 + 6] = (0, 0, 0, 0)
        pixels[i * 9 + 7] = (0, 0, 0, 0)
        pixels[i * 9 + 8] = (0, 0, 0, 0)
        pixels.show()
        time.sleep(0.5)

        #turn on LEDs for planets already above horizon
        if planet_list[i][0] > planet_list[i + 9][
                0]:  # if rise time is later than set time, it's above the horizon
            print('above horizon:', planet_list[i][1])

            dur_rem = planet_list[i +
                                  9][0] - now  #find time remaining until set
            dur = (24 * 3600) - (planet_list[i][0] - planet_list[i + 9][0]
                                 )  #find approximate total time above horizon
            dur_int = int(dur /
                          (2 * (n / len(names)) -
                           1))  #find duration of a single timestemp interval
            int_rem = int(
                dur_rem / dur_int
            )  # number of intervals remaining is the duration remaining divided by duration interval
            if int_rem > 17:
                int_rem = 17

            dur_int_rem = dur % dur_int  #remainder of time in final interval
            print('duration remaining:', dur_rem)
            print('intervals remaining:', int_rem)

            timestamp, planetname, action = planet_list[i + 9]

            #if the planet is setting:
            if int_rem < (n / len(names)) and not int_rem == 0:
                # 1. find a_set timestamps
                for j in range(int_rem - 1):
                    above_set_timestamp = int(timestamp -
                                              ((dur_int *
                                                (j + 1)) + dur_int_rem))
                    above_set_tuple = (above_set_timestamp, planetname,
                                       'a_set')
                    planet_list.append(above_set_tuple)

                # 2. light up last int_rem LEDs for setting
                if i % 2 == 1:
                    for j in range(int_rem):
                        pixels[i * 9 + 9 - (j + 1)] = LED[j]
                        pixels.show()
                elif i % 2 == 0:
                    for j in range(int_rem):
                        pixels[i * 9 + j] = LED[j]
                        pixels.show()
            elif int_rem == 0:  #if the planet is about to set, light up last LED only
                if i % 2 == 1:
                    pixels[i * 9 + 9 - 1] = LED[0]
                    pixels.show()
                elif i % 2 == 0:
                    pixels[i * 9] = LED[0]
                    pixels.show()

            # if the planet is rising:
            else:
                #1. find a_rise timestamps
                for j in range(int_rem - int(n / len(names))):
                    above_rise_timestamp = int(timestamp - (
                        int((n / len(names)) - 1) * dur_int + dur_int *
                        (j + 1) + dur_int_rem))
                    above_rise_tuple = (above_rise_timestamp, planetname,
                                        'a_rise')
                    planet_list.append(above_rise_tuple)
                #2. find a_set timestamps
                for j in range(int(n / len(names) - 1)):
                    above_set_timestamp = int(timestamp -
                                              (dur_int *
                                               (j + 1) + dur_int_rem))
                    above_set_tuple = (above_set_timestamp, planetname,
                                       'a_set')
                    planet_list.append(above_set_tuple)
                #3. light up LEDs
                for j in range(2 * int(n / len(names)) - int_rem):
                    if i % 2 == 1:
                        pixels[i * 9 + j] = LED[j]
                        pixels.show()
                    elif i % 2 == 0:
                        pixels[i * 9 + 9 - (j + 1)] = LED[j]
                        pixels.show()

    list.sort(planet_list)  #sort list of rise and set chronologically
    print('planet list:')
    print(planet_list)
    logging.info('planet_list: %s' % planet_list)

    while True:
        timestamp, planetname, action = planet_list.pop(0)
        timestamp_local = time.localtime(timestamp)
        timestamp_local_str = " ".join(map(str, timestamp_local))
        print('next up:', 'planet:', planetname, 'action:', action,
              'unix timestamp:', timestamp, 'local event time:',
              timestamp_local_str)
        logging.info(
            'next up: planet: %s, action: %s, unix timestamp: %s, local event time: %s'
            % (planetname, action, timestamp, timestamp_local_str))

        planet_num = names.index(planetname)

        #sleep until the action
        delay = timestamp - now
        print('delay is:', delay)
        logging.info('delay is: %s' % delay)

        if delay > 0:
            # sleep until timestamp
            time.sleep(delay)

        if action == 'rise':
            print('action is:', action)
            logging.info('action is: %s' % action)

            #part 1: create list of above horizon intervals to adjust LEDs
            dur = [item for item in planet_list if planetname in item
                   ][0][0] - timestamp
            #find duration above horizon in seconds by looking up the timstamp of that planet's set time in planet_list (the rise time has been popped out)
            dur_int = int(dur /
                          (2 * (n / len(names)) -
                           1))  #find duration of a single timestemp interval
            #dur_rem = dur % dur_int #find duration leftover (might not need this)
            print('total time above horizon:', dur)
            logging.info('total time above horizon: %s' % dur)

            #add action timestamps for above_rise and above_set intervals between rise and set
            for j in range(int((n / len(names)) - 1)):
                above_rise_timestamp = int((timestamp + dur_int * (j + 1)))
                above_rise_tuple = (above_rise_timestamp, planetname, 'a_rise')
                planet_list.append(above_rise_tuple)
            for j in range(int((n / len(names)) - 1)):
                above_set_timestamp = int(
                    (timestamp + int((n / len(names)) - 1) * dur_int +
                     dur_int * (j + 1)))
                above_set_tuple = (above_set_timestamp, planetname, 'a_set')
                planet_list.append(above_set_tuple)

            #turn on first LED at rise action timestamp
            if planet_num % 2 == 1:
                pixels[planet_num * 9] = LED[0]
                pixels.show()
            if planet_num % 2 == 0:
                pixels[planet_num * 9 + 9 - 1] = LED[0]
                pixels.show()

            print(planetname, 'rise')
            logging.info('%s, rise' % planetname)

        elif action == "a_rise":
            print('action is:', action)
            logging.info('action is: %s' % action)

            #count remaining instances of a_rise
            count = 0
            for i in range(len(planet_list)):
                if planet_list[i][1] == planetname and planet_list[i][
                        2] == action:
                    count += 1
            LED_count = int(n / len(names)) - count
            print('count is:', count)
            logging.info('count is: %s' % count)

            for i in range(LED_count):
                if planet_num % 2 == 1:
                    pixels[planet_num * 9 + i] = LED[i]
                    pixels.show()
                elif planet_num % 2 == 0:
                    pixels[planet_num * 9 + 9 - (i + 1)] = LED[i]
                    pixels.show()

        elif action == "a_set":
            print('action is:', action)
            logging.info('action is: %s' % action)

            count = 0
            for i in range(len(planet_list)):
                if planet_list[i][1] == planetname and planet_list[i][
                        2] == action:
                    count += 1
            LED_count = count + 1
            print('count is:', count)
            logging.info('count is: %s' % count)

            pixels[planet_num * 9] = (0, 0, 0, 0)
            pixels[planet_num * 9 + 1] = (0, 0, 0, 0)
            pixels[planet_num * 9 + 2] = (0, 0, 0, 0)
            pixels[planet_num * 9 + 3] = (0, 0, 0, 0)
            pixels[planet_num * 9 + 4] = (0, 0, 0, 0)
            pixels[planet_num * 9 + 5] = (0, 0, 0, 0)
            pixels[planet_num * 9 + 6] = (0, 0, 0, 0)
            pixels[planet_num * 9 + 7] = (0, 0, 0, 0)
            pixels[planet_num * 9 + 8] = (0, 0, 0, 0)

            for i in range(LED_count):
                if planet_num % 2 == 1:
                    pixels[planet_num * 9 + 9 - (i + 1)] = LED[i]
                    pixels.show()
                if planet_num % 2 == 0:
                    pixels[planet_num * 9 + i] = LED[i]
                    pixels.show()

        elif action == "sett":
            print('action is:', action)
            logging.info('action is: %s' % action)

            pixels[planet_num * 9] = (0, 0, 0, 0)
            pixels[planet_num * 9 + 1] = (0, 0, 0, 0)
            pixels[planet_num * 9 + 2] = (0, 0, 0, 0)
            pixels[planet_num * 9 + 3] = (0, 0, 0, 0)
            pixels[planet_num * 9 + 4] = (0, 0, 0, 0)
            pixels[planet_num * 9 + 5] = (0, 0, 0, 0)
            pixels[planet_num * 9 + 6] = (0, 0, 0, 0)
            pixels[planet_num * 9 + 7] = (0, 0, 0, 0)
            pixels[planet_num * 9 + 8] = (0, 0, 0, 0)
            pixels.show()

            time.sleep(5)

            if [
                    item for item in planet_list
                    if item[1] == planetname and item[2] == 'rise'
            ]:
                #get next set timestamp only and add to list if there's already a 'rise' timestamp
                next_set_timestamp = planet_timestamp(planetname, 'sett', ts,
                                                      planets, city, eph,
                                                      names)
                next_set_tuple = (next_set_timestamp, planetname, 'sett')
                planet_list.append(next_set_tuple)
                print('rise found in planet_list')
                print('next set:', next_set_timestamp)
                logging.info('rise found in planet_list')
                logging.info('next set: %s' % next_set_timestamp)

            else:
                print('no rise found in planet_list')
                logging.info('no rise found in planet_list')
                #get next rise timestamp and add to tuple if there isn't a rise
                next_rise_timestamp = planet_timestamp(planetname, 'rise', ts,
                                                       planets, city, eph,
                                                       names)
                next_rise_tuple = (next_rise_timestamp, planetname, 'rise')
                planet_list.append(next_rise_tuple)
                print('next rise:', next_rise_timestamp)
                logging.info('next rise: %s' % next_rise_timestamp)

                #get next set timestamp and add to list
                next_set_timestamp = planet_timestamp(planetname, 'sett', ts,
                                                      planets, city, eph,
                                                      names)
                next_set_tuple = (next_set_timestamp, planetname, 'sett')
                planet_list.append(next_set_tuple)
                print('next set:', next_set_timestamp)
                logging.info('next set: %s' % next_set_timestamp)

        now = int(time.time())  # return time since the Epoch (embedded)
        print('current unix timestamp:', now)
        logging.info('current unix timestamp: %s' % now)

        now_local = time.localtime(now)
        now_local_str = " ".join(map(str, now_local))
        print('current local time:', now_local_str)
        logging.info('current local time: %s' % now_local_str)

        list.sort(planet_list)
        print('planet list:')
        print(planet_list)
        logging.info('planet list: %s' % planet_list)
Exemplo n.º 28
0
print("date and time =", dt_string)

geocentric = satellite.at(t)
#print(geocentric.position.km)

subpoint = wgs84.subpoint(geocentric)

print(subpoint)
print('Latitude:', subpoint.latitude)
print('Longitude:', subpoint.longitude)
print('Elevation (m):', int(subpoint.elevation.m))
print()

#(z, e, n) = LLtoUTM(23,subpoint.latitude, subpoint.longitude)

me = wgs84.latlon(48.873459, 2.358040)

difference = satellite - me
#print(difference)

topocentric = difference.at(t)
#print(topocentric.position.km)

alt, az, distance = topocentric.altaz()

if alt.degrees > 0:
    print('The ISS is above the horizon')

#print (alt.degrees)
print("Altitude: ", alt)
print("Azimut: ", az)
Exemplo n.º 29
0
from skyfield.api import N, W, wgs84
from skyfield.api import load

planets = load('de421.bsp')
earth, mars = planets['earth'], planets['mars']

ts = load.timescale()
t = ts.now()

boston = earth + wgs84.latlon(42.3583 * N, 71.0636 * W)
astrometric = boston.at(t).observe(mars)
alt, az, d = astrometric.apparent().altaz()

print(alt)
print(az)
def test_astroby_skyfield_horizons():
    """
    ### Astropy 與 Skyfield 取得太陽座標對照表

    * 基本上,Astropy 的 get_obj 會得到從地心看太陽的 GCRS 赤道座標,對應於 Skyfield 的 earth.at(t).observe(sun).apparent()。

    * Astropy 用 gcrscoord.transform_to(GeocentricTrueEcliptic(equinox = t)) 將 GCRS 赤道座標轉成真時黃道座標(true ecliptic),
        對應於 Skyfield 的 gcrscoord.frame_latlon(ecliptic_frame)。
    """
    timestr = "2021-4-20 9:37"
    t_astropy = Time(timestr, scale='utc')
    solar_system_ephemeris.set('de430.bsp')
    sun_astropy_apparent = get_body('sun', t_astropy)
    t_skyfield = ts.utc(2021, 4, 20, 9, 37)
    sun_skyfield_astrometric = earth.at(t_skyfield).observe(sun).radec()
    sun_skyfield_apparent = earth.at(t_skyfield).observe(sun).apparent()
    # print(sun_skyfield_astrometric)
    print("\n比較 GCRS astrometric")
    print("sun_skyfield_astrometric", sun_skyfield_astrometric[0]._degrees,
          sun_skyfield_astrometric[1]._degrees, sun_skyfield_astrometric[2].km)
    # 比較 GCRS
    print("\n比較 GCRS apparent")
    print(sun_astropy_apparent)
    print('sun_astropy_apparent in (deg,deg,km) :',
          sun_astropy_apparent.ra.deg, sun_astropy_apparent.dec.deg,
          sun_astropy_apparent.distance.km)
    radec_skyfield = sun_skyfield_apparent.radec()
    print('sun_skyfield_apparent in (deg,deg,km) :',
          radec_skyfield[0]._degrees, radec_skyfield[1]._degrees,
          radec_skyfield[2].km)

    # 比較 GeocentricTrueEcliptic
    print('\n比較 GeocentricTrueEcliptic')
    sun_ecliptic_astropy = sun_astropy_apparent.transform_to(
        GeocentricTrueEcliptic(equinox=t_astropy))
    sun_ecliptic_skyfield = sun_skyfield_apparent.frame_latlon(ecliptic_frame)
    print(sun_ecliptic_astropy)
    print(sun_ecliptic_skyfield[1]._degrees, sun_ecliptic_skyfield[0]._degrees,
          sun_ecliptic_skyfield[2].km)

    # 比較 TETE
    print('\n比較 TreeEclipticTrueEquator(TETE)')
    sun_tete_astropy = sun_astropy_apparent.transform_to(
        TETE(obstime=t_astropy))
    sun_tete_skyfield = sun_skyfield_apparent.radec(epoch='date')
    print(sun_tete_astropy)
    print(sun_tete_skyfield[0]._degrees, sun_tete_skyfield[1]._degrees,
          sun_tete_skyfield[2].km)

    sun_by_earth = Horizons(id='10',
                            id_type='majorbody',
                            location='500',
                            epochs={
                                'start': "2021-4-20 9:37",
                                'stop': "2021-4-20 9:38",
                                'step': '1'
                            })
    sun_by_earth_ephem = sun_by_earth.ephemerides(quantities='1,2,4,20,31')
    print("jpl 資料")
    print(sun_by_earth_ephem['RA', 'DEC', 'RA_app', 'DEC_app', 'delta',
                             'ObsEclLon', 'ObsEclLat'])

    # 比較 AltAz
    print("\n比較 AltAz")
    location_astropy = EarthLocation(lon=121 * u.deg,
                                     lat=25 * u.deg,
                                     height=0 * u.m)
    moon_taipei_astropy = get_body('moon', t_astropy, location_astropy)
    # print(moon_taipei_astropy)
    _altaz_astropy = AltAz(obstime=t_astropy, location=location_astropy)
    moon_taipei_altaz_astropy = moon_taipei_astropy.transform_to(
        _altaz_astropy)
    print("moon_taipei_altaz_astropy: ", moon_taipei_altaz_astropy)

    taipei = earth + wgs84.latlon(25 * N, 121 * E, elevation_m=0)
    moon_taipei_skyfield = taipei.at(t_skyfield).observe(moon).apparent()
    alt, az, distance = moon_taipei_skyfield.altaz()
    print("moon_taipei_altaz_skyfield: ", az._degrees, alt._degrees,
          distance.km)

    moon_by_taipei = Horizons(id='301',
                              id_type='majorbody',
                              location={
                                  'lon': 121,
                                  'lat': 25,
                                  'elevation': 0
                              },
                              epochs={
                                  'start': "2021-4-20 9:37",
                                  'stop': "2021-4-20 9:38",
                                  'step': '1'
                              })
    moon_by_taipei_ephem = moon_by_taipei.ephemerides(quantities='1,2,4,20,31')
    print("moon_taipei_jpl (AZ EL)", moon_by_taipei_ephem['AZ', 'EL'])