Beispiel #1
0
def RAAN_to_LTAN(RAAN, UTC, EOP_data):
    '''
    This function computes the Local Time of Ascending Node for a 
    sunsynchronous orbit.
    
    Parameters
    ------
    RAAN : float
        Right Ascension of Ascending Node [deg]
    UTC : datetime object
        time in UTC
    EOP_data : dictionary
        EOP data for the given time including pole coordinates and offsets,
        time offsets, and length of day 
        
    Returns
    ------
    LTAN : float
        local time of ascending node, decimal hour in range [0, 24) 
    '''
    
    # Compute TT in JD format
    TT_JD = utcdt2ttjd(UTC, EOP_data['TAI_UTC'])
    
    # Compute TT in centuries since J2000 epoch
    TT_cent = jd2cent(TT_JD)
    
    # Compute apparent right ascension of the sun
    sun_eci_geom, sun_eci_app = compute_sun_coords(TT_cent)
    sun_ra = atan2(sun_eci_app[1], sun_eci_app[0]) * 180./pi     # deg
    
    # Compute LTAN in decimal hours
    LTAN = ((RAAN - sun_ra)/15. + 12.) % 24.    # decimal hours    
    
    return LTAN
Beispiel #2
0
def teme2gcrf(r_TEME, v_TEME, UTC, IAU1980nut, EOP_data):
    '''
    This function converts position and velocity vectors from the True
    Equator Mean Equinox (TEME) frame used for TLEs to the GCRF inertial
    frame.
    
    Parameters
    ------
    r_TEME : 3x1 numpy array
        position vector in TEME frame
    v_TEME : 3x1 numpy array
        velocity vector in TEME frame
    UTC : datetime object
        time in UTC
    IAU1980nut : 2D numpy array
        nutation coefficients
    EOP_data : dictionary
        EOP data for the given time including pole coordinates and offsets,
        time offsets, and length of day  
    
    Returns
    ------
    r_GCRF : 3x1 numpy array
        position vector in GCRF frame
    v_GCRF : 3x1 numpy array
        velocity vector in GCRF frame    
    '''

    # Compute TT in JD format
    TT_JD = utcdt2ttjd(UTC, EOP_data['TAI_UTC'])

    # Compute TT in centuries since J2000 epoch
    TT_cent = jd2cent(TT_JD)

    # IAU 1976 Precession
    P = compute_precession_IAU1976(TT_cent)

    # IAU 1980 Nutation
    N, FA, Eps0, Eps_true, dPsi, dEps = \
        compute_nutation_IAU1980(IAU1980nut, TT_cent, EOP_data['ddPsi'],
                                 EOP_data['ddEps'])

    # Equation of the Equinonx 1982
    R = eqnequinox_IAU1982_simple(dPsi, Eps0)

    # Compute transformation matrix and output
    GCRF_TEME = np.dot(P, np.dot(N, R))

    r_GCRF = np.dot(GCRF_TEME, r_TEME)
    v_GCRF = np.dot(GCRF_TEME, v_TEME)

    return r_GCRF, v_GCRF
