コード例 #1
0
ファイル: test_spiceypy.py プロジェクト: skulumani/astro
 def test_spicepy_state_transformation(self):
     spice.furnsh(self.cass.metakernel)
     T = spice.sxform('IAU_EARTH', 'IAU_SATURN', self.etOne)
     R = spice.pxform('IAU_EARTH', 'IAU_SATURN', self.etOne)
     (Rout, wout) = spice.xf2rav(T)
     np.testing.assert_array_almost_equal(Rout, R)
     spice.kclear()
コード例 #2
0
ファイル: transformation.py プロジェクト: tthatcher95/ale
    def from_spice(cls,
                   *args,
                   sensor_frame,
                   target_frame,
                   center_ephemeris_time,
                   ephemeris_times=[],
                   **kwargs):
        frame_chain = cls()

        times = np.array(ephemeris_times)

        sensor_time_dependent_frames, sensor_constant_frames = cls.frame_trace(
            sensor_frame, center_ephemeris_time)
        target_time_dependent_frames, target_constant_frames = cls.frame_trace(
            target_frame, center_ephemeris_time)

        time_dependent_frames = list(
            zip(sensor_time_dependent_frames[:-1],
                sensor_time_dependent_frames[1:]))
        constant_frames = list(
            zip(sensor_constant_frames[:-1], sensor_constant_frames[1:]))
        target_time_dependent_frames = list(
            zip(target_time_dependent_frames[:-1],
                target_time_dependent_frames[1:]))
        target_constant_frames = list(
            zip(target_constant_frames[:-1], target_constant_frames[1:]))

        time_dependent_frames.extend(target_time_dependent_frames)
        constant_frames.extend(target_constant_frames)

        for s, d in time_dependent_frames:
            quats = np.zeros((len(times), 4))
            avs = np.zeros((len(times), 3))
            for j, time in enumerate(times):
                state_matrix = spice.sxform(spice.frmnam(s), spice.frmnam(d),
                                            time)
                rotation_matrix, avs[j] = spice.xf2rav(state_matrix)
                quat_from_rotation = spice.m2q(rotation_matrix)
                quats[j, :3] = quat_from_rotation[1:]
                quats[j, 3] = quat_from_rotation[0]

            rotation = TimeDependentRotation(quats, times, s, d, av=avs)
            frame_chain.add_edge(rotation=rotation)

        for s, d in constant_frames:
            quats = np.zeros(4)
            rotation_matrix = spice.pxform(spice.frmnam(s), spice.frmnam(d),
                                           times[0])
            quat_from_rotation = spice.m2q(rotation_matrix)
            quats[:3] = quat_from_rotation[1:]
            quats[3] = quat_from_rotation[0]

            rotation = ConstantRotation(quats, s, d)

            frame_chain.add_edge(rotation=rotation)

        return frame_chain
コード例 #3
0
# Load the SPICE kernels via a meta file
spiceypy.furnsh('kernel_meta.txt')

# Create an initial date-time object that is converted to a string
DATETIME_UTC = datetime.datetime.now().strftime('%Y-%m-%dT%H:%M:%S')

# Convert to Ephemeris Time (ET) using the SPICE function utc2et
DATETIME_ET = spiceypy.utc2et(DATETIME_UTC)

#%%

# ECLIPJ2000_DE405 and ECLIPJ2000 appear to be similar?! A transformation
# matrix between both coordinate systems (for state vectors) should be
# consequently the identity matrix
MAT = spiceypy.sxform(instring='ECLIPJ2000_DE405', \
                      tostring='ECLIPJ2000', \
                      et=DATETIME_ET)

# Let's print the transformation matrix row-wise (spoiler alert: it is the
# identity matrix)
print('Transformation matrix between ECLIPJ2000_DE405 and ECLIPJ2000')
for mat_row in MAT:
    print(f'{np.round(mat_row, 2)}')
print('\n')

#%%

