Exemple #1
0
    def __init__(self,
                 trv          = None,
                 elements     = None,
                 epoch_time   = 0.0,
                 conic_mu     = 3.986004415e14,
                 use_logs     = {'inertial': 'inertial.log',
                                 'elements': 'elements.log'}):
        """ Constructor. Must provide either trv or elements/epoch_time.
        Generally expects everything to be in meters.

        Args:
            trv:        initial time, position, velocity vector
            elements:   orbital elements, e.g. from make_elements()
            epoch_time: epoch time of elements (default: 0.0)
            conic_mu:   gravitational constant for central body (e.g. earth)
                        for conic approximation (default is earth); should be
                        in m^3/s^2"""
        self.conic_mu    = conic_mu
        
        if elements is not None:
            # Note that SPICE uses km, km/s, and we use m, m/s
            trv = np.hstack((0.0, spice.conics(elements, epoch_time) * 1000.0))
        
        self.trv          = trv

        self.logs         = {}
        if use_logs['inertial']:
            self.logs['inertial'] = Log(use_logs['inertial'], mode = 'w')
            self.log_inertial()
        if use_logs['elements']:
            self.logs['elements'] = Log(use_logs['elements'], mode = 'w')
            self.log_elements()
Exemple #2
0
def coes2state( coes, mu = pd.earth[ 'mu' ], deg = True ):
	a, e, i, ta, aop, raan = coes
	if deg:
		i    *= nt.d2r
		ta   *= nt.d2r
		aop  *= nt.d2r
		raan *= nt.d2r

	rp = a * ( 1 - e )

	return spice.conics( [ rp, e, i, raan, aop, ta, 0, mu], 0 )
Exemple #3
0
def dist(x, ele_ast, Gm):
    #x[0] is time and x[1] is true anomaly
    M_A = toMean(x[1], ele_ast[1])
    pos_earth = sp.spkpos('EARTH', x[0], 'J2000', 'LT+S', 'SUN')
    ele = np.zeros(8)
    ele[0:4] = ele_ast[0:4]
    ele[5] = M_A
    ele[6] = 0
    ele[7] = Gm
    xyz_asteroid = sp.conics(ele, 0)[0:3]
    d = np.linalg.norm(pos_earth[1] - xyz_asteroid)
    return d
Exemple #4
0
def dist1(x, ele_ast, Gm):
    #x[0] node, x[1] argp, x[2] time(earth), x[3] tA of asteroid
    pos_earth = sp.spkpos('Earth', x[2], 'J2000', 'LT+S', 'SUN')
    ele = np.zeros(8)
    ele[0:2] = ele_ast[0:2]
    ele[3] = x[0]
    ele[4] = x[1]
    ele[5] = toMean(x[3], ele_ast[1])
    ele[6] = 0
    ele[7] = Gm
    xyz_ast = sp.conics(ele, 0)[0:3]
    d = np.linalg.norm(pos_earth[1] - xyz_ast)
    return d
Exemple #5
0
def cometary2cartesian(epoch, com, frame='ecliptic', mu=cnst.GM):
    """Uses spiceypy to convert cometary orbital elements to
    HELIOCENTRIC (!) Cartesian states

    Parameters:
    -----------
    epoch    ... epoch of orbital elements [JD]
    com      ... cometary element array [q,e,inc(deg),node(deg),peri(deg),tp(JD)]]
    frame    ... reference frame of output Cartesian state ('ecliptic', 'icrf')
    mu       ... Gravitational parameter

    Returns:
    --------
    cart     ... Cartesian state (x,y,z,vx,vy,vz)

    External dependencies:
    ----------------------
    spiceypy (imported as sp)
    numpy (imported as np)
    cometary2keplerian

    """
    kep = cometary2keplerian(epoch, com, mu)[0]

    #   Input for spiceypy.conics:
    #   q    = pericenter distance
    #   e    = eccentricity
    #   i    = inclination (rad)
    #   node = longitude of the ascending node (rad)
    #   w    = argument of pericenter (rad)
    #   M    = mean anomaly at epoch (rad)
    #   T0   = epoch
    #   mu   = gravitational parameter

    cart = sp.conics(
        np.array([
            com[0], com[1],
            np.deg2rad(com[2]),
            np.deg2rad(com[3]),
            np.deg2rad(com[4]),
            np.deg2rad(kep[5]), 0, mu
        ]), 0)

    inframe = 'ecliptic'
    res = frameChange(cart, inframe, frame)

    return res
