Example #1
0
    def __getTIO(self, epoch: datetime.datetime):
        """
        Gets the Terrestrial Intermediate Origin (TIO) locator s'
        Terrestrial Intermediate Ref Sys (TIRS) defined by TIO and CIP.
        TIRS related to to CIRS by Earth Rotation Angle
        :param epoch:
        :return:
        """
        mjd = pySat.pySatTime.UTC2MJD(epoch)
        self.sprime = erfa.sp00(2400000.5, mjd)

        return self.sprime
Example #2
0
def cirs_to_itrs_mat(time):
    # compute the polar motion p-matrix
    xp, yp = get_polar_motion(time)
    sp = erfa.sp00(*get_jd12(time, 'tt'))
    pmmat = erfa.pom00(xp, yp, sp)

    # now determine the Earth Rotation Angle for the input obstime
    # era00 accepts UT1, so we convert if need be
    era = erfa.era00(*get_jd12(time, 'ut1'))

    # c2tcio expects a GCRS->CIRS matrix, but we just set that to an I-matrix
    # because we're already in CIRS
    return erfa.c2tcio(np.eye(3), era, pmmat)
def cirs_to_itrs_mat(time):
    # compute the polar motion p-matrix
    xp, yp = get_polar_motion(time)
    sp = erfa.sp00(*get_jd12(time, 'tt'))
    pmmat = erfa.pom00(xp, yp, sp)

    # now determine the Earth Rotation Angle for the input obstime
    # era00 accepts UT1, so we convert if need be
    era = erfa.era00(*get_jd12(time, 'ut1'))

    # c2tcio expects a GCRS->CIRS matrix, but we just set that to an I-matrix
    # because we're already in CIRS
    return erfa.c2tcio(np.eye(3), era, pmmat)
Example #4
0
def mat_icrs_itrs_equ(epoch, full=False):
    """
        Equinox-based ICRS to ITRS transformation. Employ the IAU 1976 
    precession and IAU 1980 nutation theory.

    Parameter:
    ==========
    epoch: `Time`, scale='utc'
    full: `bool`, default=False
        If full=True, then return approximate rate of mat

    Return:
    =======
    mat: mat = mat_pm * mat_er * mat_nut * mat_pre
    mat_rate: if full=True, return this
        mat_rate = mat_pm * d(mat_er)/dt * mat_nut * mat_pre

    Remark:
    =======
    r_itrs = mat * r_icrs, where vectors are of shape (3,1)
    v_itrs = (mat + mat_rate) * v_icrs
    """
    dut1 = iers.ut1_utc(epoch.jd1, epoch.jd2)
    ut11, ut12 = erfa.utcut1(epoch.jd1, epoch.jd2, dut1)
    tai1, tai2 = erfa.utctai(epoch.jd1, epoch.jd2)
    tt1, tt2 = erfa.taitt(tai1, tai2)
    mat_nut = np.matrix(erfa.nutm80(tt1, tt2))
    mat_pre = np.matrix(erfa.pmat76(tt1, tt2))
    s = erfa.sp00(tt1, tt2)
    x, y = iers.pm_xy(epoch.jd1, epoch.jd2)
    mat_pm = np.matrix(erfa.pom00(x.to_value('rad'), y.to_value('rad'), s))
    era = erfa.gst94(ut11, ut12)
    mat_er = rotation_matrix(era*u.rad, 'z')

    mat = mat_pm * mat_er * mat_nut * mat_pre
    if not full:
        return mat
    else:
        mat_tmp = np.matrix('0, 1, 0; -1, 0, 0; 0, 0, 0', dtype=float) 
        mat_er_rate = 7.292115e-5 * mat_tmp * mat_er  
        mat_rate = mat_pm * mat_er_rate * mat_nut * mat_pre
        return mat, mat_rate
Example #5
0
def _polar_mot_matrix(obstime):
    """
    Form the matrix of polar motion for a given date, IAU 2000.

    The matrix operates in the sense V(TRS) = rpom * V(CIP), meaning that it is the final rotation when computing the
    pointing direction to a celestial source.

    Parameters
    ----------
    obstime : Time
        time at which the polar motion should be calculated.
    Returns
    -------
        3x3 rotation matrix due to polar motion
    """
    # compute the polar motion p-matrix
    xp, yp = get_polar_motion(obstime)
    sp = erfa.sp00(*get_jd12(obstime, 'tt'))
    polar_mot_mat = erfa.pom00(xp, yp, sp)

    return polar_mot_mat