# Compute the state vector of Ceres in ECLIPJ2000 as seen from the Sun
CERES_STATE_VECTOR, _ = spiceypy.spkgeo(targ=2000001, \
                                        et=DATETIME_ET, \
                                        ref='ECLIPJ2000',
コード例 #4
0
    def sensor_position(self):
        """
        Returns a tuple with information detailing the position of the sensor at the time
        of the image. Expects ephemeris_time to be defined. This must be a floating point number
        containing the ephemeris time. Expects spacecraft_name to be defined. This must be a
        string containing the name of the spacecraft containing the sensor. Expects
        reference_frame to be defined. This must be a sring containing the name of
        the target reference frame. Expects target_name to be defined. This must be
        a string containing the name of the target body.

        Returns
        -------
        : (positions, velocities, times)
          a tuple containing a list of positions, a list of velocities, and a list of times
        """
        if not hasattr(self, '_position'):
            ephem = self.ephemeris_time
            pos = []
            vel = []

            target = self.spacecraft_name
            observer = self.target_name
            # Check for ISIS flag to fix target and observer swapping
            if self.swap_observer_target:
                target = self.target_name
                observer = self.spacecraft_name

            for time in ephem:
                # spkezr returns a vector from the observer's location to the aberration-corrected
                # location of the target. For more information, see:
                # https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/FORTRAN/spicelib/spkezr.html
                if self.correct_lt_to_surface and self.light_time_correction.upper(
                ) == 'LT+S':
                    obs_tar_state, obs_tar_lt = spice.spkezr(
                        target, time, 'J2000', self.light_time_correction,
                        observer)
                    # ssb to spacecraft
                    ssb_obs_state, ssb_obs_lt = spice.spkezr(
                        observer, time, 'J2000', 'NONE', 'SSB')

                    radius_lt = (self.target_body_radii[2] +
                                 self.target_body_radii[0]) / 2 / (
                                     scipy.constants.c / 1000.0)
                    adjusted_time = time - obs_tar_lt + radius_lt
                    ssb_tar_state, ssb_tar_lt = spice.spkezr(
                        target, adjusted_time, 'J2000', 'NONE', 'SSB')
                    state = ssb_tar_state - ssb_obs_state
                    matrix = spice.sxform("J2000", self.reference_frame, time)
                    state = spice.mxvg(matrix, state, 6, 6)
                else:
                    state, _ = spice.spkezr(target, time, self.reference_frame,
                                            self.light_time_correction,
                                            observer)

                if self.swap_observer_target:
                    pos.append(-state[:3])
                    vel.append(-state[3:])
                else:
                    pos.append(state[:3])
                    vel.append(state[3:])

            # By default, SPICE works in km, so convert to m
            self._position = [p * 1000 for p in pos]
            self._velocity = [v * 1000 for v in vel]
        return self._position, self._velocity, self.ephemeris_time
コード例 #5
0
def sxform_val(inf, outf, et):
    print(f"\n{inf} -> {outf}")
    print(sp.sxform(inf, outf, et))
コード例 #6
0
    def convert_coord(self,
                      dates,
                      coord_src,
                      system_src,
                      system_dst,
                      observe_src=None,
                      observe_dst=None,
                      precess=False):
        """
        Function to convert coordinates betwen different reference frames.
        :param dates: Astropy time object of dates(s).
        :param coord_src: Array of coordinates to convert. Should be len(dates)*3 for positions only, or len(dates)*6
                          for full state
        :param system_src: String name of coordinate system of coord array.
        :param system_dst: String name of coordinate system to transform coord array to.
        :param observe_src: String name of observatory for origin of system from. Only needed for some systems.
        :param observe_dst: String name of observatory for origin of system to. Only needed for some systems.
        :param precess: Boolean. If True accounts for precession in coordinate system.
        :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
        """
        # If coordinates input as a list, then bung them into an array.
        if isinstance(coord_src, list):
            if all([isinstance(c, (float, int)) for c in coord_src]):
                coord_src = np.array(coord_src)
                coord_src = np.squeeze(coord_src)
            else:
                print(
                    "ERROR: coord_src should be a numpy array of coordinates or a list of floats/ints."
                )

        # If coord only has one dimension, set it so that time is zeroth.
        if coord_src.ndim == 1:
            n_coords = 1
            n_components = coord_src.size
        else:
            n_coords = coord_src.shape[0]
            n_components = coord_src.shape[1]

        # Check dates and coord sizes match.
        if dates.size != n_coords:
            print(
                "Error: Number of dates does not correspond to number of coordinates."
            )

        # Check coord components are either 3 or 6, for position or state. Set no_velocity flag too.
        if n_components == 3:
            no_velocity = True
        elif n_components == 6:
            no_velocity = False
        else:
            print(
                "ERROR: Invalid dimension of position vector or state vector")

        # Get NAIF formated name for src and dst observer and frame.
        # Get SRC frame and osberver
        if observe_src is None:
            # Observer defined by the frame.
            frame_src, observe_src = self.get_system_frame_names(
                system_src, precess=precess)
        else:
            # Observer must be specified for this frame
            observe_src = self.get_naif_body_code(observe_src)
            # Get naif frame and observer
            frame_src, observe_src = self.get_system_frame_names(
                system_src, observatory=observe_src, precess=precess)

        # Repeat for DST frame and observer
        if observe_dst is None:
            # Observer defined by frame
            frame_dst, observe_dst = self.get_system_frame_names(
                system_dst, precess=precess)
        else:
            # Observer must be specified for this frame
            observe_dst = self.get_naif_body_code(observe_dst)
            # Get naif frame and observ
            frame_dst, observe_dst = self.get_system_frame_names(
                system_dst, observatory=observe_dst, precess=precess)

        # Convert to ephemeris time
        if dates.isscalar:
            et = spice.str2et(dates.isot)
        else:
            et = spice.str2et(dates.isot.tolist())

        # If observer changes, first do origin shift.
        if observe_src != observe_dst:

            # Get location of observe_dst relative to observe_src in frame_src
            corr = 'NONE'
            if no_velocity:
                observe_src_state, ltime = spice.spkpos(
                    observe_dst, et, frame_src, corr, observe_src)
            else:
                # Velocity requested. This needs spkezr, which only accepts floats. So loop et and call spkezr for
                #  each et. Preallocate state and ltime, in this case state is a len(et)x6 array.
                if dates.isscalar:
                    observe_src_state, ltime = spice.spkezr(
                        observe_dst, et, frame_src, corr, observe_src)
                else:
                    observe_src_state = np.zeros(coord_src.shape, dtype=float)
                    ltime = np.zeros(dates.size, dtype=float)
                    for i in range(dates.size):
                        observe_src_state[i, :], ltime[i] = spice.spkezr(
                            observe_dst, et[i], frame_src, corr, observe_src)

            # Now shift the origin
            coord_src = coord_src - observe_src_state

        # Must loop through dates for the matrix multiplication. Preallocate space for output.
        # Now rotate from src frame to dst frame.
        if dates.isscalar:
            if no_velocity:
                # Get rotation matrix for position only
                transform = spice.pxform(frame_src, frame_dst, et)
                coord_dst = np.matmul(transform, coord_src)
            else:
                # Get rotation matrix for full state
                transform = spice.sxform(frame_src, frame_dst, et)
                coord_dst = np.matmul(transform, coord_src)
        else:
            # Must loop through dates for the matrix multiplication. Preallocate space for output.
            coord_dst = np.zeros(coord_src.shape, dtype=float)

            for i in range(dates.size):
                if no_velocity:
                    transform = spice.pxform(frame_src, frame_dst, et[i])
                else:
                    transform = spice.sxform(frame_src, frame_dst, et[i])

                coord_dst[i, :] = np.matmul(transform, coord_src[i, :])

        return coord_dst
コード例 #7
0
    def save(self,base_fname, force):

        """ Save asteroid state vectors in a NAIF SPICE SPK file
         Base filename will be appended by asteroid internal ID + extension (.bsp)

        Parameters
        ----------
            base_fname: string
                Base file name. 
            force : boolean
                Force the program to rewrite asteroid SPK files
                
        """
        
        n_segments = 1 # This parameter should be an argument or should always be 1
        segmentsize = (len(self.svec)-1)//n_segments

        # File name to save SPK to
        self.spkname = base_fname+str(self.id)+".bsp"

        if force:
            if os.path.isfile(self.spkname):
                os.system("rm %s" %(self.spkname))
            
        handle = sp.spkopn(self.spkname,"spkfile",500)
        
        for i in np.arange(0,n_segments):

            # Computing first and last index for segment
            idx_first=i*segmentsize+1
            idx_last =(i+1)*segmentsize+1

            # first elements are initial values from initial orbit so ignoring those            
            segmenttimeet = self.timeset[idx_first:idx_last]
            segmenttime =   self.svec[idx_first:idx_last,8]
            segmentx =      self.svec[idx_first:idx_last,1]*shared.au2km
            segmenty =      self.svec[idx_first:idx_last,2]*shared.au2km
            segmentz =      self.svec[idx_first:idx_last,3]*shared.au2km
            segmentxd =     self.svec[idx_first:idx_last,4]*shared.au2km/shared.day2s
            segmentyd =     self.svec[idx_first:idx_last,5]*shared.au2km/shared.day2s
            segmentzd =     self.svec[idx_first:idx_last,6]*shared.au2km/shared.day2s
            
            tmpstates=[segmentx,segmenty,segmentz,segmentxd,segmentyd,segmentzd]
            spicestates=np.swapaxes(tmpstates,0,1)
            spicestates=spicestates.tolist()

            # Coordinate transformation from Ecliptic to Equatorial frame for saving as SPKs
            spicestateseq=copy.deepcopy(spicestates)
#            spicestateseq=spicestates[:]
            counter=0
            for state in spicestates:
                matrix=sp.sxform("ECLIPJ2000","J2000",segmenttimeet[counter])
                spicestateseq[counter]=sp.mxvg(matrix,spicestates[counter],6,6)
                counter=counter+1
                
#           SPK Type 9, Lagrange interpolation (Open Orb states are heliocentric, so central body is 10, which is the Sun)
#            sp.spkw09(handle, self.spiceid, 10, "J2000", segmenttimeet[0], segmenttimeet[-1], str(i), 10, segmentsize, spicestateseq, segmenttimeet)

#           SPK Type 5 (Two body interpolation)
            sp.spkw05(handle,2444444+self.id,10, "J2000", segmenttimeet[0], segmenttimeet[-1], str(i), shared.gms, segmentsize, spicestateseq, segmenttimeet)
            
        sp.spkcls(handle)
コード例 #8
0
#to change the approximation used change the method of each planet to EULER, EULERCROMER OR VERLET



#for the sun
mass_sun = (constants.GM_sun / UPPER_G).value
pos_sun, vel_sun = get_body_barycentric_posvel("sun", t, ephemeris="jpl")
sunarray = [
    pos_sun.xyz[0].to("m").value,
    pos_sun.xyz[1].to("m").value,
    pos_sun.xyz[2].to("m").value,
    vel_sun.xyz[0].to("m/s").value,
    vel_sun.xyz[1].to("m/s").value,
    vel_sun.xyz[2].to("m/s").value,
]
trans = sxform("J2000", "ECLIPJ2000", t.jd)
sunarrayecl = mxvg(trans, sunarray, 6, 6)
position_sun = [sunarrayecl[0], sunarrayecl[1], sunarrayecl[2]]
velocity_sun = [sunarrayecl[3], sunarrayecl[4], sunarrayecl[5]]
sun = Particle(position_sun, velocity_sun, np.array([0,0,0]), name='Sun', mass = mass_sun, algorithm = "EULER")
#print(mass_sun)
#print(velocity_sun)

#for mercury
mass_mercury = (constants.GM_mercury / UPPER_G).value
pos_mercury, vel_mercury = get_body_barycentric_posvel("mercury", t, ephemeris="jpl")
mercuryarray = [
    pos_mercury.xyz[0].to("m").value,
    pos_mercury.xyz[1].to("m").value,
    pos_mercury.xyz[2].to("m").value,
    vel_mercury.xyz[0].to("m/s").value,