def get_sun_sizes(utc_start, utc_end, step_size): """get sun angular size and time steps given start and end times""" #spice constants abcorr = "None" #tolerance = "1" #method = "Intercept: ellipsoid" #prec = 3 #shape = "Ellipsoid" #load spiceypy kernels os.chdir(KERNEL_DIRECTORY) sp.furnsh(KERNEL_DIRECTORY + os.sep + METAKERNEL_NAME) print(sp.tkvrsn("toolkit")) os.chdir(BASE_DIRECTORY) utctimestart = sp.str2et(utc_start) utctimeend = sp.str2et(utc_end) durationseconds = utctimeend - utctimestart nsteps = int(np.floor(durationseconds / step_size)) timesteps = np.arange(nsteps) * step_size + utctimestart ref = "J2000" observer = "-143" target = "SUN" #get TGO-SUN pos tgo2sunpos = [ sp.spkpos(target, time, ref, abcorr, observer)[0] for time in timesteps ] sunaxes = sp.bodvrd("SUN", "RADII", 3)[1][0] #get mars axis values return ([np.arctan((sunaxes*2.0)/np.linalg.norm(tgo2sunVector))*sp.dpr()*60.0 \ for tgo2sunVector in tgo2sunpos], timesteps)
class TestSpiceyPyFunctions(): cass = kernels.CassiniKernels() spice.furnsh(cass.metakernel) utc = ['Jun 20, 2004', 'Dec 1, 2005'] etOne = spice.str2et(utc[0]) etTwo = spice.str2et(utc[1]) step = 4000 times = np.linspace(etOne, etTwo, step) spice.kclear() def test_spiceypy_cassini(self): spice.furnsh(self.cass.metakernel) true_initial_pos = [-5461446.61080924 ,-4434793.40785864 ,-1200385.93315424] positions, lightTimes = spice.spkpos('Cassini', self.times, 'J2000', 'None', 'SATURN BARYCENTER') np.testing.assert_array_almost_equal(positions[0], true_initial_pos) spice.kclear() def test_spicepy_rotation_matrix_identity(self): spice.furnsh(self.cass.metakernel) R_E2E = spice.pxform('IAU_EARTH', 'IAU_EARTH', self.etOne) np.testing.assert_array_almost_equal(R_E2E, np.eye(3)) spice.kclear() # @pytest.mark.skip('failing') 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()
def generateepochs(self, start, end, step): """Generate list of times using start and end times and number of steps Parameters ---------- start : float Starting time (MJD) end : float Ending time (MJD) Same size as t step : float Step size (days) """ start = float(start) end = float(end) step = float(step) self.step = step # Used in save module. Should get rid of this. n_times = 1 + (end - start) / step self.times = np.arange(start, end, step) self.timesjd = self.times + shared.mjd2jd self.timeset = np.zeros(len(self.times) + 1) initialtime = self.svec[0][8] + shared.mjd2jd self.timeset[0] = sp.str2et('JD ' + repr(initialtime)) for i in range(1, len(self.timeset)): self.timeset[i] = sp.str2et('JD ' + repr(self.timesjd[i - 1])) # Formatting the times in the way openorb wants it twos = np.repeat(2, len(self.times)) tmp = np.stack((self.times, twos)) self.times = np.swapaxes(tmp, 0, 1)
def relative_position(obj, reference, ettemp, frame='J2000'): kernels = load_kernels() if isinstance(ettemp, Time): et = spice.str2et(ettemp.isot) elif isinstance(ettemp, float): et = ettemp else: et = [ spice.str2et(e.isot) if type(e) == type(Time.now()) else e for e in ettemp ] abcor = 'LT+S' if isinstance(et, float): posvel, lt = spice.spkezr(obj, et, frame, abcor, reference) pos, vel = posvel[:3], posvel[3:] else: pos = np.zeros((len(et), 3)) vel = np.zeros((len(et), 3)) for i, t in enumerate(et): posvel, lt = spice.spkezr(obj, t, frame, abcor, reference) pos[i, :] = np.array(posvel[:3]) vel[i, :] = np.array(posvel[3:]) pos *= u.km vel *= u.km / u.s for k in kernels: spice.unload(k) return pos, vel
def write_positions( utc_start, utc_end, steps, ): """ Write positions of earth and moon in output file. Input: -utc_start str (format YYYYmmdd) -utc_end str (format YYYYmmdd) -steps int """ # read kernel files paths and some constants from config dark_side_path = os.path.dirname( os.path.dirname(os.path.realpath(__file__))) config = configparser.ConfigParser() config.read(os.path.join(dark_side_path, "config", "config.ini")) spk_kernel = config["spice"]["spk_kernel"] lsk_kernel = config["spice"]["lsk_kernel"] reference_frame = config["spice"]["reference_frame"] aberration_correction = config["spice"]["aberration_correction"] # load kernels spice.furnsh(spk_kernel) spice.furnsh(lsk_kernel) # compute ET times et_start = spice.str2et(format_date_for_spice(utc_start)) et_end = spice.str2et(format_date_for_spice(utc_end)) times = [x * (et_end - et_start) / steps + et_start for x in range(steps)] # load positions earth_positions, _ = spice.spkpos("EARTH", times, reference_frame, aberration_correction, "SUN") moon_positions, _ = spice.spkpos("MOON", times, reference_frame, aberration_correction, "EARTH") # create output dir output_dir = os.path.join( dark_side_path, "data", ) if not os.path.exists(output_dir): os.makedirs(output_dir) # write results in output files write_output_file(os.path.join(output_dir, "earth.txt"), [ "{:15.8f}, {:15.8f}, {:15.8f}".format(pos[0], pos[1], pos[2]) for pos in earth_positions ]) write_output_file(os.path.join(output_dir, "moon.txt"), [ "{:15.8f}, {:15.8f}, {:15.8f}".format(pos[0], pos[1], pos[2]) for pos in moon_positions ]) write_output_file(os.path.join(output_dir, "times.txt"), [ "{}".format(format_date_from_spice(spice.et2utc(time, "C", 0))) for time in times ])
def test_near_landing_coverage(self): spice.furnsh(self.near.metakernel) utc = ['Feb 12, 2001 12:00:00 UTC', 'Feb 12, 2001 20:05:00 UTC'] etone = 35251264.18507089 ettwo = 35280364.18507829 np.testing.assert_almost_equal(spice.str2et(utc[0]), etone) np.testing.assert_almost_equal(spice.str2et(utc[1]), ettwo) spice.kclear()
def build_model_spec_dict(lbl_file, cube_file, spacecraft_state, instrument_orientation, scalar=1.0, verbose=False): image_time = info.get_field_value(lbl_file, "IMAGE_TIME") interframe_delay = float(info.get_field_value(lbl_file, "INTERFRAME_DELAY")) + 0.001 start_time = spice.str2et(info.get_field_value(lbl_file, "START_TIME")) + 0.06188 stop_time = spice.str2et(info.get_field_value(lbl_file, "STOP_TIME")) + 0.06188 mid_time = (start_time + stop_time) / 2.0 min_lat = float( scripting.getkey(cube_file, "MinimumLatitude", grpname="Mapping")) max_lat = float( scripting.getkey(cube_file, "MaximumLatitude", grpname="Mapping")) min_lon = float( scripting.getkey(cube_file, "MinimumLongitude", grpname="Mapping")) max_lon = float( scripting.getkey(cube_file, "MaximumLongitude", grpname="Mapping")) rot = rotation_matrix_to_euler_angles(instrument_orientation) rot = radians_xyz_to_degrees_xyz(rot) if verbose: print_r("Image Time: ", image_time) print_r("Interframe Delay: ", interframe_delay) print_r("Start Time: ", start_time) print_r("Stop Time: ", stop_time) print_r("Middle Time: ", mid_time) print_r("Minimum Latitude: ", min_lat) print_r("Maximum Latitude: ", max_lat) print_r("Minimum Longitude: ", min_lon) print_r("Maximum Longitude: ", max_lon) print_r("Scalar: ", scalar) print_r("Spacecraft Location: ", spacecraft_state * scalar) print_r("JunoCam Orientation: ", rot) model_spec_dict = { "image_time": image_time, "interframe_delay": interframe_delay, "start_time": start_time, "stop_time": stop_time, "middle_time": mid_time, "latitude_minimum": min_lat, "latitude_maximum": max_lat, "longitude_minimum": min_lon, "longitude_maximum": max_lon, "scalar": scalar, "spacecraft_location": (spacecraft_state * scalar).tolist(), "instrument_orientation": rot.tolist() } return model_spec_dict
def computeDataFrameGeometries(self, data_frames, greg_format_string, julian_format_string): for data_frame in data_frames: self.greg_format_string = greg_format_string self.julian_format_string = julian_format_string greg_split_string = self.greg_format_string.split(' ') data_frame.greg_time_system_string = [ i for i in greg_split_string if '::' in i ][0][2:] julian_split_string = self.julian_format_string.split(' ') data_frame.julian_time_system_string = [ i for i in julian_split_string if '::' in i ][0][2:] current_epoch = data_frame.start_epoch current_epoch = spice.str2et(current_epoch) stop_epoch = spice.str2et(data_frame.stop_epoch) time_remaining = stop_epoch - current_epoch while time_remaining >= 0.0: greg_date_string = spice.timout(current_epoch, self.greg_format_string) JD_date = spice.timout(current_epoch, self.julian_format_string) for body_pair in data_frame.body_pairs: # get target body state body_state, light_times = spice.spkez( spice.bodn2c(body_pair[1]), current_epoch, data_frame.frame, 'NONE', spice.bodn2c(body_pair[0])) distance_km = self.np.linalg.norm(body_state[0:3]) distance_AU = distance_km / self.AU data_frame.data[body_pair[0]][body_pair[1]].append([ greg_date_string, JD_date, body_state, distance_km, distance_AU ]) # compute solar geometries SEP_angle, SPE_angle = self.computeSEPandSPEangles( current_epoch, data_frame.spacecraft_SPICE_ID) data_frame.data['SEP'].append( [greg_date_string, JD_date, SEP_angle]) data_frame.data['SPE'].append( [greg_date_string, JD_date, SPE_angle]) # compute any eclipses self.computeCircleCircleOccultations(current_epoch, greg_date_string, JD_date, data_frame) if time_remaining == 0.0: break else: if time_remaining >= data_frame.time_step: current_epoch += data_frame.time_step time_remaining -= data_frame.time_step else: time_remaining -= stop_epoch - current_epoch current_epoch += stop_epoch - current_epoch
def cal2et(time, format='UTC', support_ker=False, unload=False): """ Converts UTC or Calendar TDB (CAL) time to Ephemeris Time (ET). Accepts a single time or a lists of times. This function assumes that the support kernels (meta-kernel or leapseconds) kernel has been loaded. :param time: Input UTC or CAL time :type time: Union[float, list] :param format: Input format; 'UTC' or 'CAL' :type format: str :param unload: If True it will unload the input meta-kernel :type unload: bool :return: Output ET :rtype: Union[str, list] """ out_list = [] if isinstance(time, str): time = [time] # # We need to specify that is Calendar format in TDB. If it is UTC we need # to load the support kernels # if support_ker: spiceypy.furnsh(support_ker) if format == 'CAL': time[:] = [x.replace('T', ' ') for x in time] time[:] = [x + ' TDB' for x in time] for element in time: try: if format == 'UTC': out_elm = spiceypy.utc2et(element) elif format == 'CAL': out_elm = spiceypy.str2et(element) else: out_elm = element except: out_elm = spiceypy.str2et(element) out_list.append(out_elm) if len(out_list) == 1: out_time = out_list[0] else: out_time = out_list if unload: spiceypy.unload(support_ker) return out_time
def FinderReboundf51_2(t, years, arr, times, vecs, IDs): ''' Finds the radec of objects in the jovian system from the pansstars observatory a number of years before the time of observation and integrates it to the time of observation using rebound. Arguments: name: str The name of the object in spice documentation. See Summary_Names.txt t: float A julian date ''' thor = Time(t, format='jd', scale='utc') thor = thor.tt.value tstr = "jd " + str(t) + " utc" ts = spice.str2et(tstr) get_earth = get_astroquery_function('0', 'geometric', 'f51') sec_year = 86400 * 365.25 sim = Integrator(ts - years * sec_year, ts, [ '1', '2', '3', '4', '6', '7', '8', 'Jupiter', 'Io', 'Europa', 'Ganymede', 'Callisto' ], [ MMercuryB, MVenusB, MEarthB, MMarsB, MSaturnB, MUranusB, MNeptuneB, MJupiter, MIo, MEuropa, MGanymede, MCallisto ], [9, 10, 11, 12, 13, 14, 15], GMSun, arr) ttemp = ts radec = [] for j in range(0, len(times)): temp = "jd " + str(times[j]) + " utc" ttemp2 = spice.str2et(temp) k = sim.t + (ttemp2 - ttemp) / 86400 ttemp = ttemp2 sim.integrate(k) thor = Time(times[j], format='jd', scale='utc') thor = thor.tt.value ps = sim.particles dist = np.sqrt((ps[-1].x - ps[3].x)**2 + (ps[-1].y - ps[3].y)**2 + (ps[-1].z - ps[3].z)**2) ltime = float(((dist * u.AU).to(u.m) / c) / u.s) k = sim.t - ltime / (24 * 3600) sim.integrate(k) ps = sim.particles AnSun = np.array([float(ps[-1].x), float(ps[-1].y), float(ps[-1].z)]) #F51Sun = get_earth(thor) #vecs.append(F51Sun[0]) vectors = AnSun + vecs[j][0] radec.append(np.array([CordConv(vectors), times[j], IDs[j]])) k = sim.t + ltime / (24 * 3600) sim.integrate(k) return radec
def test_msi_frame_transformation_fixed(self): spice.kclear() spice.furnsh(self.near.metakernel) etone = spice.str2et('Jan 1, 2001 10:04:02.2 UTC') ettwo = spice.str2et('Feb 12, 2001 18:03:02.6 UTC') Rone = spice.pxform(self.near.near_body_frame, self.near.near_msi_frame, etone) Rtwo = spice.pxform(self.near.near_body_frame, self.near.near_msi_frame, ettwo) np.testing.assert_array_almost_equal(Rone, Rtwo) spice.kclear()
def CA(self, utc_0, utc_1, step=120, abcorr='CN+S'): '''Search Close Approch time and distance''' et_0 = spice.str2et(utc_0) et_1 = spice.str2et(utc_1) times = [x * (et_1-et_0)/step + et_0 for x in range(step)] pos, _ = spice.spkpos(self.targ, times, self.ref, abcorr, self.obs) dists = np.sqrt(np.sum(np.power(pos, 2), 1)) # Find the smallest distance ca_i = np.argmin(dists) ca_et = times[ca_i] ca_dist = dists[ca_i] return spice.et2utc(ca_et, 'ISOC', 5), ca_dist
def gregDateOffsetCalculator(gregorian_date, delta_days, time_system_string): # returns the time_system_string Gregorian date, offset from the input date string by delta_days # gregorian_date: SPICE compatible Gregorian date string # delta_days: number of days that you want to advance the Gregorian date string by # time_system_string: string representation of the output requested for the gregorian_date's time system (e.g. "TDB", "UTC" etc.) return spice.timout( spice.str2et( str( spice.str2et(gregorian_date) / 86400.0 + 2451545.0 + delta_days) + " JD TDB"), "YYYY Mon DD ::" + time_system_string + " HR:MN:SC.######")
def computeOccultations(self, observer_in, occultation_bodies_in, target_in, target_shape_in, target_frame_in, step_size_in, aberration_correction_in, greg_format_string_in): self.greg_format_string = greg_format_string_in split_string = self.greg_format_string.split(' ') self.time_system_string = [i for i in split_string if '::' in i][0][2:] self.observer = str(observer_in) self.occultation_bodies = occultation_bodies_in self.target = target_in self.target_shape = target_shape_in self.target_frame = target_frame_in self.search_step_size = step_size_in self.aberration_correction = aberration_correction_in self.cumulative_results = {} for body in self.occultation_bodies: # add a new key to the results dictionary for this body self.cumulative_results[body.name] = [] for occultation_type in body.occultation_types: body.search_start_ET_seconds = spice.str2et(body.search_start) body.search_end_ET_seconds = spice.str2et(body.search_end) spice.wninsd(body.search_start_ET_seconds, body.search_end_ET_seconds, self.SPICE_search_window) spice.gfoclt(occultation_type, body.name, body.shape, body.frame, self.target, self.target_shape, self.target_frame, self.aberration_correction, self.observer, self.search_step_size, self.SPICE_search_window, self.results_window) winsiz = spice.wncard(self.results_window) for body_index in range(winsiz): [intbeg, intend] = spice.wnfetd(self.results_window, body_index) btmstr = spice.timout(intbeg, self.greg_format_string) etmstr = spice.timout(intend, self.greg_format_string) occultation_event = OccultationEvent() occultation_event.start = btmstr occultation_event.stop = etmstr occultation_event.start_JD = greg2Julian(btmstr) occultation_event.stop_JD = greg2Julian(etmstr) occultation_event.duration = intend - intbeg occultation_event.type = occultation_type occultation_event.observer = self.observer occultation_event.occulting_body = body.name occultation_event.occulting_body_shape = body.shape occultation_event.target = self.target occultation_event.target_body_shape = self.target_shape self.cumulative_results[body.name].append( occultation_event)
def test_EVME_1966(plot=False): ''' Earth-Venus-Mars-Earth (EVME) 2 year trajectory launching in 1966 Example comes from Richard Battin's book called "Astronautical Guidance" ''' spice.furnsh(sd.leapseconds_kernel) spice.furnsh(sd.de432) sequence = [{ 'planet': 3, 'time': '1966-02-10', 'tm': -1 }, { 'planet': 2, 'planet_mu': pd.venus['mu'], 'time': '1966-07-07', 'tm': 1, 'tol': 1e-5 }, { 'planet': 4, 'planet_mu': pd.mars['mu'], 'time': '1967-01-10', 'tm': -1, 'tol': 1e-5 }, { 'planet': 3, 'planet_mu': pd.earth['mu'], 'time': '1967-12-18', 'tol': 1e-5 }] itvim = ITVIM({'sequence': sequence}) itvim.print_summary() t0_target = spice.str2et('1966-02-06') t1_target = spice.str2et('1966-07-09') t2_target = spice.str2et('1967-01-24') t3_target = spice.str2et('1967-12-17') t_targets = [t0_target, t1_target, t2_target, t3_target] t_tol = 90 * 24 * 3600.0 # t2_target is about 3 days different if plot: itvim.plot_orbits({ 'planets': [pd.venus, pd.earth, pd.mars], 'colors': ['m', 'c', 'lime'], 'sc_labels': ['SC0', 'SC1', 'SC2'], 'traj_lws': 2, 'show': True })
def occultations(body1, body2, start, end): cnfine = spiceypy.utils.support_types.SPICEDOUBLE_CELL(MAXWIN) result = spiceypy.utils.support_types.SPICEDOUBLE_CELL(MAXWIN) # Obtain the TDB time bounds of the confinement # window, which is a single interval in this case. et0 = spiceypy.str2et(start) et1 = spiceypy.str2et(end) # Insert the time bounds into the confinement window spiceypy.wninsd(et0, et1, cnfine) # 15-minute step. Ignore any occultations lasting less than 15 minutes. # Units are TDB seconds. step = 900.0 obsrvr = "Earth" # Loop over the occultation types. for occtype in types: # For each type, do a search for both transits of # Titan across Saturn and occultations of Titan by Saturn. for j in range(2): if not j: front = body1 fframe = "IAU_" + body1 back = body2 bframe = "IAU_" + body2 else: front = body2 fframe = "IAU_" + body2 back = body1 bframe = "IAU_" + body1 spiceypy.gfoclt(occtype, front, "ellipsoid", fframe, back, "ellipsoid", bframe, "lt", obsrvr, step, cnfine, result) # Display the results print() title = spiceypy.repmc("Condition: # occultation of # by #", "#", occtype) title = spiceypy.repmc(title, "#", back) title = spiceypy.repmc(title, "#", front) print(title) for r in result: print(spiceypy.timout(r, "YYYY Mon DD HR:MN:SC"))
def lon_lat_r(body, time, earth_radius=6371e3): """ Use SPICE software to get longitude and latitude of the point on Earth at which <body> is in zenith and the distance between the barycenters of Earth and <body> at a specified <time> (in UTC). We're pretending the earth is a sphere here, as is commonly done in tidal studies (and presumably is done in the ocean model this is fed into). Input: body - SPICE name of the body (e.g. "SUN" or "MOON") time - date and time in datetime format (UTC) earth_radius - radius of the earth (default 6371e3 m) Output: lon, lat - longitude and latitude at which <body> is in zenith r - range of the body (distance between barycenters) """ # convert UTC time to ephemeris time time = spice.str2et(str(time) + " UTC") # get position in rectangular coordinate system (body frame of Earth) pos_rec, _ = spice.spkpos(body, time, "ITRF93", "NONE", "EARTH") # transform to geodetic coordinates assuming zero flatness (to get lat/lon) pos_geo = spice.recgeo(pos_rec, earth_radius / 1e3, 0) # transform to range, right ascension, declination (to get range) pos_rad = spice.recrad(pos_rec) # isolate coordinates we'll need (and convert from km to m) lon = pos_geo[0] lat = pos_geo[1] r = pos_rad[0] * 1e3 return lon, lat, r
def generate_positions(self, times, observing_body, frame): """ Generate positions from a spice kernel. Parameters ---------- times : iterable of `datetime` An iterable (e.g. a `list`) of `datetime` objects at which the positions are calculated. observing_body : str The observing body. Output position vectors are given relative to the position of this body. See https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/req/naif_ids.html for a list of bodies. frame : str The coordinate system to return the positions in. See https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/req/frames.html for a list of frames. """ # Spice needs a funny set of times fmt = '%b %d, %Y' spice_times = [spiceypy.str2et(time.strftime(fmt)) for time in times] observing_body = observing_body # 'None' specifies no light-travel time correction positions, lightTimes = spiceypy.spkpos(self.target, spice_times, frame, 'None', observing_body) positions = np.array(positions) * u.km self._times = times self._positions = positions self._x = positions[:, 0] self._y = positions[:, 1] self._z = positions[:, 2] self._generated = True self._observing_body = observing_body
def getNacCenterAndRotationAtTime(imname): ''' Extract the rotation of the spacecraft and its position for the given picture Notice that WAV and NAC can be considered aligned on the same axis and centred in the spacecraft so it can be used the same way independently by the camera :param imname: the input picture filename :return: the centre and the rotation matrix of the spacecraft ''' os.chdir(spice_kernels_dir) # or spyceypy will not work spiceypy.furnsh(spice_kernels_dir + os.path.sep + furnsh_file) #load the kernels from furnsh tstr = extractTimeString( imname) # get only the time string from the filename t = spiceypy.str2et(tstr) # transform the string to a time # get the position of Rosetta spacecraft in 67p refence frame, centred in 67P + light time corr (not really needed) pos = spiceypy.spkpos("ROSETTA", t, "67P/C-G_CK", "LT+S", "67P/C-G")[0] # pos = spiceypy.spkpos("ROSETTA", t, "ROS_OSIRIS_NAC", "LT+S", "67P/C-G")[0] print("Found position: {}".format(pos)) #and the rotation - we use NAC but it is the same for the WAC # R = spiceypy.pxform("67P/C-G_CK", "ROS_OSIRIS_NAC", t); # rotation matrix of the nac camera, in respect to 67P reference frame R = spiceypy.pxform("ROS_OSIRIS_NAC", "67P/C-G_CK", t) return np.array(pos), np.array(R)
def mjd2et(self, time): """Convert MJD to ET """ time = time + 2400000.5 return (sp.str2et('JD ' + repr(time)))
def ephemeris_stop_time(self): if self.spacecraft_clock_stop_count: return spice.scs2e(self.spacecraft_id, self.spacecraft_clock_stop_count) else: return spice.str2et( self.utc_stop_time.strftime("%Y-%m-%d %H:%M:%S"))
def epoch(utc): ''' Converts two UTC dates to julian time and calculate the change in epoch Args: utc - mission start and end dates as two strings in an array Returns: etOne - start date in julian time etTwo - end date in julian time dt - change in epoch in seconds ''' # convert to julian time etOne = spice.str2et(utc[0]) etTwo = spice.str2et(utc[1]) # difference in epoch dt = etTwo - etOne return etOne, etTwo, dt
def generateDistanceReport(self, output_file, ephemeris_file, body_SPICE_IDs=[]): header_row = "Gregorian_date_TDB, Julian_date_TDB, " for bodyID in body_SPICE_IDs: pass ephem_file_rows = self.ephemeris_file_reader.parseEMTGephemerisFile( ephemeris_file) for ephem_row in ephem_file_rows: # compute distance from the Sun spacecraft_distance_from_sun = np.sqrt( ephem_row.spacecraft_position_x**2 + ephem_row.spacecraft_position_y**2 + ephem_row.spacecraft_position_z**2) for bodyID in body_SPICE_IDs: # get the distance from the Sun to the body current_seconds_past_J2000 = spice.str2et( ephem_row.gregorian_date) body_state_ICRF, sun_body_light_times = spice.spkez( 10, current_seconds_past_J2000, 'J2000', 'NONE', bodyID) spacecraft_distance_from_body = np.sqrt( (ephem_row.spacecraft_position_x - body_state_ICRF[0])**2 + (ephem_row.spacecraft_position_y - body_state_ICRF[1])**2 + (ephem_row.spacecraft_position_z - body_state_ICRF[2])**2)
def FinderSpicef51(name, t): ''' Finds the radec of objects in the jovian system from the pansstars observatory. Used to test the correspondence of spice and Horizons. Arguments: name: str The name of the object in spice documentation. See Summary_Names.txt t: float A julian date ''' thor = Time(t, format='jd', scale='utc') thor = thor.tt.value tstr = "jd " + str(t) + " utc" ts = spice.str2et(tstr) get_earth = get_astroquery_function('0', 'geometric', 'f51') get_jup = get_spice_function(name, "NONE", "0") exyz = get_earth(thor) jxyz = get_jup(ts) fxyz = LT(ts, -exyz[0], get_jup) vectors = fxyz[0] + exyz[0] return CordConv(vectors)
def populateManeuverData(self, control_segment_data): """Parses the data from a single row in a .mission_meneuver_spec file into multiple maneuver event objects""" data_index = 0 for maneuver in self.maneuvers: maneuver.frame = control_segment_data[data_index].strip() maneuver.gregorian_date = control_segment_data[data_index + 1].strip() # if no time system is specified, assume it is TDB if "TDB" not in maneuver.gregorian_date or "TDT" not in maneuver.gregorian_date or "UTC" not in maneuver.gregorian_date: maneuver.gregorian_date = maneuver.gregorian_date + " TDB" maneuver.julian_date = spice.str2et( maneuver.gregorian_date) / 86400.0 + 2451545.0 maneuver.GMAT_julian_date = SpiceyUtil.greg2GMATJulian( maneuver.gregorian_date) maneuver.control_x = float(control_segment_data[data_index + 2]) maneuver.control_y = float(control_segment_data[data_index + 3]) maneuver.control_z = float(control_segment_data[data_index + 4]) maneuver.control_magnitude = float( control_segment_data[data_index + 5]) maneuver.starting_spacecraft_mass = float( control_segment_data[data_index + 6]) maneuver.mass_flow_rate = float(control_segment_data[data_index + 7]) maneuver.duty_cycle = float(control_segment_data[data_index + 8]) maneuver.final_spacecraft_mass = float( control_segment_data[data_index + 9]) maneuver.delta_v = float(control_segment_data[data_index + 10]) maneuver.duration = float(control_segment_data[data_index + 11]) maneuver.epochET_seconds = float(control_segment_data[data_index + 12]) data_index = data_index + 13
def datetime2et(time: datetime) -> float: """ Convert datetime to SPICE ephemeris time.""" if isinstance(time, float): return time if not isinstance(time, datetime): raise TypeError("Time must be a float or a datetime object.") return spy.str2et(time.isoformat())
def nightlystates(self,timerange): """ Generate asteroid state at every midnight within the input time range Expects integer MJD dates (midnight). Generates geocentric coordinates (range, RA, DEC, rangerate, dRA, dDec) for the asteroid at each midnight between, and including, start and end. Parameters ---------- timerange: 2 element float numpy array [Starting time, Ending time] (MJD) """ # Converting from MJD to JD and computing number of days including endpoints start=int(timerange[0])+shared.mjd2jd stop =int(timerange[-1])+shared.mjd2jd ndays=int(stop-start)+1 # Loading SPK try: sp.furnsh(self.spkname) except: sys.exit("Cannot load %s" %(self.spkname)) # Initializing state variables self.nightlyt=np.zeros(ndays) self.nightlyr=np.zeros(ndays) self.nightlydr=np.zeros(ndays) self.nightlyra=np.zeros(ndays) self.nightlydra=np.zeros(ndays) self.nightlydec=np.zeros(ndays) self.nightlyddec=np.zeros(ndays) counter = -1 for i in np.linspace(start,stop,num=ndays): counter += 1 # Converting from UTC to ET timeet=sp.str2et('JD '+repr(i)) # Finding direction of asteroids from geocenter # Finding states wrt station adds 4 days for 1e6 objects asteroidsvec=sp.spkezr(str(self.spiceid),timeet,"J2000","LT","Earth") # Units are km and km/s # Converting from Rectangular to Latitudinal coordinates. # tmp is a 6 element vector (R, Long, Lat, Dr, Dlong, Dlat) Units are radians and radians/s tmp=sp.xfmsta(asteroidsvec[0][0:6],"RECTANGULAR","LATITUDINAL"," ") self.nightlyt[counter] = i self.nightlyr[counter] = tmp[0] self.nightlydr[counter] = tmp[3] self.nightlyra[counter] = tmp[1] self.nightlydra[counter] = tmp[4] self.nightlydec[counter] = tmp[2] self.nightlyddec[counter]= tmp[5]
def cassini_surfintercerpt(utc, output=False): target = 'TITAN' fixref = 'IAU_TITAN' dref = 'IAU_TITAN' method = 'ELLIPSOID' abcorr = 'NONE' obsrvr = 'CASSINI' state = cassini_phase(utc) dvec = spice.vhat(-state[:3]) et = spice.str2et(utc) [point, trgepc, srfvec] = spice.sincpt(method, target, et, fixref, abcorr, obsrvr, dref, dvec) temp = spice.reclat(point) radius = temp[0] colat = 90 + spice.convrt(temp[1], "RADIANS", "DEGREES") lon = np.mod(spice.convrt(temp[2], "RADIANS", "DEGREES"), 360) if output: print("Distance to Intercept Point", spice.vnorm(srfvec)) print("Radius", radius) print("Colatitude", colat) print("Longtitude", lon) return point, [radius, colat, lon], spice.vnorm(srfvec)
def mjd2et(self, time): """Convert MJD to ET (seconds past J2000) """ time = time + shared.mjd2jd return (sp.str2et('JD ' + repr(time)))
def test_ITVIM_EME_1963_2_year(plot=False): ''' Earth-Mars-Earth (EME) 2 year trajectory launching in 1963 Example comes from Richard Battin's book called "Astronautical Guidance" ''' spice.furnsh(sd.leapseconds_kernel) spice.furnsh(sd.de432) sequence = [{ 'planet': 3, 'time': '1963-06-21', 'tm': -1 }, { 'planet': 4, 'planet_mu': pd.mars['mu'], 'time': '1964-12-30 20:20:21.5', 'tm': 1, 'tol': 1e-5 }, { 'planet': 3, 'time': '1965-05-14', 'tol': 1e-5 }] itvim = ITVIM({'sequence': sequence}) itvim.print_summary() vinf_target0 = 18200.0 * nt.fps2kms vinf_target1 = 28852.0 * nt.fps2kms vinf_tol = 0.05 rp_target = 7892.0 * nt.mi2km + pd.mars['radius'] rp_tol = 1 t0_target = spice.str2et('1963-06-21') t1_target = spice.str2et('1964-12-31') t2_target = spice.str2et('1963-06-21') t_tol = 1 * 24 * 3600.0 assert itvim.seq[0]['v_infinity'] == pytest.approx(vinf_target0, abs=vinf_tol) assert itvim.seq[1]['v_infinity'] == pytest.approx(vinf_target1, abs=vinf_tol) assert itvim.seq[1]['periapsis'] == pytest.approx(rp_target, abs=rp_tol) assert itvim.seq[1]['et'] == pytest.approx(t1_target, abs=t_tol) if plot: itvim.plot_orbits()
def dtime2etjd(dtime): import spiceypy as sp # dtime in DATETIME_FORMAT="%d/%m/%y %H:%M:%S" dtime=datetime.datetime.strptime(dtime,DATETIME_FORMAT) dtime=dtime.strftime("%m/%d/%Y %H:%M:%S.%f") qet=sp.str2et(dtime) qjd=et2jd(qet) return qet,qjd
def datetime_to_et(dtime, scale='UTC'): """ convert a python datetime to SPICE ephemerides seconds (TBD) Args: dtime (datetime): python datetime scale (str, optional): time scale of input time (default: UTC) Returns: float: SPICE ephemerides sceonds (TBD) """ return spice.str2et(dtime.strftime( '%m/%d/%y %H:%M:%S.%f ({})'.format(scale)))
def getTargetPosition(target, craft, camera, time): """ get position of target in world coordinates relative to the observing craft. """ # get target code targetId = spice.bodn2c(target) # eg 'Jupiter'->599 # get spacecraft instrument spacecraft = -31 if craft=='Voyager1' else -32 spacecraftBus = spacecraft * 1000 spacecraftScanPlatform = spacecraftBus - 100 spacecraftNarrowCamera = spacecraftScanPlatform - 1 spacecraftWideCamera = spacecraftScanPlatform - 2 # instrument = spacecraftBus # use for NAIF continuous kernels instrument = spacecraftScanPlatform # use for PDS discrete kernels # get ephemeris time # note: target and spacecraft locations are stored relative to J2000 # time is utc time as string ephemerisTime = spice.str2et(time) # seconds since J2000 (will be negative) # sclkch = spice.sce2s(spacecraft, ephemerisTime) # spacecraft clock ticks, string # sclkdp = spice.sce2c(spacecraft, ephemerisTime) # spacecraft clock ticks, double clockTicks = spice.sce2c(spacecraft, ephemerisTime) # spacecraft clock ticks, double # print 'clockTicks',clockTicks # get position of target relative to spacecraft # this is the direction from craft to target in ECLIPB1950 frame observer = 'Voyager ' + craft[-1] # eg 'Voyager 1' frame = 'ECLIPB1950' # coordinate frame abberationCorrection = 'NONE' position, lightTime = spice.spkpos(target, ephemerisTime, frame, abberationCorrection, observer) # print 'target position relative to observer', position return position
# EARTH SURFACE GRAVITY g=9.8 # m/s^2 # DOODSON CONSTANTS (Hendershott, Lecture on Tides) Dmoon=0.2675*g # m/s^2 Dsun=0.4605*Dmoon # m/s^2 # MEAN ORBITAL DISTANCE Rmoon=3.84399e5 # m Rsun=1.49598023e8 # m # ###################################################################### # SPICE RELATED ROUTINES # ###################################################################### # Ephemeris time: et=sp.str2et("01/01/2015 00:00:00.000 UTC") etini=sp.str2et("01/01/%s 00:00:00.000 UTC"%yini) jdini=et2jd(etini) etend=sp.str2et("01/01/%s 00:00:00.000 UTC"%yend) print "Number of days:",(etend-etini)/DAY det=1.0*DAY/6 det=1*HOUR astronomy=[] et=etini while True: # STATE VECTOR MOON AND SUN rmoon=sp.spkezr("MOON",et,"J2000","NONE","399") rsun=sp.spkezr("SUN",et,"J2000","NONE","399") Rm,vm=normX(rmoon) Rs,vs=normX(rsun) V=Dmoon*(Rmoon/Rm)**3+Dsun*(Rsun/Rs)**3
# GENERATE A RANDOM ID q=1 while q: quakeid=randomStr(7) q=db.execute("select quakeid from Quakes where quakeid='%s';"%quakeid) quake["quakeid"]=quakeid print "\tQuake id: ",quakeid # CALCULATE JULIAN DAY AND EPHEMERIS TIME quake["qdatetime"]=quake["Fecha"]+" "+quake["Hora UTC"]; """ qdate=datetime.datetime.strptime(quake["qdatetime"],DATETIME_FORMAT) quake["qjd"]=date2jd(qdate) """ dtime=qdate.strftime("%m/%d/%Y %H:%M:%S.%f") qet=sp.str2et(dtime) qjd=et2jd(et) quake["qet"]="%.3f"%et quake["qjd"]="%.6f"%qjd # CALCULATE HOUR ANGLE OF THE MOON AND THE SUN qlon=float(quake["Longitud"]) hmoon=bodyHA("MOON",qet,qlon) hsun=bodyHA("SUN",qet,qlon) quake["hmoon"]="%.5f"%(hmoon) quake["hsun"]="%.5f"%(hsun) print "\tDate: ",quake["qdatetime"] print "\tJD: ",quake["qjd"] print "\tET: ",quake["qet"]
def vgMap(filterVolumes=None, optionOverwrite=False, directCall=True): "Build up 2d color map" # # cmd = "echo $ISISROOT" # cmd = "env | ag ^ISIS" # s = lib.system(cmd) # print s # load SPICE kernels (data files) with camera and target positions, etc libspice.loadKernels() # read small dbs into memory # centeringInfo = lib.readCsv(config.dbCentering) # when to turn centering on/off retargetingInfo = lib.readCsv(config.dbRetargeting) # remapping listed targets csvPositions, fPositions = lib.openCsvReader(config.dbPositions) # for target size # # dictionary to keep track of last image file in target sequence (eg for Ariel flyby) # lastImageInTargetSequence = {} # size of 2d map mymax = 800 mxmax = 2 * mymax mxcenter = mxmax/2 mycenter = mymax/2 # set up blank mapping arrays: h(x,y) = (hx(x,y), hy(x,y)) # h tells map where to pull its pixels from - ie map(mx,my) = im(h(mx,my)) hx = np.zeros((mymax,mxmax),np.float32) hy = np.zeros((mymax,mxmax),np.float32) # make blank maps for each color channel #. each system-craft-target-camera-channel will need its own png map file to write to and colorize from # store in a map folder # bluemap = np.zeros((mymax,mxmax),np.float32) bluemap = np.zeros((mymax,mxmax),np.uint8) # each might also need a count map, if wind up averaging things together to smooth things out # would prefer to avoid it if possible though - adds more complexity and i/o countmap = np.zeros((mymax,mxmax),np.uint8) # iterate through all available images, filter on desired volume or image csvFiles, fFiles = lib.openCsvReader(config.dbFiles) nfile = 1 for rowFiles in csvFiles: volume = rowFiles[config.colFilesVolume] fileId = rowFiles[config.colFilesFileId] # filter to given volume # if volume!=filterVolume: continue # get image properties filter = rowFiles[config.colFilesFilter] system = rowFiles[config.colFilesSystem] craft = rowFiles[config.colFilesCraft] target = rowFiles[config.colFilesTarget] camera = rowFiles[config.colFilesCamera] time = rowFiles[config.colFilesTime] note = rowFiles[config.colFilesNote] # relabel target field if necessary target = lib.retarget(retargetingInfo, fileId, target) #. skip others if fileId!='C1465335': continue # get cube filename cubefile = lib.getFilepath('import', volume, fileId) if not os.path.isfile(cubefile): # print 'warning file not found', cubefile continue #. for now # get folders importSubfolder = lib.getSubfolder('import', volume) jpegSubfolder = importSubfolder + 'jpegs/' # mapSubfolder = importSubfolder + 'maps/' mapSubfolder = importSubfolder #. for now lib.mkdir(jpegSubfolder) lib.mkdir(mapSubfolder) # export as jpeg imagefile = jpegSubfolder + fileId + '.jpg' # if not os.path.isfile(imagefile): if 1: cmd = "isis2std from=%s to=%s format=jpeg" % (cubefile, imagefile) print cmd lib.system(cmd) # print 'Volume %s mapping %d: %s \r' % (volume,nfile,infile), # print 'Volume %s mapping %d: %s' % (volume,nfile,infile) nfile += 1 # get target code, eg Jupiter targetId = spice.bodn2c(target) # eg 'Jupiter'->599 # print target, targetId # get instrument spacecraft = -31 if craft=='Voyager1' else -32 spacecraftBus = spacecraft * 1000 # eg -31000 spacecraftScanPlatform = spacecraftBus - 100 # eg -31100 spacecraftNarrowCamera = spacecraftScanPlatform - 1 # eg -31101 spacecraftWideCamera = spacecraftScanPlatform - 2 # eg -31102 # instrument = spacecraftBus # eg -31000, use for NAIF continuous kernels instrument = spacecraftScanPlatform # eg -31100, use for PDS discrete kernels # get ephemeris time ephemerisTime = spice.str2et(time) # seconds since J2000 (will be negative) # world coordinate frame to use # (ECLIPB1950 is how the voyager and planet positions are encoded) frame = 'ECLIPB1950' # get world-to-camera matrix (camera pointing matrix) # C is a transformation matrix from ELIPB1950 to the instrument-fixed frame # at the given time C = getCameraMatrix(frame, spacecraft, instrument, ephemerisTime) print 'C=camera pointing matrix - transform world to camera coords' print C # get world-to-body matrix # B = getBodyMatrix(frame, targetId, ephemerisTime) B = spice.tipbod(frame, targetId, ephemerisTime) print 'B=world to body/target frame matrix' print B # get boresight vector # this is just the third row of the C-matrix, *per spice docs* boresight = C[2] print 'boresight pointing vector',boresight # get location of prime meridian rotationRate = 870.5366420 # deg/day for great red spot primeMeridian = rotationRate /24/60/60 * ephemerisTime # deg print 'primeMeridian (deg)', primeMeridian % 360 primeMeridianRadians = primeMeridian * math.pi/180 # get target position in world coordinates # ie vector from craft to target # and distance observer = 'Voyager ' + craft[-1] # eg Voyager 1 abberationCorrection = 'NONE' position, lightTime = spice.spkpos(target, ephemerisTime, frame, abberationCorrection, observer) # position = getObserverToTargetVector(frame, observer, target, ephemerisTime) distance = libspice.getDistance(position) posnormal = position / distance print 'target position relative to observer',position print 'distance in km',distance print 'position normalized', posnormal # see how different boresight and position vector are dot = np.dot(boresight, posnormal) theta = math.acos(dot) * 180/math.pi print 'angle between boresight and position vector', theta # what longitudes are visible? #.. get from position of craft visibleLongitudesMin = 0 visibleLongitudesMax = math.pi # get tilt of north pole relative to image y-axis npRadians = getNorthPoleAngle(target, position, C, B, camera) # get axial tilt rotation matrix cc = math.cos(npRadians) ss = math.sin(npRadians) mTilt = np.array([[cc,-ss],[ss,cc]]) # get expected angular size (as fraction of frame) and radius imageFraction = lib.getImageFraction(csvPositions, fileId) targetRadiusPx = int(400*imageFraction) #.param # read the (centered) image im = cv2.imread(imagefile) # draw the target's north pole on image # im = drawNorthPole(im) # build hx,hy arrays, which tell map where to pull pixels from in source image # m: map (0 to mxmax, 0 to mymax) r = targetRadiusPx # pixels for mx in xrange(mxmax): # eg 0 to 1600 for my in xrange(mymax): # eg 0 to 800 # q: map (0 to 2pi, -1 to 1) qx = float(mx) / mxmax * 2 * math.pi + primeMeridianRadians qx = qx % (2 * math.pi) # 0 to 2pi qy = -float(my-mycenter)/mycenter # 1 to -1 # s: image (-1 to 1, -1 to 1) sx = -math.sqrt(1 - qy**2) * math.cos(qx) # -1 to 1 sy = qy # 1 to -1 # rotate s to account for axial tilt relative to camera up axis # ie s = mTilt * s s = np.array([sx,sy]) s = np.dot(mTilt,s) sx,sy = s # p: image (0 to 800, 0 to 800) px = sx * r + 400 # 0 to 800 py = -sy * r + 400 # 0 to 800 # hx[my][mx] = px # hy[my][mx] = py visible = (qx >= visibleLongitudesMin) and (qx <= visibleLongitudesMax) if visible: hx[my][mx] = px hy[my][mx] = py else: hx[my][mx] = 0 hy[my][mx] = 0 # do map projection map = cv2.remap(im, hx, hy, cv2.INTER_LINEAR) map = map[:,:,0] # map = np.array(map, np.float32) libimg.show(map) # save map as png file mapfile = mapSubfolder + fileId + '-map.png' cv2.imwrite(mapfile, map) sys.exit(0) # #. now need to blend this into the main map for this filter # # print type(map[0][0]) # # print type(bluemap[0][0]) # # bluemap = cv2.addWeighted(bluemap, 0.5, map, 0.5, 0) # # ret, countzero = cv2.threshold(countmap, 0,255, cv2.THRESH_BINARY) # # ret, countone = cv2.threshold(countmap, 0,255, cv2.THRESH_BINARY) # # countzero = 255-countone # # ret, mapMask = cv2.threshold(map, 1, 255, cv2.THRESH_BINARY) # # mapMask = cv2.bitwise_and(countzero, mapMask) # # c = mapMask & 1 # # countmap += c # # libimg.show(countmap) # # ret, mapnonzero = cv2.threshold(map, 0,1, cv2.THRESH_BINARY) # ret, mapnonzero = cv2.threshold(map, 1,1, cv2.THRESH_BINARY) # countmapPlusOne = countmap + 1 # countmap2 = countmap + 1-mapnonzero # base = np.array(bluemap, np.float32) # # base = base * countmap / countmapPlusOne # base = base * countmap2 / countmapPlusOne # newmap = np.array(map, np.float32) # newmap = newmap / countmapPlusOne # newbase = base + newmap # newbase = np.array(newbase, np.uint8) # # increment countmap where map image data exists # countmap += mapnonzero # # countmap = cv2.bitwise_and(countmap, mapnonzero) # countmap = np.clip(countmap, 0, 4) # bluemap = newbase # libimg.show(bluemap) # # # libimg.show(mapMask) # # mapMaskInv = 255-mapMask # # # libimg.show(mapMaskInv) # # bluemapSame = cv2.bitwise_and(bluemap, mapMaskInv) # # bluemapChange = cv2.bitwise_and(bluemap, mapMask) # # bluemapChange = cv2.addWeighted(bluemapChange, 0.5, map, 0.5, 0) # # # bluemapNew = cv2.bitwise_and(map, mapMask) # # bluemap = bluemapSame + bluemapChange # # # bluemap = bluemapSame + bluemapNew # # libimg.show(bluemap) # # bluemap = cv2.bitwise_and(bluemap, mapMaskInv) # # libimg.show(bluemap) # # bluemap = bluemap + map # # libimg.show(bluemap) # # if nfile>0: # # if nfile>3: # # if nfile>5: # if nfile>8: # sys.exit(0) fPositions.close() fFiles.close() print
s.data.cell_data.scalars = np.cos(phaseAngle) surf = mlab.pipeline.surface(s) surf.contour.filled_contours = True surf.contour.minimum_contour = 0.0 surf.contour.maximum_contour = 1.0 surf.module_manager.scalar_lut_manager.data_range = (0,1) mlab.view(v) mlab.draw() r_hat_virtis = np.array([0,0,1]) spice.furnsh("../input/spiceMetafile.tm") # t = time for which the pointing is calculated t = datetime.datetime(2015,4,25,0,28) timeStamp = datetime.datetime.strftime(t, '%Y-%m-%dT%H:%M:%S') et = spice.str2et(timeStamp) # define virtis bore sight vector, first in instrument reference frame # (which is [0,0,1]) and then rotate this vector into the comet centric # frame of reference for the given time t. rVirtis_hat = np.array([0,0,1]) R = spice.pxform('ROS_OSIRIS_NAC','67P/C-G_CK', et) rVirtis_hat = np.dot(R, rVirtis_hat) nPixelsX = 3 nPixelsY = 3 pVectors = pointing_vectors(nPixelsX, nPixelsY) ################################################################################ # compute coordinates of S/C and Sun in the comet body centric frame m2km = 1000 observer = 'CHURYUMOV-GERASIMENKO'
prec = 0 s = spice.et2utc(et, formatStr, prec, lenout=256) return s def getDistance(x,y,z): return math.sqrt(x**2+y**2+z**2) # load kernels (data files) spice.furnsh('naif0012.tls') # leap second data spice.furnsh('Voyager_1.a54206u_V0.2_merged.bsp') spice.furnsh('Voyager_2.m05016u.merged.bsp') # spice.furnsh('jup100.bsp') # jupiter satellite data (20mb) # get ephemeris time (seconds since J2000) etStart = spice.str2et(utcStart) etStop = spice.str2et(utcStop) # get time range nsteps = 50 etTimes = [i*(etStop-etStart)/nsteps + etStart for i in range(nsteps)] # get vectors from observer to target # see http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkpos_c.html frame = 'J2000' abcorr = 'NONE' # abberation correction positions, lightTimes = spice.spkpos(target, etTimes, frame, abcorr, observer)
def vgPlot(): "create plot for each system flyby" loadSpice() #. loop through these, save each file to stepxx_maps/map-Jupiter-Voyager1.jpg etc #. crop each file when done to a square #. vg titles could use these for titlepage for each system flyby #. might as well draw info on maps here - Voyager 1 at Jupiter, date, etc - futura font # note: azimuthElevation values were determined with the plot viewer class Flyby: bodies = None date = None ndays = None axisMax = 1e6 # km axisCenter = (0,0,0) azimuthElevation = None flybys = [] flyby = Flyby() flyby.bodies = ['Jupiter', 'Voyager 1', 'Io', 'Europa', 'Ganymede', 'Callisto'] flyby.date = "1979-03-05" flyby.ndays = 4 flyby.axisMax = 1e6 # km flyby.axisCenter = (0.6e6,-0.2e6,0) flyby.azimuthElevation = (-100,48) flybys.append(flyby) flyby = Flyby() flyby.bodies = ['Saturn', 'Voyager 1','Titan','Enceladus','Rhea','Mimas','Tethys','Dione'] flyby.date = "1980-11-12" flyby.ndays = 3 flyby.axisMax = 0.6e6 # km flyby.axisCenter = (-0.4e6,-0.4e6,0) flyby.azimuthElevation = (80,97) flybys.append(flyby) flyby = Flyby() flyby.bodies = ['Jupiter', 'Voyager 2', 'Io', 'Europa', 'Ganymede', 'Callisto'] flyby.date = "1979-07-09" flyby.ndays = 5 flyby.axisMax = 1e6 # km flyby.axisCenter = (-0.2e6,0,0) flyby.azimuthElevation = (102,107) flybys.append(flyby) flyby = Flyby() flyby.bodies = ['Saturn','Voyager 2','Titan','Enceladus','Rhea','Mimas','Tethys','Dione'] flyby.date = "1981-08-26" flyby.ndays = 2 flyby.axisMax = 0.6e6 # km flyby.axisCenter = (-0.2e6,0.1e6,0) flyby.azimuthElevation = (172,82) flybys.append(flyby) flyby = Flyby() flyby.bodies = ['Uranus','Voyager 2','Ariel','Miranda','Oberon','Titania','Umbriel'] flyby.date = "1986-01-25" flyby.ndays = 2 flyby.axisMax = 0.4e6 # km flyby.azimuthElevation = (-82,-7) flybys.append(flyby) flyby = Flyby() flyby.bodies = ['Neptune','Voyager 2','Triton'] # proteus not in kernels flyby.date = "1989-08-25" flyby.ndays = 2 flyby.axisMax = 1e6 # km flyby.azimuthElevation = (-62,40) flybys.append(flyby) for flyby in flybys: planet = flyby.bodies[0] observer = flyby.bodies[1] print 'Generating plot for %s at %s' % (observer, planet) nsteps = 100 # plot density # get ephemeris time around closest approach (seconds since J2000) etClosest = int(spice.str2et(flyby.date)) etStart = int(etClosest - flyby.ndays * 24*60*60 / 2) etEnd = int(etClosest + flyby.ndays * 24*60*60 / 2) etStep = int((etEnd - etStart) / nsteps) # initialize data structs ets = [] positions = [] minDist = {} minPos = {} for body in flyby.bodies: minDist[body] = 9e15 # loop over time range, get positions for et in xrange(etStart, etEnd, etStep): row = [] for body in flyby.bodies: # get position of body (voyager or moon) relative to planet (eg Jupiter). # position is an (x,y,z) coordinate in the given frame of reference. frame = 'J2000' abberationCorrection = 'NONE' position, lightTime = spice.spkpos(planet, et, frame, abberationCorrection, body) # save time and position to arrays ets.append(et) row.append(position) # find closest approach of voyager to each body if body==observer: # voyager posVoyager = position # save for other bodies # distance = int(libspice.getDistance(position)) # if distance < minDist[body]: # minDist[body] = distance # minPos[body] = position elif body==planet: pass else: # get distance to voyager, km posToVoyager = position-posVoyager distance = int(libspice.getDistance(posToVoyager)) if distance < minDist[body]: minDist[body] = distance minPos[body] = position positions.append(row) # make the map plotMap(flyby, positions, minPos) # all done - clean up the kernels spice.kclear()
def getCameraMatrix(craft, camera, time): """ get the camera matrix for the given craft and camera at a utc time. assumes libimg.loadKernels has been called. returns C, the 3x3 rotation matrix as a numpy array. """ # get target code # targetId = spice.bodn2c(target) # eg 'Jupiter'->599 # get spacecraft instrument spacecraft = -31 if craft=='Voyager1' else -32 spacecraftBus = spacecraft * 1000 spacecraftScanPlatform = spacecraftBus - 100 spacecraftNarrowCamera = spacecraftScanPlatform - 1 spacecraftWideCamera = spacecraftScanPlatform - 2 # instrument = spacecraftBus # use for NAIF continuous kernels instrument = spacecraftScanPlatform # use for PDS discrete kernels # get field of view and focal length # f is the focal length relative to the screen halfwidth of 1.0 # i.e. screen coordinates are -1.0 to 1.0 #. use ik # print 'camera',camera fov = config.cameraFOVs[camera] # degrees - 0.424 or 3.169 screenHalfwidth = 1.0 f = screenHalfwidth / math.tan(fov/2 * math.pi/180) # print 'f=focal length',f # get ephemeris time # note: target and spacecraft locations are stored relative to J2000 # time is utc time as string ephemerisTime = spice.str2et(time) # seconds since J2000 (will be negative) # sclkch = spice.sce2s(spacecraft, ephemerisTime) # spacecraft clock ticks, string # sclkdp = spice.sce2c(spacecraft, ephemerisTime) # spacecraft clock ticks, double clockTicks = spice.sce2c(spacecraft, ephemerisTime) # spacecraft clock ticks, double # print 'clockTicks',clockTicks # # get position of target relative to spacecraft # # this is the direction from craft to target in ECLIPB1950 frame # observer = 'Voyager ' + craft[-1] # eg 'Voyager 1' # frame = 'ECLIPB1950' # coordinate frame # abberationCorrection = 'NONE' # position, lightTime = spice.spkpos(target, ephemerisTime, frame, # abberationCorrection, observer) # print 'target position relative to observer', position # get camera pointing matrix C # C is the world-to-camera transformation matrix. # ie C is a rotation matrix from the base frame 'frame' to # the instrument-fixed frame at the time clockTicks +/- tolerance. # https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/ckgp_c.html tolerance = spice.sctiks(spacecraft, "0:00:800") # time tolerance frame = 'ECLIPB1950' # coordinate frame # ckgp is 'camera kernel get pointing' # note: the pointing information is stored in the time frame J2000, # but the coordinates are in the ECLIPB1950 coordinate frame. C, clkout, found = spice.ckgp(instrument, clockTicks, tolerance, frame) # print 'C=camera pointing matrix - transform world to camera coords' # print C return C