Example #6
0
    def _pvobs(self):
        '''calculates position and velocity of the observatory
           returns position/velocity in AU and AU/d in GCRS reference frame
        '''

        # convert obs position from WGS84 (lat long) to ITRF geocentric coords in AU
        xyz = self.location.to(u.AU).value

        # now we need to convert this position to Celestial Coords
        # specifically, the GCRS coords.
        # conversion from celestial to terrestrial coords given by
        # [TRS] = RPOM * R_3(ERA) * RC2I * [CRS]
        # where:
        # [CRS] is vector in GCRS (geocentric celestial system)
        # [TRS] is vector in ITRS (International Terrestrial Ref System)
        # ERA is earth rotation angle
        # RPOM = polar motion matrix

        tt = self.tt
        mjd = self.utc.mjd

        # we need the IERS values to correct for the precession/nutation of the Earth
        iers_tab = IERS.open()

        # Find UT1, which is needed to calculate ERA
        # uses IERS_B by default , for more recent times use IERS_A download
        try:      
            ut1 = self.ut1 
        except:
            try:
                iers_a_file = download_file(IERS_A_URL, cache=True)
                iers_a = IERS_A.open(iers_a_file)
                print "Trying to download...", iers_a_file
                self.delta_ut1_utc = self.get_delta_ut1_utc(iers_a)
                ut1 = self.ut1
            except:
                # fall back to UTC with degraded accuracy
                warnings.warn('Cannot calculate UT1: using UTC with degraded accuracy') 
                ut1 = self.utc
                
        # Gets x,y coords of Celestial Intermediate Pole (CIP) and CIO locator s
        # CIO = Celestial Intermediate Origin
        # Both in GCRS
        X,Y,S = erfa.xys00a(tt.jd1,tt.jd2)

        # Get dX and dY from IERS B
        dX = np.interp(mjd, iers_tab['MJD'], iers_tab['dX_2000A']) * u.arcsec 
        dY = np.interp(mjd, iers_tab['MJD'], iers_tab['dY_2000A']) * u.arcsec

        # Get GCRS to CIRS matrix
        # can be used to convert to Celestial Intermediate Ref Sys
        # from GCRS.
        rc2i = erfa.c2ixys(X+dX.to(u.rad).value, Y+dY.to(u.rad).value, S)

        # Gets the Terrestrial Intermediate Origin (TIO) locator s'
        # Terrestrial Intermediate Ref Sys (TIRS) defined by TIO and CIP.
        # TIRS related to to CIRS by Earth Rotation Angle
        sp = erfa.sp00(tt.jd1,tt.jd2)

        # Get X and Y from IERS B
        # X and Y are
        xp = np.interp(mjd, iers_tab['MJD'], iers_tab['PM_x']) * u.arcsec
        yp = np.interp(mjd, iers_tab['MJD'], iers_tab['PM_y']) * u.arcsec 

        # Get the polar motion matrix. Relates ITRF to TIRS.
        rpm = erfa.pom00(xp.to(u.rad).value, yp.to(u.rad).value, sp)

        # multiply ITRF position of obs by transpose of polar motion matrix
        # Gives Intermediate Ref Frame position of obs
        x,y,z = np.array([rpmMat.T.dot(xyz) for rpmMat in rpm]).T

        # Functions of Earth Rotation Angle, theta
        # Theta is angle bewtween TIO and CIO (along CIP)
        # USE UT1 here.
        theta = erfa.era00(ut1.jd1,ut1.jd2)
        S,C = np.sin(theta),np.cos(theta)

        # Position #GOT HERE
        pos = np.asarray([C*x - S*y, S*x + C*y, z]).T

        # multiply by inverse of GCRS to CIRS matrix
        # different methods for scalar times vs arrays
        if pos.ndim > 1:
            pos = np.array([np.dot(rc2i[j].T,pos[j]) for j in range(len(pos))])
        else:   
            pos = np.dot(rc2i.T,pos)

        # Velocity
        vel = np.asarray([SR*(-S*x - C*y), SR*(C*x-S*y), np.zeros_like(x)]).T
        # multiply by inverse of GCRS to CIRS matrix
        if vel.ndim > 1:
            vel = np.array([np.dot(rc2i[j].T,vel[j]) for j in range(len(pos))])
        else:        
            vel = np.dot(rc2i.T,vel)

        #return position and velocity
        return pos,vel
