예제 #1
0
def main():
    ts = load.timescale()
    t = ts.tt(2018, 1, 22, 9, 9, 20)
    trial_angles = 10, 20, 30, 40  # the error peaks around 20 degrees
    trial_elevations = 0, 6000, AU_M
    print(__doc__)
    for n in range(1, 5):
        print('=== {} iterations ==='.format(n))
        print('')
        for elevation_m in trial_elevations:
            for degrees in trial_angles:
                top = Topos(latitude_degrees=degrees,
                            longitude_degrees=123,
                            elevation_m=elevation_m)
                xyz_au = top.at(t).position.au
                xyz_au = einsum('ij...,j...->i...', t.M, xyz_au)
                lat, lon, elev = reverse_terra(xyz_au, t.gast, n)
                lat = lat / DEG2RAD
                error_mas = 60.0 * 60.0 * 1000.0 * abs(degrees - lat)
                print('latitude {} degrees, elevation {} m'
                      ' -> error of {:.2f} mas'.format(degrees, elevation_m,
                                                       error_mas))
        print('')
    print("""\
Given that iterations=3 pushes the maximum error from tens of mas ("mas"
means " milli-arcsecond") down to hundredths of a mas, it is the value
we have chosen as a default.  A fourth iteration, if we ever chose to
perform one, pushes the error down to "0.00 mas".
""")
def main():
    ts = load.timescale()
    t = ts.tt(2018, 1, 22, 9, 9, 20)
    trial_angles = 10, 20, 30, 40  # the error peaks around 20 degrees
    trial_elevations = 0, 6000, AU_M
    print(__doc__)
    for n in range(1, 5):
        print('=== {} iterations ==='.format(n))
        print('')
        for elevation_m in trial_elevations:
            for degrees in trial_angles:
                top = Topos(latitude_degrees=degrees, longitude_degrees=123,
                            elevation_m=elevation_m)
                xyz_au = top.at(t).position.au
                xyz_au = einsum('ij...,j...->i...', t.M, xyz_au)
                lat, lon, elev = reverse_terra(xyz_au, t.gast, n)
                lat = lat / DEG2RAD
                error_mas = 60.0 * 60.0 * 1000.0 * abs(degrees - lat)
                print('latitude {} degrees, elevation {} m'
                      ' -> error of {:.2f} mas'
                      .format(degrees, elevation_m, error_mas))
        print('')
    print("""\
Given that iterations=3 pushes the maximum error from tens of mas ("mas"
means " milli-arcsecond") down to hundredths of a mas, it is the value
we have chosen as a default.  A fourth iteration, if we ever chose to
perform one, pushes the error down to "0.00 mas".
""")
예제 #3
0
def test_itrf_vector():
    ts = load.timescale(builtin=True)
    t = ts.utc(2019, 11, 2, 3, 53)
    top = Topos(latitude_degrees=45,
                longitude_degrees=0,
                elevation_m=constants.AU_M - constants.ERAD)
    x, y, z = top.at(t).itrf_xyz().au
    assert abs(x - 0.7071) < 1e-4
    assert abs(y - 0.0) < 1e-14
    assert abs(z - 0.7071) < 1e-4
예제 #4
0
def test_negation():
    ts = load.timescale()
    t = ts.utc(2020, 8, 30, 16, 5)
    usno = Topos('38.9215 N', '77.0669 W', elevation_m=92.0)
    neg = -usno
    p1 = usno.at(t)
    p2 = neg.at(t)
    assert (p1.position.au == -p2.position.au).all()
    assert (p1.velocity.au_per_d == -p2.velocity.au_per_d).all()

    # A second negation should return the unwrapped original.
    neg = -neg
    assert neg is usno
예제 #5
0
def test_from_altaz_parameters(ts):
    usno = Topos('38.9215 N', '77.0669 W', elevation_m=92.0)
    t = ts.tt(jd=api.T0)
    p = usno.at(t)
    a = api.Angle(degrees=10.0)
    d = api.Distance(au=0.234)
    with assert_raises(ValueError, 'the alt= parameter with an Angle'):
        p.from_altaz(alt='Bad value', alt_degrees=0, az_degrees=0)
    with assert_raises(ValueError, 'the az= parameter with an Angle'):
        p.from_altaz(az='Bad value', alt_degrees=0, az_degrees=0)
    p.from_altaz(alt=a, alt_degrees='bad', az_degrees=0)
    p.from_altaz(az=a, alt_degrees=0, az_degrees='bad')
    assert str(p.from_altaz(alt=a, az=a).distance()) == '0.1 au'
    assert str(p.from_altaz(alt=a, az=a, distance=d).distance()) == '0.234 au'