Exemple #6
0
def keplerian2cartesian(epoch, kep, frame='ecliptic', mu=cnst.GM):
    """Uses spiceypy to convert Keplerian orbital elements
    to heliocentric Cartesian states.

    Parameters:
    -----------
    epoch    ... epoch of orbital elements [JD]
    kep      ... orbital element array [a,e,inc(deg),peri/w(deg),node(deg),M(deg)]
    frame    ... coordinate frame of Cartesian state output: 'ecliptic', 'icrf'
    mu       ... gravitational parameter

    Returns:
    --------
    cart ... heliocentric Cartesian state (x,y,z,vx,vy,vz).

    External dependencies:
    ----------------------
    spiceypy (imported as sp)
    numpy (imported as np)


    """
    q = kep[0] * (1 - kep[1])

    #   Input for spiceypy.conics:
    #   q    = pericenter distance
    #   e    = eccentricity
    #   i    = inclination (deg)
    #   node = longitude of the ascending node (deg)
    #   w    = argument of pericenter (deg)
    #   M    = mean anomaly at epoch (deg)
    #   T0   = epoch
    #   mu   = gravitational parameter

    cart = sp.conics(
        np.array([
            q, kep[1],
            np.deg2rad(kep[2]),
            np.deg2rad(kep[4]),
            np.deg2rad(kep[3]),
            np.deg2rad(kep[5]), 0, mu
        ]), 0)

    inframe = 'ecliptic'
    res = frameChange(cart, inframe, frame)

    return res
Exemple #7
0
def comet_position_error(et,p,elts):
  RP,ECC,ARGP,LNODE,INC,TP = elts
  qRP = RP*au
  qECC = ECC
  qINC = deg2rad(INC)
  qLNODE = deg2rad(LNODE)
  qARGP = deg2rad(ARGP)
  T0 = et
  qTP = spice.str2et('%.14f JD'%TP)
  qTP = qTP - 69.184  #fixme
  qa = np.abs(qRP/(1-qECC))
  qn = np.sqrt(mu/(qa*qa*qa))
  qM0 = qn*(T0-qTP)
  qelts = qRP,qECC,qINC,qLNODE,qARGP,qM0,T0,mu
  state = spice.conics(qelts,et)
  p_c = state[0:3]
  e = p - p_c
  return np.sqrt(np.sum(e*e))
Exemple #8
0
def cometary2cartesian(epoch, com, mu=0.01720209895**2):
    """Uses spiceypy to convert cometary orbital elements to
    HELIOCENTRIC (!) Cartesian states

    Parameters:
    -----------
    epoch ... epoch of orbital elements [JD]
    com ... cometary element array [e,q,tp(JD),node(deg),peri(deg),inc(deg)]]
    mu ... Gravitational parameter

    Returns:
    --------
    cart ... Cartesian state (x,y,z,vx,vy,vz).

    External dependencies:
    ----------------------
    spiceypy (imported as sp)
    numpy (imported as np)
    cometary2keplerian

    """
    kep = cometary2keplerian(epoch, com, mu)

    #   Input for spiceypy.conics:
    #   q    = pericenter distance
    #   e    = eccentricity
    #   i    = inclination (deg)
    #   node = longitude of the ascending node (deg)
    #   w    = argument of pericenter (deg)
    #   M    = mean anomaly at epoch (deg)
    #   T0   = epoch
    #   mu   = gravitational parameter

    cart = sp.conics(
        np.array([
            com[1], com[0],
            np.deg2rad(com[5]),
            np.deg2rad(com[3]),
            np.deg2rad(com[4]),
            np.deg2rad(kep[5]), 0, mu
        ]), 0)
    return cart
Exemple #9
0
def keplerian2cartesian(epoch, kep, mu=0.01720209895**2):
    """Uses spiceypy to convert Keplerian orbital elements
    to HELIOCENTRIC (!) Cartesian states

    Parameters:
    -----------
    epoch ... epoch of orbital elements [JD]
    kep ... orbital element array [a,e,inc(deg),peri/w(deg),node(deg),M(deg)]
    mu ... Gravitational parameter

    Returns:
    --------
    cart ... Cartesian state (x,y,z,vx,vy,vz).

    External dependencies:
    ----------------------
    spiceypy (imported as sp)
    numpy (imported as np)


    """
    q = kep[0] * (1 - kep[1])

    #   Input for spiceypy.conics:
    #   q    = pericenter distance
    #   e    = eccentricity
    #   i    = inclination (deg)
    #   node = longitude of the ascending node (deg)
    #   w    = argument of pericenter (deg)
    #   M    = mean anomaly at epoch (deg)
    #   T0   = epoch
    #   mu   = gravitational parameter

    cart = sp.conics(
        np.array([
            q, kep[1],
            np.deg2rad(kep[2]),
            np.deg2rad(kep[4]),
            np.deg2rad(kep[3]),
            np.deg2rad(kep[5]), 0, mu
        ]), 0)
    return cart