Example #7
0
    def _pvobs(self):
        '''calculates position and velocity of the observatory
           returns position/velocity in AU and AU/d in GCRS reference frame
        '''

        # convert obs position from WGS84 (lat long) to ITRF geocentric coords in AU
        xyz = self.location.to(u.AU).value

        # now we need to convert this position to Celestial Coords
        # specifically, the GCRS coords.
        # conversion from celestial to terrestrial coords given by
        # [TRS] = RPOM * R_3(ERA) * RC2I * [CRS]
        # where:
        # [CRS] is vector in GCRS (geocentric celestial system)
        # [TRS] is vector in ITRS (International Terrestrial Ref System)
        # ERA is earth rotation angle
        # RPOM = polar motion matrix

        tt = self.tt
        mjd = self.utc.mjd

        # we need the IERS values to correct for the precession/nutation of the Earth
        iers_tab = IERS.open()

        # Find UT1, which is needed to calculate ERA
        # uses IERS_B by default , for more recent times use IERS_A download
        try:
            ut1 = self.ut1
        except:
            try:
                iers_a_file = download_file(IERS_A_URL, cache=True)
                iers_a = IERS_A.open(iers_a_file)
                self.delta_ut1_utc = self.get_delta_ut1_utc(iers_a)
                ut1 = self.ut1
            except:
                # fall back to UTC with degraded accuracy
                warnings.warn(
                    'Cannot calculate UT1: using UTC with degraded accuracy')
                ut1 = self.utc

        # Gets x,y coords of Celestial Intermediate Pole (CIP) and CIO locator s
        # CIO = Celestial Intermediate Origin
        # Both in GCRS
        X, Y, S = erfa.xys00a(tt.jd1, tt.jd2)

        # Get dX and dY from IERS B
        dX = np.interp(mjd, iers_tab['MJD'], iers_tab['dX_2000A']) * u.arcsec
        dY = np.interp(mjd, iers_tab['MJD'], iers_tab['dY_2000A']) * u.arcsec

        # Get GCRS to CIRS matrix
        # can be used to convert to Celestial Intermediate Ref Sys
        # from GCRS.
        rc2i = erfa.c2ixys(X + dX.to(u.rad).value, Y + dY.to(u.rad).value, S)

        # Gets the Terrestrial Intermediate Origin (TIO) locator s'
        # Terrestrial Intermediate Ref Sys (TIRS) defined by TIO and CIP.
        # TIRS related to to CIRS by Earth Rotation Angle
        sp = erfa.sp00(tt.jd1, tt.jd2)

        # Get X and Y from IERS B
        # X and Y are
        xp = np.interp(mjd, iers_tab['MJD'], iers_tab['PM_x']) * u.arcsec
        yp = np.interp(mjd, iers_tab['MJD'], iers_tab['PM_y']) * u.arcsec

        # Get the polar motion matrix. Relates ITRF to TIRS.
        rpm = erfa.pom00(xp.to(u.rad).value, yp.to(u.rad).value, sp)

        # multiply ITRF position of obs by transpose of polar motion matrix
        # Gives Intermediate Ref Frame position of obs
        x, y, z = np.array([rpmMat.T.dot(xyz) for rpmMat in rpm]).T

        # Functions of Earth Rotation Angle, theta
        # Theta is angle bewtween TIO and CIO (along CIP)
        # USE UT1 here.
        theta = erfa.era00(ut1.jd1, ut1.jd2)
        S, C = np.sin(theta), np.cos(theta)

        # Position #GOT HERE
        pos = np.asarray([C * x - S * y, S * x + C * y, z]).T

        # multiply by inverse of GCRS to CIRS matrix
        # different methods for scalar times vs arrays
        if pos.ndim > 1:
            pos = np.array(
                [np.dot(rc2i[j].T, pos[j]) for j in range(len(pos))])
        else:
            pos = np.dot(rc2i.T, pos)

        # Velocity
        vel = np.asarray(
            [SR * (-S * x - C * y), SR * (C * x - S * y),
             np.zeros_like(x)]).T
        # multiply by inverse of GCRS to CIRS matrix
        if vel.ndim > 1:
            vel = np.array(
                [np.dot(rc2i[j].T, vel[j]) for j in range(len(pos))])
        else:
            vel = np.dot(rc2i.T, vel)

        #return position and velocity
        return pos, vel