예제 #6
0
def angle_2d(lat, lon, y, m, d, h):
    # given surface lat lon and time, calculate the its angles involving satellite and Sun

    # information about satellites (chose GOES 16)
    sats = api.load.tle('https://celestrak.com/NORAD/elements/goes.txt')
    satellite = sats['GOES 16 [+]']

    # planets
    planets = load('de421.bsp')
    sun = planets['sun']
    earth = planets['earth']

    # create array to hold angles
    angles = np.zeros((len(lat), len(lon), 5))

    for i in range(len(lat)):
        for j in range(len(lon)):
            #time
            ts = api.load.timescale()
            tm = ts.tt(y, m, d, h, 0, 0)

            # call the surface station "boston"
            boston = Topos(str(lat[i]) + ' N',
                           str(lon[j]) + ' W',
                           elevation_m=0.0)

            # the angle between the two vectors: earth center to satellite and earth center to observer
            theta = satellite.at(tm).separation_from(boston.at(tm))

            # geometry
            difference = satellite - boston
            geometry = difference.at(tm).altaz()

            # angles involving satellite
            scan = np.round(180 - (90 + geometry[0].degrees + theta.degrees),
                            2)
            zenith = np.round(geometry[0].degrees, 2)
            azimuth = np.round(geometry[1].degrees, 2)
            angles[i, j, 0] = zenith
            angles[i, j, 1] = azimuth
            angles[i, j, 2] = scan

            # angles involving the Sun
            observer = earth + boston
            geo2 = observer.at(tm).observe(sun).apparent().altaz()
            zenithsun = np.round(geo2[0].degrees, 2)
            azimuthsun = np.round(geo2[1].degrees, 2)
            angles[i, j, 3] = zenithsun
            angles[i, j, 4] = azimuthsun
    return angles
예제 #7
0
def test_frame_rotation():
    # Does a frame's rotation and twist get applied in the right
    # directions?  Let's test whether the position and velocity of an
    # ITRS vector (ERAD,0,0) are restored to the proper orientation.
    top = Topos(latitude_degrees=0, longitude_degrees=0)
    ts = load.timescale()
    t = ts.utc(2020, 11, 27, 15, 34)  # Arbitrary time; LST ~= 20.03.
    p = top.at(t)

    r = p.frame_xyz(itrs)
    assert max(abs(r.m - [ERAD, 0, 0])) < 4e-8 # meters

    r, v = p.frame_xyz_and_velocity(itrs)
    assert max(abs(r.m - [ERAD, 0, 0])) < 4e-8 # meters
    assert max(abs(v.km_per_s)) < 3e-15 # km/s
예제 #8
0
def test_itrf_vector():
    top = Topos(latitude_degrees=45, longitude_degrees=0,
                elevation_m=constants.AU_M - constants.ERAD)

    x, y, z = top.itrs_position.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
예제 #9
0
def test_velocity():
    # 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 = Topos(latitude_degrees=36.7138, longitude_degrees=-112.2169)
    p = jacob.at(t)
    velocity1 = p.position.km[:,1] - p.position.km[:,0]
    velocity2 = p.velocity.km_per_s[:,0]
    print(length_of(velocity2 - factor * velocity1))
    assert length_of(velocity2 - factor * velocity1) < 0.0007