def convert_tle(line1, line2):
    i_deg = float(line2[8:16])
    asc_node_deg = float(line2[17:25])
    e = float("." + line2[26:33])
    a_of_p_deg = float(line2[34:42])
    mean_a_deg = float(line2[43:51])
    mean_motion_rev_day = float(line2[53:63])

    epoch_day = float(line1[20:32])
    tle_year = int(line1[18:20])    
    if (0 <= tle_year <= 56):
        epoch_year = 2000 + tle_year
    else:
        epoch_year = 1900 + tle_year
    
    year_start_to_j2000 = (date(epoch_year, 1, 1) - date(2000, 1, 1)).days - .5
    days_since_j2000 = year_start_to_j2000 + epoch_day - 1
    print(days_since_j2000 + 2451545)
    seconds_since_j2000 = days_since_j2000 * 86400
    
    mean_motion_rad_s = mean_motion_rev_day * (2*m.pi) / 86400
    a = (gm_earth / (mean_motion_rad_s ** 2))**(1/3)
    r_p = a*(1-e)
    r_p_km = r_p / 1000

    i_r = m.radians(i_deg)
    asc_node_r = m.radians(asc_node_deg)
    a_of_p_r = m.radians(a_of_p_deg)
    mean_a_r = m.radians(mean_a_deg)
    gm_earth_km = gm_earth / 1e9
    keplerian_elements = np.array([r_p_km, e, i_r, asc_node_r, a_of_p_r, mean_a_r, seconds_since_j2000, gm_earth_km])

    sv_geo_km = spice.conics(keplerian_elements, seconds_since_j2000)
    sv_geo = sv_geo_km * 1000

    earth_sv = spice.spkssb(3, seconds_since_j2000, 'J2000') * 1000

    sv = np.add(sv_geo, earth_sv)
    return sv