Example #8
0
def gcrs2irts_matrix_b(t, eop):
    """
    Ref: http://www.iausofa.org/sofa_pn_c.pdf
    Purpose:
        This function calculates the cartesian transformation matrix for transforming GCRS to ITRS or vice versa
    :param eop:
        eop is a dataframe containing the Earth Orientation Parameters as per IAU definitions
    :param t:
        t is a datetime object or a list of datetime objects with the UTC times for the transformation matrix to be
        calculated for
    :return:
        matrix is a [3,3] numpy array or list of arrays used for transforming GCRS to ITRS or vice versa at the
        specified times; ITRS = matrix @ GCRS
    """
    if not (isinstance(t, Iterable)):
        t = [t]
    matrix = []
    for ti in t:
        year = ti.year
        month = ti.month
        day = ti.day
        hour = ti.hour
        minute = ti.minute
        second = ti.second

        # TT (MJD). */
        djmjd0, date = erfa.cal2jd(iy=year, im=month, id=day)
        # jd = djmjd0 + date
        day_frac = (60.0 * (60.0 * hour + minute) + second) / DAYSEC
        utc = date + day_frac
        Dat = erfa.dat(year, month, day, day_frac)
        tai = utc + Dat / DAYSEC
        tt = tai + 32.184 / DAYSEC

        # UT1. */
        dut1 = eop["UT1-UTC"][date] * (
            1 - day_frac) + eop["UT1-UTC"][date + 1] * day_frac
        tut = day_frac + dut1 / DAYSEC
        # ut1 = date + tut

        # CIP and CIO, IAU 2006/2000A. */
        x, y, s = erfa.xys06a(djmjd0, tt)

        # X, Y offsets
        dx06 = (eop["dX"][date] *
                (1 - day_frac) + eop["dX"][date + 1] * day_frac) * DAS2R
        dy06 = (eop["dY"][date] *
                (1 - day_frac) + eop["dY"][date + 1] * day_frac) * DAS2R

        # Add CIP corrections. */
        x = x + dx06
        y = y + dy06

        # GCRS to CIRS matrix. */
        rc2i = erfa.c2ixys(x, y, s)

        # Earth rotation angle. */
        era = erfa.era00(djmjd0 + date, tut)

        # Form celestial-terrestrial matrix (no polar motion yet). */
        rc2ti = erfa.cr(rc2i)
        rc2ti = eraRZ(era, rc2ti)
        #rc2ti = erfa.rz(era, rc2ti)

        # Polar motion matrix (TIRS->ITRS, IERS 2003). */
        xp = (eop["x"][date] *
              (1 - day_frac) + eop["x"][date + 1] * day_frac) * DAS2R
        yp = (eop["y"][date] *
              (1 - day_frac) + eop["y"][date + 1] * day_frac) * DAS2R
        rpom = erfa.pom00(xp, yp, erfa.sp00(djmjd0, tt))

        # Form celestial-terrestrial matrix (including polar motion). */
        rc2it = erfa.rxr(rpom, rc2ti)
        matrix.append(rc2it)
    if len(matrix) == 1:
        matrix = matrix[0]
    return matrix