Beispiel #3
0
def itrf2gcrf(r_ITRF, v_ITRF, UTC, EOP_data, XYs_df=[]):
    '''
    This function converts a position and velocity vector in the ITRF(ECEF)
    frame to the GCRF(ECI) frame using the IAU 2006 precession and 
    IAU 2000A_R06 nutation theories. This routine employs a hybrid of the 
    "Full Theory" using Fukushima-Williams angles and the CIO-based method.  

    Specifically, this routine interpolates a table of X,Y,s values and then
    uses them to construct the BPN matrix directly.  The X,Y,s values in the 
    data table were generated using Fukushima-Williams angles and the 
    IAU 2000A_R06 nutation theory.  This general scheme is outlined in [3]
    and [4].
    
    Parameters
    ------
    r_ITRF : 3x1 numpy array
        position vector in ITRF
    v_ITRF : 3x1 numpy array
        velocity vector in ITRF
    UTC : datetime object
        time in UTC
    EOP_data : dictionary
        EOP data for the given time including pole coordinates and offsets,
        time offsets, and length of day  
    
    Returns
    ------
    r_GCRF : 3x1 numpy array
        position vector in GCRF
    v_GCRF : 3x1 numpy array
        velocity vector in GCRF
    
    '''

    # Form column vectors
    r_ITRF = np.reshape(r_ITRF, (3, 1))
    v_ITRF = np.reshape(v_ITRF, (3, 1))

    # Compute UT1 in JD format
    UT1_JD = utcdt2ut1jd(UTC, EOP_data['UT1_UTC'])

    # Compute TT in JD format
    TT_JD = utcdt2ttjd(UTC, EOP_data['TAI_UTC'])

    # Compute TT in centuries since J2000 epoch
    TT_cent = jd2cent(TT_JD)

    # Construct polar motion matrix (ITRS to TIRS)
    W = compute_polarmotion(EOP_data['xp'], EOP_data['yp'], TT_cent)

    # Contruct Earth rotaion angle matrix (TIRS to CIRS)
    R = compute_ERA(UT1_JD)

    # Construct Bias-Precessino-Nutation matrix (CIRS to GCRS/ICRS)
    XYs_data = init_XYs2006(UTC, UTC, XYs_df)
    X, Y, s = get_XYs(XYs_data, TT_JD)

    # Add in Free Core Nutation (FCN) correction
    X = EOP_data['dX'] + X  # rad
    Y = EOP_data['dY'] + Y  # rad

    # Compute Bias-Precssion-Nutation (BPN) matrix
    BPN = compute_BPN(X, Y, s)

    # Transform position vector
    ecef2eci = np.dot(BPN, np.dot(R, W))
    r_GCRF = np.dot(ecef2eci, r_ITRF)

    # Transform velocity vector
    # Calculate Earth rotation rate, rad/s (Vallado p227)
    wE = 7.29211514670639e-5 * (1 - EOP_data['LOD'] / 86400)
    r_TIRS = np.dot(W, r_ITRF)

    v_GCRF = np.dot(
        BPN,
        np.dot(R, (np.dot(W, v_ITRF) +
                   np.cross(np.array([[0.], [0.], [wE]]), r_TIRS, axis=0))))

    return r_GCRF, v_GCRF