Exemple #11
0
    def get_rv_spice(self, epoch):
        '''returns state-vector using SPICE function at input epoch [MJD]'''

        # convert epoch from MJD to JD for handling in SPICE
        epoch_JD = epoch + 2400000.5

        # compute periapsis
        rp = self.a * (1 - self.e_mag)

        # compute mean anomaly at input epoch
        M0_current = self.get_meanAnom(epoch_JD)

        # insert orbital elements into array
        elements_array = [rp, self.e_mag, self.i, self.LAN, self.omega, M0_current, epoch_JD, self.mu]

        # compute orbital elements
        state_vec = spice.conics(elements_array, epoch_JD)

        # prepare outputs
        r_vec_spice = state_vec[:len(state_vec)//2]
        v_vec_spice = state_vec[len(state_vec)//2:]

        return r_vec_spice, v_vec_spice
Exemple #12
0
    def __init__(self, body, tEntrance, state, tExit=None):

        self.body = body
        self.entranceState = state

        self.tExit = tExit
        self.tEntrance = tEntrance

        self.GM = body.Gmass[0]

        #output vars explanation
        #https://ssd.jpl.nasa.gov/?sb_elem
        #function documentation
        #https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/oscltx_c.html

        self.ele = sp.oscltx(state, convert(tEntrance),
                             self.GM)  #orbital elements in array form
        self.elements = {  #orbital elements in dict form, for clarity
            "RP": self.ele[0],  #Perifocal distance.
            "ECC": self.ele[1],  #Eccentricity.
            "INC": self.ele[2],  #Inclination.
            "LNODE": self.ele[3],  #Longitude of the ascending node.
            "ARGP": self.ele[4],  #Argument of periapsis.
            "M0": self.ele[5],  #Mean anomaly at epoch.
            "T0": self.ele[6],  #Epoch.
            "GM": self.ele[7],  #Gravitational parameter.
            "NU": self.ele[8],  #True anomaly at epoch.
            "A": self.ele[
                9]  #Semi-major axis. A is set to zero if it is not computable.
        }

        self.ele = self.ele[:8]  #trim for further use
        #print(self.elements)

        r = np.array(state[:3])
        v = np.array(state[3:6])
        #https://space.stackexchange.com/questions/22000/simulate-celestial-body-motion-on-hyperbolic-trajectory-2d
        h = np.cross(r, v)
        e = np.cross(v, h) / self.GM - r / mag(r)

        #eccentricity direction as i
        i = e / np.linalg.norm(e)
        self.eccVec = i
        #rotational momentum direction as k
        k = h / np.linalg.norm(h)
        self.up = k
        #figure out j from the first 2 vectors
        j = np.cross(k, i)

        self.rMtrx = np.array([i, j, k])
        #print('rMtrx:',self.rMtrx)

        #print("ijk:", i, j, k)
        #transform 3d coordinate to 2d coordinate
        rR = squish(r, self.rMtrx)
        vR = squish(v, self.rMtrx)

        self.angleIn = None
        self.angleOut = None

        # dA/dt = r * v / 2
        arealVelocity = mag(rR) * mag(vR) / 2
        self.av = arealVelocity

        if not tExit == None:
            #print(tExit - tEntrance).total_seconds()
            self.angleIn = angleFromR(r, self)
            tState = sp.conics(self.ele, convert(tExit))
            self.angleOut = angleFromR(tState[0:3], self)

            if self.angleOut < self.angleIn:
                self.angleOut += np.pi * 2
        return

        #print("results:", rR, vR)

        #
        #find total area sweeped by the object inside the sphere of influence
        #
        #focal distance = rp + semi major axis, take negative value
        foc = -1 * (abs(self.elements["RP"]) + abs(self.elements["A"]))
        A = self.elements['A']
        RP = self.elements['RP']
        E = self.elements['ECC']
        #x coordinate, when setting the actual origin instead
        #of the focus as the origin
        X = lambda x: foc + x
        # scipy integration -- quad (formula, lower bound, upper bound)
        Area = lambda r: 2 * abs(
            quad(lambda x: math.sqrt(x**2 - A**2), X(r[0]), X(RP))[0] * math.
            sqrt(E**2 - 1) + .5 * np.sign(r[0]) * abs(r[0] * r[1]))
        #print(Area(rR))

        self.deltaT = Area(rR) / arealVelocity
        """
        #exit state using symmetry
        vfR = np.array([vR[0]*-1, vR[1]])
        rfR = np.array([rR[0], rR[1]*-1])

        #convert back to 3d J2000 rather than 2d orbital-plane coords
        self.vf = unSquish(vfR, self.rMtrx)
        self.rf = unSquish(rfR, self.rMtrx)
        """

        #exit state using deltaT
        #self.exitState = sp.prop2b(self.GM, state, self.deltaT)
        self.exitState = sp.conics(self.ele, self.deltaT + self.elements['T0'])

        #print("deltaT: ", self.deltaT, "\nvf:", self.vf, "\nrf: ", self.rf)

        if not self.angleIn == None:
            self.angleIn = angleFromR(r, self)
        if not self.angleOut == None:
            self.angleOut = angleFromR(self.exitState[0:3], self)
            if self.angleOut < self.angleIn:
                self.angleOut += np.pi * 2
# function. Note: the mean anomaly is 0 degrees and will be set as a default
# value in the SQLite database
HALE_BOPP_ORB_ELEM = [spiceypy.convrt(HALE_BOPP_DF['Perihelion_dist'] \
                                      .iloc[0], 'AU', 'km'), \
                      HALE_BOPP_DF['e'].iloc[0], \
                      np.radians(HALE_BOPP_DF['i'].iloc[0]), \
                      np.radians(HALE_BOPP_DF['Node'].iloc[0]), \
                      np.radians(HALE_BOPP_DF['Peri'].iloc[0]), \
                      0.0, \
                      HALE_BOPP_DF['EPOCH_ET'].iloc[0], \
                      GM_SUN]

#%%

# Compute the state vector for midnight 2020-05-10
HALE_BOPP_ST_VEC = spiceypy.conics(HALE_BOPP_ORB_ELEM, \
                                   spiceypy.utc2et('2020-05-10'))

# Compare with results from https://ssd.jpl.nasa.gov/horizons.cgi
print('Comparison of the computed state \n' \
      'vector with the NASA HORIZONS results')
print('==========================================')
print(f'X in km (Comp): {HALE_BOPP_ST_VEC[0]:e}')
print('X in km (NASA): 5.348377806424425E+08')
print('==========================================')
print(f'Y in km (Comp): {HALE_BOPP_ST_VEC[1]:e}')
print('Y in km (NASA): -2.702225247057124E+09')
print('==========================================')
print(f'Z in km (Comp): {HALE_BOPP_ST_VEC[2]:e}')
print('Z in km (NASA): -5.904425343521862E+09')
print('==========================================')
print(f'VX in km/s (Comp): {HALE_BOPP_ST_VEC[3]:e}')
Exemple #14
0
def propagate_spice(etr_mjd,
                    eldf,
                    MU=1.32712440018 * 10**11,
                    step=1000,
                    sv_option=True,
                    dr_option=True):
    """
    SPICE-based orbit propagator developed for GTOC4
    Args:
        et_MJD (lst): list including start and end time of propagation (in MJD)
        step (float): steps of propagation
        eldf (pandas df): pandas dataframe of orbital elements to be propagated (expect spacecraft to be first row)
        sv_option (bool): if set to True, compute state-vector
        dr_option (bool): if set to True, compute relative position vector between object of first row and object of other rows
    Returns:
        (tuple): time-array [JD], state-vector (if True), relative position vector (if True), and relative position scalar
            state-vector is3 d numpy array, where:
                1st index: number of arrays = number of bodies to propagate
                2nd index: rows = timesteps
                3rd index: columns = x, y, z, vx, vy, vz, name of object
            relative position vector is also 3d numpy array, where:
                1st index: number of arrays = number of bodies relative to spacecraft
                2nd index: rows = timesteps
                3rd index: columns = dx, dy, dz, name of object
            and relative position salar is 3d numpy array, where: 
                1st index: number of arrays = number of bodies relative to spacecraft
                2nd index: rows = timesteps
                3rd index: name of object
    Examples:
        et, sv, dr, drnorm = propagate_spice(etr_MJD, el_pd1, MU=1.32712440018*10**11, step=steps, sv_option=True, dr_option=True)
    """

    # measure time at start of program
    tstart = time.time()

    # convert time range from MJD to JD
    etr_jd = mjd2jd((etr_mjd))
    # create time array
    etrsteps = [
        x * (etr_jd[1] - etr_jd[0]) / step + etr_jd[0] for x in range(step)
    ]
    # store number of bodies to propagate
    [bdy, tmp] = eldf.shape

    # initialize 3d numpy array to store state-vectors and object name
    if sv_option == True:
        sv = np.zeros((bdy, step, 7))

    # initialise 3d numpy array to store relative position vector and object name
    if dr_option == True:
        dr = np.zeros((bdy - 1, step, 4))
        drnorm = np.zeros((bdy - 1, step, 2))

    # propagate over time array
    for i in range(step):
        # prepare orbital elements for spice.conics() function
        for j in range(bdy):
            # convert orbital elements to spice-format
            rp = eldf.at[j, 'a'] * au2km * (1 - eldf.at[j, 'e'])
            elts = np.array([
                rp, eldf.at[j, 'e'],
                np.rad2deg(eldf.at[j, 'i']),
                np.rad2deg(eldf.at[j, 'LAN']),
                np.rad2deg(eldf.at[j, 'omega']),
                np.rad2deg(eldf.at[j, 'M0']),
                mjd2jd(eldf.at[j, 'Epoch']), MU
            ])
            tmp = spice.conics(elts, etrsteps[i])

            # FIXME - store state-vector of one object
            if sv_option == True:
                for k in range(6):
                    sv[(j, i, k)] = tmp[k]
                sv[j, i, 6] = eldf.at[j, 'Name']

            # store relative state-vector of current object (except if object is the spacecraft ifself)
            if dr_option == True:
                if j == 0:
                    sc_currentpos = np.zeros(3)
                    # store current spacecraft location
                    sc_currentpos[0] = tmp[0]  # state-vector[0]
                    sc_currentpos[1] = tmp[1]  # state-vector[1]
                    sc_currentpos[2] = tmp[2]  # state-vector[2]
                else:
                    # compute relative vector
                    for l in range(3):
                        dr[(j - 1, i, l)] = tmp[l] - sc_currentpos[l]
                    dr[(j - 1, i, 3)] = eldf.at[j, 'Name']
                    drnorm[(j - 1, i, 0)] = np.sqrt(dr[(j - 1, i, 0)]**2 +
                                                    dr[(j - 1, i, 1)]**2 +
                                                    dr[(j - 1, i, 2)]**2)
                    drnorm[(j - 1, i, 1)] = eldf.at[j, 'Name']

    # measure time
    tend = time.time()
    # computation time
    dt = tend - tstart
    # print computational time
    print(f'Propagation time: {round(dt,2)} [sec]')

    if sv_option == True and dr_option == True:
        return etrsteps, sv, dr, drnorm
    elif sv_option == True and dr_option == False:
        return etrsteps, sv
    elif sv_option == False and dr_option == True:
        return etrsteps, dr, drnorm
Exemple #15
0
 def relPosition(self, deltaT):
     return sp.conics(self.ele, deltaT + self.elements['T0'])
Exemple #16
0
# Our computation will be performed within a while condition (to check whether
# 67P entered the SOI or not); thus we need to set an initial value for the
# while condition. Here: a very large distance between 67P and Jupiter
comet_jup_dist = 10.0**10

# While condition: Compute the following coding part as long as 67P did not
# enter Jupiter's SOI
while comet_jup_dist > SOI_JUPITER_R:

    # Add one hour to the date-time stamp and convert it ot ET
    datetime_stamp = datetime_stamp + datetime.timedelta(hours=1)
    et_stamp = spiceypy.datetime2et(datetime_stamp)

    # Compute the state vector of 67P based on the initial orbital elements
    # (Sun-centric in ECLIPJ2000)
    COMET_67P_STATE_ORB = spiceypy.conics(COMET_67P_ORB_ELEM, et_stamp)

    # Compute Jupiter's state vector in as seen from the Sun
    JUPITER_STATE, _ = spiceypy.spkgeo(targ=5, \
                                       et=et_stamp, \
                                       ref='ECLIPJ2000', \
                                       obs=10)

    # Compute the distance between Jupiter and 67P
    comet_jup_dist = spiceypy.vnorm(JUPITER_STATE[:3] -
                                    COMET_67P_STATE_ORB[:3])

#%%

# If the while condition is not fulfilled, 67P crosses Jupiter's SOI! Let's
# take a look when this happened and also let's verify the distance to
    def get_coord(self,
                  dates,
                  target,
                  system,
                  observatory=None,
                  corr='NONE',
                  precess=False,
                  return_ltime=False,
                  no_velocity=False):
        """
        Function to calculate the coordinates of a spacecraft or solar system body
        :param dates: Astropy time object of dates(s).
        :param target: String name of target body to calculate the position of.
        :param system: String name of coordinate system to calculate position in.
        :param observatory: String name of observatory for origin of coordinate system.
        :param corr: Boolean. If True performs correction for planetary abberation.
        :param precess: Boolean. If True accounts for precession in ..
        :param return_ltime: Boolean. If True also returns light travel time between observatory and target.
        :param no_velocity: Boolean. If True, the velocity components are not returned in the state vector.
        :return state: Array, giving state at each dates. Either len(dates)x3 or len(dates)x6, depending on no_velocity
        :return ltime (optional): The light travel time between observatory and target
        """
        # TODO: Add in error checks to make sure target is specified.

        # The NAIF codes for stereo a and b are:
        sta_naif_code = '-234'
        stb_naif_code = '-235'

        target = self.get_naif_body_code(target)

        if observatory is not None:
            observatory = self.get_naif_body_code(observatory)

        frame, observatory = self.get_system_frame_names(
            system, observatory, precess)

        # Pull out the max valid ephemeris time for each craft
        if target == sta_naif_code:
            max_dates = self.__PredMaxdates__['sta']
        else:
            max_dates = self.__PredMaxdates__['stb']

        # Get ephemeris times for the input dates. If larger than max dates, set to max dates and set correct flag.
        correct_late_times = False
        if dates.isscalar:
            if dates <= max_dates:
                et = [spice.str2et(dates.isot)]
            else:
                et = [spice.str2et(max_dates.isot)]
                correct_late_times = True
        else:
            if all(dates <= max_dates):
                et = spice.str2et(dates.isot.tolist())
            else:
                et = spice.str2et(dates.isot.tolist())
                id_gt_max = dates > max_dates
                et[id_gt_max] = spice.str2et(max_dates.isot)
                correct_late_times = True

        # Now add in the calls to spice functions to get the state variables
        # If no velocity, use spkpos.
        if no_velocity:
            state, ltime = spice.spkpos(target, et, frame, corr, observatory)
            # Convert state from list of arrays to numpy array
            state = np.array(state)
        else:
            # Velocity requested. This needs spkezr, which only accepts floats. So loop through et and call spkezr for
            state = np.zeros((dates.size, 6), dtype=float)
            ltime = np.zeros(dates.size, dtype=float)
            for i in range(dates.size):
                state[i, :], ltime[i] = spice.spkezr(target, et[i], frame,
                                                     corr, observatory)

        # Add in correction to get states for times after max ephemeris time using
        # Conics. Loop over entries after maximum time
        if correct_late_times:
            if observatory == sta_naif_code:
                elts = self.__PredConic__['sta']
            elif observatory == stb_naif_code:
                elts = self.__PredConic__['stb']

            for idt in np.argwhere(id_gt_mxt is True):
                et = spice.str2et(dates.isot[idt])
                temp = spice.conics(elts, et)
                # Updates state with conics estimate.
                if no_velocity:
                    state[idt, :] = temp[0:3]
                else:
                    state[idt, :] = temp

                ltime[idt] = -1

            # Now convert updatesd coords from HAE to specified system
            temp = state[:, id_gt_mxt]
            temp = convert_stereo_coord(dates.isot[id_gt_mxt], temp, 'HAE',
                                        system)
            state[:, id_gt_mxt] = temp

        # If only one date, loose first dimension
        if dates.isscalar:
            state = np.squeeze(state)

        if return_ltime:
            return state, ltime
        else:
            return state
Exemple #18
0
# 3rd party libraries
import spiceypy as spice

# AWP library
from Spacecraft import Spacecraft as SC
import orbit_calculations as oc
import plotting_tools     as pt
import planetary_data     as pd

if __name__ == '__main__':
	periapsis = pd.earth[ 'radius' ] + 4000.0 # km

	coes_circular    = [ periapsis,       0,   0, 0, 0, 0 ]
	coes_elliptical  = [ periapsis / 0.3, 0.7, 0, 0, 0, 0 ]
	state_parabolic  = spice.conics(
		[ periapsis, 1.0, 0, 0, 0, -10.0, 0, pd.earth[ 'mu' ] ], 0 )
	state_hyperbolic = spice.conics(
		[ periapsis, 2.5, 0, 0, 0, -10.0, 0, pd.earth[ 'mu' ] ], 0 )

	sc_circular   = SC( { 'coes': coes_circular,   'tspan': '1' } )
	sc_elliptical = SC( { 'coes': coes_elliptical, 'tspan': '2' } )
	sc_parabolic  = SC( { 'orbit_state': state_parabolic,  'tspan': 70000.0 } )
	sc_hyperbolic = SC( { 'orbit_state': state_hyperbolic, 'tspan': 30000.0 } )
	
	rs = [ sc_circular.states [ :, :3 ], sc_elliptical.states[ :, :3 ],
		   sc_parabolic.states[ :, :3 ], sc_hyperbolic.states[ :, :3 ] ]
	labels = [ 'Circular $(ecc=0.0)$',  'Elliptical $(ecc=0.7)$',
			   'Parabolic $(ecc=1.0)$', 'Hyperbolic $(ecc=3.0)$' ]

	sc_elliptical.plot_states( {
		'time_unit': 'hours',
# Set the date-time of the Asteroid Day (yeah)
SAMPLE_ET = spiceypy.utc2et('2020-06-30T00:00:00')

# Set the Asteroid Day ET and mean anomaly (in radians)
ast_2020_jx1_df.loc[:, 'COMP_ET'] = SAMPLE_ET
ast_2020_jx1_df.loc[:, 'M0_RAD'] = np.radians(AST_2020JX1_M0_DEG)

# Compute the state vectors for all re-sampled orbital elements
ast_2020_jx1_df.loc[:, 'STATE_VEC'] = \
    ast_2020_jx1_df.apply(lambda x: \
                          spiceypy.conics(elts=x[['PERIH_KM', \
                                                  'ECC', \
                                                  'I_RAD', \
                                                  'LNODE_RAD', \
                                                  'ARGP_RAD', \
                                                  'M0_RAD', \
                                                  'EPOCH_ET', \
                                                  'GM_SUN']].values, \
                                          et=x['COMP_ET']), axis=1)

# And extract the positional information from the state vector
ast_2020_jx1_df.loc[:, 'POS_VEC_KM'] = \
    ast_2020_jx1_df['STATE_VEC'].apply(lambda x: x[:3])

#%%

# Let's compute the largest deviation / distance of the re-sampled position
# vector by using the scipy function cdist
from scipy.spatial.distance import cdist
Exemple #20
0

# Initial & Final Conditions
sma = 8000
ecc = 0
rp = sma * (1 - ecc)
P = 2 * np.pi * np.sqrt(sma**3 / cn.mu)
tspan = np.array([0, 0.8 * P])
elm0 = np.array([
    rp, ecc,
    np.deg2rad(10),
    np.deg2rad(0),
    np.deg2rad(0),
    np.deg2rad(0), 0, cn.mu
])
states0 = sp.conics(elm0, 0)
sma = sma + 100
rp = sma * (1 - ecc)
elm1 = np.array([
    rp, ecc,
    np.deg2rad(10),
    np.deg2rad(0),
    np.deg2rad(0),
    np.deg2rad(0), 0, cn.mu
])
states1 = sp.conics(elm1, 0)
statesf = sp.prop2b(cn.mu, states1, tspan[-1])

# Method of Particular Solutions Shooting Method
[v0, mps_err] = mps_twobody(tspan, states0, statesf)
print("mps err:", mps_err)
# Set an empty array that will store the distances between the Sun
# and ATLAS
atlas_vecs = []

# Set an empty array that will store the distances between the Sun
# and the Solar Orbiter
solar_orb_vecs = []

# Iterate through the time array (comet ATLAS)
for atlas_time_step in TIME_ARRAY:

    # Compute the ET
    atlas_et = spiceypy.datetime2et(atlas_time_step)

    # Compute the ET corresponding state vector of the comet ATLAS
    atlas_state_vec = spiceypy.conics(ATLAS_SPICE_ORB_EL, atlas_et)

    # Store the position vector
    atlas_vecs.append(atlas_state_vec[:3])

# Iterate through the time array (Solar Orbiter)
for so_time_step in TIME_ARRAY:

    # Compute the ET
    so_et = spiceypy.datetime2et(so_time_step)

    # Compute the state vector of the Solar Orbiter (NAIF ID: -144)
    solar_orb_state_vec, _ = spiceypy.spkgeo(targ=-144, et=so_et, \
                                         ref='ECLIPJ2000', obs=10)

    # Store the position vector
print(f'Long. of. asc. node in degrees: {round(CERES_LNODE_DEG, 1)} ' \
      '(MPC: 80.3)')
print(f'Argument of perih. in degrees: {round(CERES_ARGP_DEG, 1)} ' \
      '(MPC: 73.6)')

print(f'Orbit period in years: {round(CERES_ORB_TIME_YEARS, 2)} ' \
      '(MPC: 4.61)')
print('\n')

#%%

# Convert the orbital elements back to the state vector
CERES_STATE_RE = spiceypy.conics([CERES_ORBITAL_ELEMENTS[0], \
                                  CERES_ORBITAL_ELEMENTS[1], \
                                  CERES_ORBITAL_ELEMENTS[2], \
                                  CERES_ORBITAL_ELEMENTS[3], \
                                  CERES_ORBITAL_ELEMENTS[4], \
                                  CERES_ORBITAL_ELEMENTS[5], \
                                  CERES_ORBITAL_ELEMENTS[6], \
                                  GM_SUN], DATETIME_ET)

print('State vector of Ceres from the kernel:\n' \
      f'{CERES_STATE_VECTOR}')
print('State vector of Ceres based on the determined orbital elements:\n' \
      f'{CERES_STATE_RE}')
print('\n')

#%%

# On spaceweather.com we can see that an asteroid has a close Earth fly-by:
# 136795(1997BQ) on 2020-May-21 at a distance of 16.1 Lunar Distance
#
Exemple #23
0
    node = rad(gfd(i, 'node[deg]', df))
    omega = rad(gfd(i, 'w[deg]', df))
    M_A = toMean(rad(gfd(i, 'trueAnomaly2[deg]', df)), e)
    elts_ast = np.array([a, e, inc, node, omega, M_A, et, Gm])
    opt1 = sc.optimize.minimize(dist,
                                [T0, rad(gfd(i, 'trueAnomaly2[deg]', df))],
                                args=(elts_ast, Gm),
                                method='CG')
    opt2 = sc.optimize.minimize(dist1, [node, omega, opt1.x[0], opt1.x[1]],
                                args=(elts_ast, Gm),
                                method='CG')
    print(opt2.x)
    new_mean = toMean(opt2.x[3], e)
    new_elts_ast = np.array(
        [a, e, inc, opt2.x[0], opt2.x[1], new_mean, et, Gm])
    new_pos_ast = convertAst(sp.conics(new_elts_ast, 0))
    new_earth_pos = convertEarth(
        sp.spkezr('EARTH', opt2.x[2], 'J2000', 'LT+S', 'SUN'))
    distance = np.linalg.norm(new_earth_pos[0:3] - new_pos_ast[0:3])
    #print(distance)

    if distance > r_earth:
        new_elts_ast = sp.oscelt(correction(new_earth_pos - new_pos_ast), T0,
                                 Gm)
    final_data = [
        C_Time_earth, new_elts_ast[0] * 6.6846e-9, new_elts_ast[1],
        new_elts_ast[2], new_elts_ast[3], new_elts_ast[4], new_elts_ast[5]
    ]
    with open('new_earth_impactors.csv', 'a', newline='') as file:
        writer = csv.writer(file)
        writer.writerow(final_data)
Exemple #24
0
#Convert into correct form for spiceypy method
r_p_km = r_p * au / 1000
i_r = m.radians(i)
asc_node_r = m.radians(asc_node)
a_of_p_r = m.radians(a_of_p)
mean_anomaly_r = m.radians(mean_anomaly)
epoch_JD2000_s = (epoch - 2451545) * 86400  #spice.str2et('jd 2453979.5')

keplerian_elements = [
    r_p_km, e, i_r, asc_node_r, a_of_p_r, mean_anomaly_r, epoch_JD2000_s,
    GM_sun_km
]
'''First, convert Keplerian elemets to a Cartesian state vector. Spiceypy gives it
    in km and km/s.'''
sv_helio_ecliptic_km = spice.conics(keplerian_elements, epoch_JD2000_s)
sv_helio_ecliptic = sv_helio_ecliptic_km * 1000

print("Heliocentric ecliptic cartesian:", np.ndarray.tolist(sv_helio_ecliptic))
'''Then, convert from ecliptic to equatorial frame'''

eps = m.radians(23.43927944444444)  #obliquity to the ecliptic
sv_helio_equatorial = []
sv_helio_equatorial[0:3] = ecl_to_eq(sv_helio_ecliptic[0:3], eps)
sv_helio_equatorial[3:6] = ecl_to_eq(sv_helio_ecliptic[3:6], eps)

print("Heliocentric equatorial:", sv_helio_equatorial)
'''Then, convert from heliocentric to barycentric coordinates'''

sun_posvel = spice.spkssb(10, epoch_JD2000_s, 'J2000') * 1000