Example #9
0
def gcrs_posvel_from_itrf(loc, toas, obsname="obs"):
    """Return a list of PosVel instances for the observatory at the TOA times.

    Observatory location should be given in the loc argument as an astropy
    EarthLocation object. This location will be in the ITRF frame (i.e.
    co-rotating with the Earth).

    The optional obsname argument will be used as label in the returned
    PosVel instance.

    This routine returns a list of PosVel instances, containing the
    positions (m) and velocities (m / s) at the times of the toas and
    referenced to the Earth-centered Inertial (ECI, aka GCRS) coordinates.
    This routine is basically SOFA's pvtob() [Position and velocity of
    a terrestrial observing station] with an extra rotation from c2ixys()
    [Form the celestial to intermediate-frame-of-date matrix given the CIP
    X,Y and the CIO locator s].
    """
    unpack = False
    # If the input is a single TOA (i.e. a row from the table),
    # then put it into a list
    if type(toas) == table.row.Row:
        ttoas = Time([toas["mjd"]])
        unpack = True
    elif type(toas) == table.table.Table:
        ttoas = toas["mjd"]
    elif isinstance(toas, Time):
        if toas.isscalar:
            ttoas = Time([toas])
            unpack = True
        else:
            ttoas = toas
    else:
        if np.isscalar(toas):
            ttoas = Time([toas], format="mjd")
            unpack = True
        else:
            ttoas = toas
    N = len(ttoas)
    if len(ttoas.shape) != 1:
        raise ValueError("At most one-dimensional array of times possible, "
                         "shape was {}".format(ttoas.shape))

    # Get various times from the TOAs as arrays
    tts = np.asarray([(t.jd1, t.jd2) for t in ttoas.tt]).T
    ut1s = np.asarray([(t.jd1, t.jd2) for t in ttoas.ut1]).T
    mjds = np.asarray(ttoas.mjd)

    iers_b = get_iers_b_up_to_date(mjds.max())

    # Get x, y coords of Celestial Intermediate Pole and CIO locator s
    X, Y, S = erfa.xys00a(*tts)

    # Get dX and dY from IERS A in arcsec and convert to radians
    # dX = np.interp(mjds, iers_tab['MJD'], iers_tab['dX_2000A_B']) * asec2rad
    # dY = np.interp(mjds, iers_tab['MJD'], iers_tab['dY_2000A_B']) * asec2rad
    # Get dX and dY from IERS B in arcsec and convert to radians
    dX = np.interp(mjds, iers_b["MJD"].to_value(u.d),
                   iers_b["dX_2000A"].to_value(u.rad))
    dY = np.interp(mjds, iers_b["MJD"].to_value(u.d),
                   iers_b["dY_2000A"].to_value(u.rad))

    # Get GCRS to CIRS matrices
    rc2i = erfa.c2ixys(X + dX, Y + dY, S)

    # Gets the TIO locator s'
    sp = erfa.sp00(*tts)

    # Get X and Y from IERS A in arcsec and convert to radians
    # xp = np.interp(mjds, iers_tab['MJD'], iers_tab['PM_X_B']) * asec2rad
    # yp = np.interp(mjds, iers_tab['MJD'], iers_tab['PM_Y_B']) * asec2rad
    # Get X and Y from IERS B in arcsec and convert to radians
    xp = np.interp(mjds, iers_b["MJD"].to_value(u.d),
                   iers_b["PM_x"].to_value(u.rad))
    yp = np.interp(mjds, iers_b["MJD"].to_value(u.d),
                   iers_b["PM_y"].to_value(u.rad))

    # Get the polar motion matrices
    rpm = erfa.pom00(xp, yp, sp)

    # Observatory geocentric coords in m
    xyzm = np.array([a.to_value(u.m) for a in loc.geocentric])
    x, y, z = np.dot(xyzm, rpm).T

    # Functions of Earth Rotation Angle
    theta = erfa.era00(*ut1s)
    s, c = np.sin(theta), np.cos(theta)
    sx, cx = s * x, c * x
    sy, cy = s * y, c * y

    # Initial positions and velocities
    iposs = np.asarray([cx - sy, sx + cy, z]).T
    ivels = np.asarray([OM * (-sx - cy), OM * (cx - sy), np.zeros_like(x)]).T
    # There is probably a way to do this with np.einsum or something...
    # and here it is .
    poss = np.empty((N, 3), dtype=np.float64)
    vels = np.empty((N, 3), dtype=np.float64)
    poss = np.einsum("ij,ijk->ik", iposs, rc2i)
    vels = np.einsum("ij,ijk->ik", ivels, rc2i)
    r = PosVel(poss.T * u.m, vels.T * u.m / u.s, obj=obsname, origin="earth")
    if unpack:
        return r[0]
    else:
        return r