Beispiel #4
0
def batch_eop_rotation_matrices(UTC_list,
                                eop_alldata_text,
                                eop_flag='linear',
                                GMST_only_flag=False):
    '''
    This function generates a list of rotation matrices between TEME/GCRF and
    GCRF/ITRF for use in coordinate transformations.  The function can process
    a large array of times and has flags to control the level of fidelity of
    the transformation, in order to facilitate good computational performance
    for a large number of transforms.
    
    Parameters
    ------
    UTC_list : list
        list of datetime object to compute Frame Rotation matrices for
    eop_alldata_text : string
        string containing observed and predicted EOP data, no header
        information
    increment : float, optional
        time increment between desired frame rotations [sec] (default=10.)
    eop_flag : string, optional
        flag to determine how to determine EOP parameters from input text data
        'zeros' = set all EOP values to zero (~2km error)
        'nearest' = set EOP values to nearest whole day (~3m error)
        'linear' = linearly interpolate EOP values between 2 nearest days (~20cm error)
        (default = 'linear')
    GMST_only_flag : boolean, optional
        flag to determine whether to apply only the Earth rotation angle for
        the GCRF/ITRF transformation (i.e., no precession, nutation, polar motion)
        True = apply GMST Earth rotation angle only (no P, N, W)
        False = apply full transformation including P, N, W
        (default = False)
    
    Returns
    ------
    GCRF_TEME_list : list of 3x3 numpy arrays
        transformation matrix at each time for GCRF/TEME
        r_GCRF = GCRF_TEME * r_TEME
    ITRF_GCRF_list : list of 3x3 numpy arrays
        transformation matrix at each time for GCRF/TEME
        r_ITRF = ITRF_GCRF * r_GCRF
    
    '''

    # Initialize Output
    GCRF_TEME_list = []
    ITRF_GCRF_list = []

    # Constants
    arcsec2rad = (1. / 3600.) * pi / 180.

    # Retrieve IAU Nutation data from file
    IAU1980_nut = get_nutation_data()

    # Retrieve polar motion data from file
    XYs_df = get_XYs2006_alldata()

    # Generate MJD list
    MJD_list = [dt2mjd(UTC) for UTC in UTC_list]

    # Loop over times
    for kk in range(len(MJD_list)):

        MJD_kk = MJD_list[kk]
        UTC_kk = UTC_list[kk]
        #        UTC_kk = mjd2dt(MJD_kk)

        # Compute the appropriate EOP values for this time using the input
        # text data.  Per Reference 4 Table 2-3, the following error levels are
        # expected for different levels of fidelity in the approximation

        # Set all EOPs to zero
        # Expected error level ~2km in GEO
        if eop_flag == 'zeros':

            xp = 0.
            yp = 0.
            UT1_UTC = 0.
            LOD = 0.
            ddPsi = 0.
            ddEps = 0.
            dX = 0.
            dY = 0.
            TAI_UTC = 0.

        # Read EOP text data for higher level approximations
        else:
            nchar = 102
            nskip = 1
            nlines = 0
            MJD_int = int(MJD_kk)

            # Get closest lines from EOP text data
            # First index have to search text data
            if kk == 0:

                MJD_prior = copy.copy(MJD_int)

                # Find EOP data lines around time of interest
                for ii in range(len(eop_alldata_text)):
                    start = ii + nlines * (nchar + nskip)
                    stop = ii + nlines * (nchar + nskip) + nchar
                    line = eop_alldata_text[start:stop]
                    nlines += 1

                    MJD_line = int(line[11:16])

                    if MJD_line == MJD_int:
                        line0 = line
                    if MJD_line == MJD_int + 1:
                        line1 = line
                        break

            # Otherwise, we can use previous knowledge
            else:

                # If it's the same day as last time we can just reuse line0
                # and line1.  Otherwise, we have to increment nlines to get
                # the new line1
                if MJD_int == MJD_prior + 1:

                    print(MJD_int)
                    print(MJD_prior)
                    print(line0)
                    print(line1)

                    # Find EOP data lines around time of interest
                    for ii in range(len(eop_alldata_text)):
                        start = ii + nlines * (nchar + nskip)
                        stop = ii + nlines * (nchar + nskip) + nchar
                        line = eop_alldata_text[start:stop]
                        nlines += 1

                        MJD_line = int(line[11:16])

                        if MJD_line == MJD_int:
                            line0 = line
                        if MJD_line == MJD_int + 1:
                            line1 = line
                            break

#                    line0 = copy.copy(line1)
#                    nlines += 1
#                    start = ii + nlines*(nchar+nskip)
#                    stop = ii + nlines*(nchar+nskip) + nchar
#                    line1 = eop_alldata_text[start:stop]
#
#                    MJD_line = int(line[11:16])
#                    if MJD_line != MJD_int:
#                        print(MJD_line)
#                        print(MJD_int)
#                        sys.exit('Wrong MJD value encountered!')

                    MJD_prior = MJD_int


#                    print('\n')
#                    print(nlines)
#                    print(start)
#                    print(stop)
#                    print(line0)
#                    print(line1)
#
#                    mistake