예제 #10
0
def test_beneath(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 = Topos(latitude_degrees=angle, longitude_degrees=angle, elevation_m=0)
    p = top.at(t)
    b = p.subpoint()

    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
예제 #11
0
def test_polar_motion_when_computing_topos_position(ts):
    xp_arcseconds = 11.0
    yp_arcseconds = 22.0
    ts.polar_motion_table = [0.0], [xp_arcseconds], [yp_arcseconds]

    top = Topos(latitude=(42, 21, 24.1), longitude=(-71, 3, 24.8),
                elevation_m=43.0)
    t = ts.utc(2020, 11, 12, 22, 2)

    # "expected" comes from:
    # from novas.compat import ter2cel
    # print(ter2cel(t.whole, t.ut1_fraction, t.delta_t, xp_arcseconds,
    #               yp_arcseconds, top.itrs_position.km, method=1))

    expected = (3146.221313017412, -3525.955228249315, 4269.301880718039)
    assert max(abs(top.at(t).position.km - expected)) < 6e-11
예제 #12
0
def _calculateGroundTrack(earth, satellite, timeset):
    topoZero = Topos(latitude_degrees=0.0, longitude_degrees=0.0)
    satAbs = earth + satellite

    earthPosition = earth.at(timeset).position.km
    zeroPosition = topoZero.at(timeset).position.km
    satPosition = satAbs.at(timeset).position.km - earthPosition

    earthRotation = np.arctan2(zeroPosition[1], zeroPosition[2])
    sinRot = np.sin(-earthRotation)
    cosRot = np.cos(-earthRotation)

    xAdj = satPosition[0] * cosRot - satPosition[1] * sinRot
    yAdj = satPosition[0] * sinRot + satPosition[1] * cosRot

    rxy = np.sqrt(xAdj**2 + yAdj**2)
    satLat = np.arctan2(satPosition[2], rxy)
    satLong = np.arctan2(yAdj, xAdj)

    plt.plot(np.rad2deg(satLong), np.rad2deg(satLat), 'o')
예제 #13
0
loc = Topos(38.8892771, -77.0353628)
satellite = EarthSatellite(line1, line2)

# Geocentric
geometry = satellite.at(t)

# Geographic point beneath satellite
subpoint = geometry.subpoint()
latitude = subpoint.latitude
longitude = subpoint.longitude
elevation = subpoint.elevation

# Topocentric
difference = satellite - loc
geometry = difference.at(t)
topoc= loc.at(t)
#
topocentric = difference.at(t)
geocentric = satellite.at(t)
# ------ Start outputs -----------
print ('\n Ephemeris time:', timestring)
print (' JD time: ',t)
print ('',loc)
print ('\n Subpoint Longitude= ', longitude )
print (' Subpoint Latitude = ', latitude )
print (' Subpoint Elevation=  {0:.3f}'.format(elevation.km),'km')
# ------ Step 1: compute sat horizontal coords ------
alt, az, distance = topocentric.altaz()
if alt.degrees > 0:
    print('\n',satellite, '\n is above the horizon')
print ('\n Altitude= ', alt.degrees )
예제 #14
0
def read_obs(iod_lines):
    """ decodes the iod_line data """

    global ssn
    global epoch_datetime
    # FIXME get rid of these globals

    Sites = CosparSite("data/stations.in")
    csi = .0055878713278878
    zet = .0055888307019922
    the = .0048580335354883

    nobs = len(
        iod_lines)  # Number of iod-compliant formatted lines in the input file

    ll = np.zeros((nobs, 3))
    odata = np.zeros((nobs, 4))
    rd = np.zeros((nobs, 3))

    i = 0
    for iod_line in iod_lines:
        # Grab the most recent version of these variables for writing eventual TLE
        # FIXME Scott's original code grabs the 2nd or "middle" datetime for epoch
        epoch_datetime = iod_line.DateTime
        ssn = iod_line.ObjectNumber

        ts = load.timescale()
        (year, month, day, hour, minute,
         second) = iod_line.DateTime.timetuple()[:6]
        t_skyfield = ts.utc(year, month, day, hour, minute, second)
        t1_jd = t_skyfield.tt

        ra = radians(iod_line.RA)
        dc = radians(iod_line.DEC)

        if (iod_line.Epoch == 4):  # precess from B1950 to J2000
            a = cos(dc) * sin(ra + csi)
            b = cos(the) * cos(dc) * cos(ra + csi) \
                - sin(the) * sin(dc)
            c = sin(the) * cos(dc) * cos(ra + csi) \
                + cos(the) * sin(dc)
            ra = atan(a / b)  # ra - zet
            if (b < 0):
                ra += pi
            ra += zet  # right ascension, radians
            ra += 1 / 30000
            dc = asin(c)
            if (abs(dc) > 1.4):
                dc = c / abs(c) * acos(sqrt(a * a + b * b))

        # precession from J2000
        t = (t1_jd - 2451545) / 36525
        csi = (2306.2181 + .30188 * t + .017998 * t * t) * t * de2ra / 3600
        zet = (2306.2181 + 1.09468 * t + .018203 * t * t) * t * de2ra / 3600
        the = (2004.3109 - .42665 * t - .041833 * t * t) * t * de2ra / 3600
        a = cos(dc) * sin(ra + csi)
        b = cos(the) * cos(dc) * cos(ra + csi) \
            - sin(the) * sin(dc)
        c = sin(the) * cos(dc) * cos(ra + csi) \
            + cos(the) * sin(dc)
        ra = atan(a / b)  # ra - zet
        if (b < 0):
            ra += pi
        ra += zet  # right ascension, radians
        dc = asin(c)
        if (abs(dc) > 1.4):
            dc = c / abs(c) * acos(sqrt(a * a + b * b))

        # line-of-sight vectors
        ll[i][0] = cos(dc) * cos(ra)
        ll[i][1] = cos(dc) * sin(ra)
        ll[i][2] = sin(dc)

        odata[i][0] = t1_jd  # julian date
        odata[i][1] = ra  # ra radians (observed)
        odata[i][2] = dc  # dc radians (observed)
        odata[i][3] = iod_line.Station  # station

        (la, lo, hh) = Sites.topos(iod_line.Station)
        observer_location = Topos(latitude_degrees=la,
                                  longitude_degrees=lo,
                                  elevation_m=hh)

        topocentric = observer_location.at(t_skyfield)
        rd[i] = topocentric.position.km / _XKMPER  # elfind works in units of Earth radii

        i += 1
    # end for
    return odata, ll, rd