# Read the EOP values for each line
            line0_array = eop_read_line(line0)
            line1_array = eop_read_line(line1)

            # Set all EOPs to values for nearest day
            # Expected error level ~3.6m max (0.8m RMS) in GEO
            if eop_flag == 'nearest':
                if (MJD_kk - MJD_int) < 0.5:
                    xp = line0_array[1] * arcsec2rad
                    yp = line0_array[2] * arcsec2rad
                    UT1_UTC = line0_array[3]
                    LOD = line0_array[4]
                    ddPsi = line0_array[5] * arcsec2rad
                    ddEps = line0_array[6] * arcsec2rad
                    dX = line0_array[7] * arcsec2rad
                    dY = line0_array[8] * arcsec2rad
                    TAI_UTC = line0_array[9]

                else:
                    xp = line1_array[1] * arcsec2rad
                    yp = line1_array[2] * arcsec2rad
                    UT1_UTC = line1_array[3]
                    LOD = line1_array[4]
                    ddPsi = line1_array[5] * arcsec2rad
                    ddEps = line1_array[6] * arcsec2rad
                    dX = line1_array[7] * arcsec2rad
                    dY = line1_array[8] * arcsec2rad
                    TAI_UTC = line1_array[9]

            # Linear interpolation of values between two nearest days
            # Expected error level ~22cm max (4cm RMS) in GEO
            if eop_flag == 'linear':

                # Adjust UT1-UTC column in case leap second occurs between lines
                line0_array[3] -= line0_array[9]
                line1_array[3] -= line1_array[9]

                # Leap seconds do not interpolate
                TAI_UTC = line0_array[9]

                # Linear interpolation
                dt = MJD_kk - line0_array[0]
                interp = (line1_array[1:] - line0_array[1:])/ \
                    (line1_array[0] - line0_array[0]) * dt + line0_array[1:]

                # Convert final output
                xp = interp[0] * arcsec2rad
                yp = interp[1] * arcsec2rad
                UT1_UTC = interp[2] + TAI_UTC
                LOD = interp[3]
                ddPsi = interp[4] * arcsec2rad
                ddEps = interp[5] * arcsec2rad
                dX = interp[6] * arcsec2rad
                dY = interp[7] * arcsec2rad

        # Compute rotation matrices for transform
        # Compute current times
        UT1_JD = utcdt2ut1jd(UTC_kk, UT1_UTC)
        TT_JD = utcdt2ttjd(UTC_kk, TAI_UTC)
        TT_cent = jd2cent(TT_JD)

        # GCRF/ITRF Transformation
        # Contruct Earth rotaion angle matrix (TIRS to CIRS)
        R_CIRS = compute_ERA(UT1_JD)

        if GMST_only_flag:
            ITRF_GCRF = R_CIRS.T

        else:
            # Construct polar motion matrix (ITRS to TIRS)
            W = compute_polarmotion(xp, yp, TT_cent)

            # Construct Bias-Precessino-Nutation matrix (CIRS to GCRS/ICRS)
            XYs_data = init_XYs2006(UTC_kk, UTC_kk, XYs_df)

            X, Y, s = get_XYs(XYs_data, TT_JD)

            # Add in Free Core Nutation (FCN) correction
            X = dX + X  # rad
            Y = dY + Y  # rad

            # Compute Bias-Precssion-Nutation (BPN) matrix
            BPN = compute_BPN(X, Y, s)

            # Transform position vector
            ITRF_GCRF = np.dot(W.T, np.dot(R_CIRS.T, BPN.T))

        # TEME/GCRF Transformation
        # IAU 1976 Precession
        P = compute_precession_IAU1976(TT_cent)

        # IAU 1980 Nutation
        N, FA, Eps0, Eps_true, dPsi, dEps = \
            compute_nutation_IAU1980(IAU1980_nut, TT_cent, ddPsi, ddEps)

        # Equation of the Equinonx 1982
        R_1982 = eqnequinox_IAU1982_simple(dPsi, Eps0)

        # Compute transformation matrix and output
        GCRF_TEME = np.dot(P, np.dot(N, R_1982))

        # Store output
        GCRF_TEME_list.append(GCRF_TEME)
        ITRF_GCRF_list.append(ITRF_GCRF)

    return GCRF_TEME_list, ITRF_GCRF_list