def lambert_leg(P1, P2, i, j, t1, t2, tof, vrel=None, dv_launch=0.): """Compute a lambert leg from planet to planet. Arguments: p1 -- starting planet (str or PyKEP.planet object) p2 -- final planet (str or PyKEP.planet object) t0 -- start time of leg in MJD2000 tof -- time of flight in days Keyword arguments: vrel -- caresian coordinates of the relative velocity before the flyby at p1 dv_launch -- dv discounted at lunch (i.e. if vrel is None) rendezvous -- add final dv Returns: dV, vrel_out, where vrel_out is the relative velocity at the end of the leg at p2 """ ast1 = ASTEROIDS[P1] ast2 = ASTEROIDS[P2] r1 = state_asteroids.EPH[i][t1][0] v1 = state_asteroids.EPH[i][t1][1] r2 = state_asteroids.EPH[j][t2][0] v2 = state_asteroids.EPH[j][t2][1] lambert = kep.lambert_problem(r1, r2, tof * kep.DAY2SEC, ast1.mu_central_body, False, 0) vrel_in = tuple(map(lambda x, y: x - y, lambert.get_v1()[0], v1)) vrel_out = tuple(map(lambda x, y: x - y, lambert.get_v2()[0], v2)) dv_lambert = np.linalg.norm(vrel_out) + np.linalg.norm(vrel_in) a, _, _, dv_damon = kep.damon(vrel_in, vrel_out, tof*kep.DAY2SEC) m_star = kep.max_start_mass(np.linalg.norm(a), dv_damon, T_max, Isp) return dv_lambert, dv_damon, m_star
def plot_orbits(ep, debris1, debris2): import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D fig = plt.figure() ax = fig.add_subplot(111, projection='3d') ax.set_aspect('equal') ax.set_xlim(-1e7, 1e7) ax.set_ylim(-1e7, 1e7) ax.set_zlim(-1e7, 1e7) for deb in debris1: try: kep.orbit_plots.plot_planet(deb, ax=ax, t0=kep.epoch(ep), s=0, color='r', alpha=0.2) except: pass for deb in debris2: try: kep.orbit_plots.plot_planet(deb, ax=ax, t0=kep.epoch(ep), s=0, color='b', alpha=0.2) except: pass plt.show()
def write_output_vts(output_vts_format_file, trajectory, earth, mars): """ Function for generating the trajectory of the CubeSat by traj.xyzv in the VTS format """ def tab_write(value): output_vts_format_file.write('%s\t' % value) for value in trajectory: time = value[0] pos = value[1:4] time_integer_part = int(pk.epoch(time).mjd // 1) # integer part of mjd time time_decimal_part = ( pk.epoch(time).mjd % 1 ) * pk.DAY2SEC # converting the decimal part of mjd time to seconds tab_write(time_integer_part) tab_write(time_decimal_part) tab_write( pos[0] / 1000.) # the position of the CubeSat along the X axis (in km) tab_write(pos[1] / 1000.) tab_write(pos[2] / 1000.) tab_write( value[4]) # the velocity of the CubeSat along the X axis (in m/s) tab_write(value[5]) tab_write(value[6]) output_vts_format_file.write('\n')
def body_eph_gen_vts(output_vts_format_file, trajectory, body): """ Function for generating the ephemeris of a body by traj.xyzv in the VTS format """ def tab_write(value): output_vts_format_file.write('%s\t' % value) def car2sph(car_pos): r = np.linalg.norm(car_pos) # km lat = np.arcsin(car_pos[2] / r) * 180. / np.pi # degree lon = np.arctan2(car_pos[1], car_pos[0]) * 180. / np.pi # degree return np.array([lon, lat, r / 1000.]) for value in trajectory: time = value[0] pos = value[1:4] sph_temp = car2sph(body.get_relative_position(time, pos)) time_integer_part = int(pk.epoch(time).mjd // 1) # integer part of mjd time time_decimal_part = ( pk.epoch(time).mjd % 1 ) * pk.DAY2SEC # converting the decimal part of mjd time to seconds tab_write(time_integer_part) tab_write(time_decimal_part) tab_write(sph_temp[1]) # latitude tab_write(sph_temp[0]) # longitude tab_write(sph_temp[2]) output_vts_format_file.write('\n')
def solve(self, *args, validate_barker=True, verbose=False, **kwargs): "Solves Lambert's problem for the requested transfer." # departure and arrival epochs dep_t = pk.epoch(self.dep_t, 'mjd') arr_t = pk.epoch(self.arr_t, 'mjd') # departure and arrival positions & velocities # /-> (could obtain `dep_ast_eph` in `lambert_optimize_dt` and pass it as # | argument to avoid having it being repeatedly calculated here) # r1, v1 = self.dep_ast.eph(dep_t) if dep_ast_eph is None else dep_ast_eph r1, v1 = self.dep_ast.eph(dep_t) r2, v2 = self.arr_ast.eph(arr_t) # Barker equation used to skip useless Lambert computations # https://en.wikipedia.org/wiki/Parabolic_trajectory#Barker.27s_equation if validate_barker and self.dT < pk.barker(r1, r2, MU_SUN) * SEC2DAY: if verbose: print(self.dT, 'Fails Barker:', self.dT, pk.barker(r1, r2, MU_SUN) * SEC2DAY) self.fail() return None l = pk.lambert_problem(r1, r2, self.dT * DAY2SEC, MU_SUN) # don't compute any multi-rev solutions: #l = pk.lambert_problem(r1, r2, self.dT * DAY2SEC, MU_SUN, False, 0) return l, v1, v2
def mjd_vts(self, time): """Method converting a MJD epoch to the vts format. Returns a tuple: the integer part of the MJD and the fractional part (converted to seconds) of the MJD. """ mjd_integer_part = int(pk.epoch(time).mjd // 1) mjd_decimal_part = (pk.epoch(time).mjd % 1) * pk.DAY2SEC return mjd_integer_part, mjd_decimal_part
def vts(self, dates): # pas compris, si un objet est de type "Date", sa méthode t.vts(...) utilise quoi et retourne quoi? """Method converting an epoch to the vts format. it returns the integer part of the MJD and the fractional part (converted to seconds) of the MJD. """ self.time_integer_part = int(pk.epoch(dates).mjd // 1) self.time_decimal_part = (pk.epoch(dates).mjd % 1) * pk.DAY2SEC return self.time_integer_part, self.time_decimal_part
def __init__( self, mass=1000, Tmax=0.05, Isp=2500, Vinf_0=3, Vinf_f=1e-12, nseg=10, departure=None, target=None, optimise4mass=False): """ Constructs a low-thrust transfer between a departure planet and a target planet (Constrained Continuous Single-Objective) NOTE: An impulsive transcription is used to transform into an NLP the Optimal Control Problem USAGE: problem.py_pl2pl(self,mass=1000,Tmax=0.05,Isp=2500,Vinf_0=3,Vinf_f=0,nseg=10,departure = PyKEP.planet_ss('earth'), target = PyKEP.planet_ss('mars')) * mass: spacecraft mass at departure [kg] * Tmax: maximum allowed thrust [N] * Isp: spacecarft engine specific impulse [Isp] * Vinf_0: allowed maximum starting velocity [km/s] * Vinf_f: allowed maximum arrival velocity [km/s] (if negative it is interpreted as a minimum arrival velocity) * nseg: number of segments used for the impulsive transcription * departure: departure planet (a PyKEP planet) * target: arrival planet (a PyKEP planet) """ try: import PyKEP except ImportError: raise ImportError( "Error while trying 'import PyKEP': is PyKEP installed?") if departure is None: departure = PyKEP.planet_ss('earth') if target is None: target = mars = PyKEP.planet_ss('mars') super(py_pl2pl, self).__init__( 9 + nseg * 3, 0, 1, 9 + nseg, nseg + 2, 1e-5) self.__departure = departure self.__target = target self.__sc = PyKEP.sims_flanagan.spacecraft(mass, Tmax, Isp) self.__Vinf_0 = Vinf_0 * 1000 self.__Vinf_f = Vinf_f * 1000 self.__leg = PyKEP.sims_flanagan.leg() self.__leg.set_mu(departure.mu_central_body) self.__leg.set_spacecraft(self.__sc) self.__nseg = nseg self.set_bounds( [0, 10, self.__sc.mass / 10, -abs(self.__Vinf_0), -abs(self.__Vinf_0), -abs(self.__Vinf_0), -abs(self.__Vinf_f), -abs(self.__Vinf_f), -abs(self.__Vinf_f)] + [-1] * 3 * nseg, [3000, 1500, self.__sc.mass, abs(self.__Vinf_0), abs(self.__Vinf_0), abs(self.__Vinf_0), abs(self.__Vinf_f), abs(self.__Vinf_f), abs(self.__Vinf_f)] + [1] * 3 * nseg) self.__optimise4mass = optimise4mass
def _compute_constraints_impl(self, x): import PyKEP start = PyKEP.epoch(x[0]) end = PyKEP.epoch(x[0] + x[1]) # Computing starting spaceraft state r, v = self.__departure.eph(start) v_list = list(v) v_list[0] += x[3] v_list[1] += x[4] v_list[2] += x[5] x0 = PyKEP.sims_flanagan.sc_state(r, v_list, self.__sc.mass) # Computing ending spaceraft state r, v = self.__target.eph(end) v_list = list(v) v_list[0] += x[6] v_list[1] += x[7] v_list[2] += x[8] xe = PyKEP.sims_flanagan.sc_state(r, v_list, x[2]) # Building the SF leg self.__leg.set(start, x0, x[-3 * self.__nseg:], end, xe) # Computing Vinf constraints (careful here, the weights do count). In case of a larger than constarint # a factor of 100 has been added if (self.__Vinf_0 >= 0): v_inf_con_0 = (x[3] * x[3] + x[4] * x[4] + x[5] * x[5] - self.__Vinf_0 * self.__Vinf_0) / ( PyKEP.EARTH_VELOCITY * PyKEP.EARTH_VELOCITY) else: v_inf_con_0 = -100 * ( x[3] * x[3] + x[4] * x[4] + x[5] * x[5] - self.__Vinf_0 * self.__Vinf_0) / (PyKEP.EARTH_VELOCITY * PyKEP.EARTH_VELOCITY) if (self.__Vinf_f >= 0): v_inf_con_f = (x[6] * x[6] + x[7] * x[7] + x[8] * x[8] - self.__Vinf_f * self.__Vinf_f) / ( PyKEP.EARTH_VELOCITY * PyKEP.EARTH_VELOCITY) else: v_inf_con_f = -100 * ( x[6] * x[6] + x[7] * x[7] + x[8] * x[8] - self.__Vinf_f * self.__Vinf_f) / (PyKEP.EARTH_VELOCITY * PyKEP.EARTH_VELOCITY) # Setting all constraints retval = list(self.__leg.mismatch_constraints() + self.__leg.throttles_constraints()) + [v_inf_con_0 ] + [v_inf_con_f] retval[0] /= PyKEP.AU retval[1] /= PyKEP.AU retval[2] /= PyKEP.AU retval[3] /= PyKEP.EARTH_VELOCITY retval[4] /= PyKEP.EARTH_VELOCITY retval[5] /= PyKEP.EARTH_VELOCITY retval[6] /= self.__sc.mass return retval
def _compute_constraints_impl(self, x): import PyKEP start = PyKEP.epoch(x[0]) end = PyKEP.epoch(x[0] + x[1]) # Computing starting spaceraft state r, v = self.__departure.eph(start) v_list = list(v) v_list[0] += x[3] v_list[1] += x[4] v_list[2] += x[5] x0 = PyKEP.sims_flanagan.sc_state(r, v_list, self.__sc.mass) # Computing ending spaceraft state r, v = self.__target.eph(end) v_list = list(v) v_list[0] += x[6] v_list[1] += x[7] v_list[2] += x[8] xe = PyKEP.sims_flanagan.sc_state(r, v_list, x[2]) # Building the SF leg self.__leg.set(start, x0, x[-3 * self.__nseg:], end, xe) # Computing Vinf constraints (careful here, the weights do count). In case of a larger than constarint # a factor of 100 has been added if (self.__Vinf_0 >= 0): v_inf_con_0 = (x[3] * x[3] + x[4] * x[4] + x[5] * x[5] - self.__Vinf_0 * self.__Vinf_0) / (PyKEP.EARTH_VELOCITY * PyKEP. EARTH_VELOCITY) else: v_inf_con_0 = -100 * (x[3] * x[3] + x[4] * x[4] + x[5] * x[5] - self. __Vinf_0 * self.__Vinf_0) / (PyKEP. EARTH_VELOCITY * PyKEP.EARTH_VELOCITY) if (self.__Vinf_f >= 0): v_inf_con_f = (x[6] * x[6] + x[7] * x[7] + x[8] * x[8] - self.__Vinf_f * self.__Vinf_f) / (PyKEP.EARTH_VELOCITY * PyKEP. EARTH_VELOCITY) else: v_inf_con_f = -100 * (x[6] * x[6] + x[7] * x[7] + x[8] * x[8] - self. __Vinf_f * self.__Vinf_f) / (PyKEP. EARTH_VELOCITY * PyKEP.EARTH_VELOCITY) # Setting all constraints retval = list(self.__leg.mismatch_constraints( ) + self.__leg.throttles_constraints()) + [v_inf_con_0] + [v_inf_con_f] retval[0] /= PyKEP.AU retval[1] /= PyKEP.AU retval[2] /= PyKEP.AU retval[3] /= PyKEP.EARTH_VELOCITY retval[4] /= PyKEP.EARTH_VELOCITY retval[5] /= PyKEP.EARTH_VELOCITY retval[6] /= self.__sc.mass return retval
def _compute_constraints_impl(self, x_full): import PyKEP sc_mass = self.__start_mass eqs = [] ineqs = [] for i in range(self.__num_legs): x = x_full[i * self.__dim_leg:(i + 1) * self.__dim_leg] start = PyKEP.epoch(x[0]) end = PyKEP.epoch(x[0] + x[1]) # Computing starting spaceraft state r, v = self.__seq[i].eph(start) x0 = PyKEP.sims_flanagan.sc_state(r, v, sc_mass) # Computing ending spaceraft state r, v = self.__seq[i + 1].eph(end) xe = PyKEP.sims_flanagan.sc_state(r, v, x[3]) # Building the SF leg self.__legs[i].set_spacecraft( PyKEP.sims_flanagan.spacecraft(sc_mass, .3, 3000.)) self.__legs[i].set(start, x0, x[-3 * self.__nseg:], end, xe) # Setting all constraints eqs.extend(self.__legs[i].mismatch_constraints()) ineqs.extend(self.__legs[i].throttles_constraints()) eqs[-7] /= PyKEP.AU eqs[-6] /= PyKEP.AU eqs[-5] /= PyKEP.AU eqs[-4] /= PyKEP.EARTH_VELOCITY eqs[-3] /= PyKEP.EARTH_VELOCITY eqs[-2] /= PyKEP.EARTH_VELOCITY eqs[-1] /= self.__start_mass sc_mass = x[3] # update mass to final mass of leg if i < self.__num_legs - 1: x_next = x_full[(i + 1) * self.__dim_leg:(i + 2) * self.__dim_leg] time_ineq = x[0] + x[1] + x[2] - x_next[0] ineqs.append(time_ineq / 365.25) else: final_time_ineq = x[0] + x[1] + x[2] - x_full[0] - x_full[ -1] # <- total time ineqs.append(final_time_ineq / 365.25) retval = eqs + ineqs return retval
def _compute_constraints_impl(self, x_full): import PyKEP sc_mass = self.__start_mass eqs = [] ineqs = [] for i in range(self.__num_legs): x = x_full[i * self.__dim_leg:(i + 1) * self.__dim_leg] start = PyKEP.epoch(x[0]) end = PyKEP.epoch(x[0] + x[1]) # Computing starting spaceraft state r, v = self.__seq[i].eph(start) x0 = PyKEP.sims_flanagan.sc_state(r, v, sc_mass) # Computing ending spaceraft state r, v = self.__seq[i + 1].eph(end) xe = PyKEP.sims_flanagan.sc_state(r, v, x[3]) # Building the SF leg self.__legs[i].set_spacecraft(PyKEP.sims_flanagan.spacecraft(sc_mass, .3, 3000.)) self.__legs[i].set(start, x0, x[-3 * self.__nseg:], end, xe) # Setting all constraints eqs.extend(self.__legs[i].mismatch_constraints()) ineqs.extend(self.__legs[i].throttles_constraints()) eqs[-7] /= PyKEP.AU eqs[-6] /= PyKEP.AU eqs[-5] /= PyKEP.AU eqs[-4] /= PyKEP.EARTH_VELOCITY eqs[-3] /= PyKEP.EARTH_VELOCITY eqs[-2] /= PyKEP.EARTH_VELOCITY eqs[-1] /= self.__start_mass sc_mass = x[3] # update mass to final mass of leg if i < self.__num_legs - 1: x_next = x_full[(i + 1) * self.__dim_leg:(i + 2) * self.__dim_leg] time_ineq = x[0] + x[1] + x[2] - x_next[0] ineqs.append(time_ineq / 365.25) else: final_time_ineq = x[0] + x[1] + x[2] - x_full[0] - x_full[-1] # <- total time ineqs.append(final_time_ineq / 365.25) retval = eqs + ineqs return retval
def lamberts(x1, x2, traj): ''' Takes two position points - numpy arrays with time,x,y,z as elements and produces two vectors with the state vector for both positions using Lamberts solution Args: x1(numpy array): time and position for point 1 [time1,x1,y1,z1] x2(numpy array): time and position for point 2 [time2,x2,y2,z2] Returns: numpy array: velocity vector for point 1 (vx, vy, vz) ''' x1_new = [1, 1, 1] x1_new[:] = x1[1:4] x2_new = [1, 1, 1] x2_new[:] = x2[1:4] time = x2[0] - x1[0] # traj = orbit_trajectory(x1_new, x2_new, time) l = pkp.lambert_problem(x1_new, x2_new, time, 398600.4405, traj) v1 = l.get_v1() v1 = np.asarray(v1) v1 = np.reshape(v1, 3) return v1
def write_output(output_file, trajectory, earth, mars): def tab_write(value): output_file.write('%s\t' % value) for value in trajectory: time = value[0] pos = value[1:4] tab_write(pk.epoch(time).jd) tab_write( pos[0] / 1000.) # the position of the CubeSat along the X axis (in km) tab_write(pos[1] / 1000.) tab_write(pos[2] / 1000.) tab_write( value[4]) # the velocity of the CubeSat along the X axis (in m/s) tab_write(value[5]) tab_write(value[6]) tab_write(np.linalg.norm(pos) / 1000.) # the radii of the CubeSat from the Sun (in km) tab_write( np.linalg.norm(earth.get_relative_position(time, pos)) / 1000.) # the radii of the CubeSat from the Earth (in km) tab_write( np.linalg.norm(mars.get_relative_position(time, pos)) / 1000.) # the radii of the CubeSat from the Mars (in km) tab_write(np.linalg.norm(earth.eph(time)) / 1000.) # the radii of Earth from the Sun (in km) output_file.write('%s' % (np.linalg.norm(mars.eph(time)) / 1000.)) # the radii of Mars from the Sun (in km) output_file.write('\n')
def search_min_dv_to_body(body, departure_date, departure_position, host_velocity, min_time_of_flight, time_delta, number): time_range = [min_time_of_flight + time_delta*i for i in xrange(number)] body_positions = [body.eph(time + departure_date.mjd2000)[0] for time in time_range] departure_velocities = [pk.lambert_problem(departure_position, pos, time*pk.DAY2SEC, pk.MU_SUN, False, 0).get_v1()[0] for pos, time in zip(body_positions, time_range)] deltaV = [np.linalg.norm(np.array(velocity)-host_velocity) for velocity in departure_velocities] index_min = np.array(deltaV).argmin() return index_min, departure_velocities[index_min]
def orbit_trajectory(x1_new, x2_new, time): ''' Tool for checking if the motion of the sallite is retrogade or counter - clock wise Args: x1 (numpy array): time and position for point 1 [time1,x1,y1,z1] x2 (numpy array): time and position for point 2 [time2,x2,y2,z2] time (float): time difference between the 2 points Returns: bool: true if we want to keep retrogade, False if we want counter-clock wise ''' l = pkp.lambert_problem(x1_new, x2_new, time, 398600.4405, False) v1 = l.get_v1() v1 = np.asarray(v1) v1 = np.reshape(v1, 3) x1_new = np.asarray(x1_new) kep1 = state_kep.state_kep(x1_new, v1) if kep1[0] < 0.0: traj = True elif kep1[1] > 1.0: traj = True else: traj = False return traj
def cluster(self, t, with_velocity=True, scaling='astro', eps=0.125, min_samples=10): """ USAGE: cl.cluster(self, t, with_velocity=True, scaling='astro', eps=0.125, min_samples=10) - t: epoch (in MJD2000) - with_velocity: when True clusters by position and velocity, otherwise only position is used - scaling: one of - None, or - 'standard' (removing mean and scale to standard variance), or - 'astro' (scaling by PyKEP.AU and PyKEP.EARTH_VELOCITY) - eps: max distance between points in a cluster - min_samples: minimum number of samples per cluster """ import PyKEP import numpy from sklearn.preprocessing import StandardScaler from sklearn.cluster import DBSCAN self._scaling = scaling self._epoch = PyKEP.epoch(t) if with_velocity: self._X = [ [elem for tupl in p.eph(self._epoch) for elem in tupl] for p in self._asteroids] else: self._X = [list(p.eph(self._epoch)[0]) for p in self._asteroids] self._X = numpy.array(self._X) self._scaler = None if self._scaling == 'standard': self._scaler = StandardScaler().fit(self._X) self._X = self._scaler.transform(self._X) elif self._scaling == 'astro': scaling_vector = [PyKEP.AU] * 3 if with_velocity: scaling_vector += [PyKEP.EARTH_VELOCITY] * 3 scaling_vector = numpy.array(scaling_vector) self._X = self._X / scaling_vector[None, :] self._db = DBSCAN(eps=eps, min_samples=min_samples).fit(self._X) self._core_samples = self._db.core_sample_indices_ self.labels = self._db.labels_ self.n_clusters = len( set(self.labels)) - (1 if -1 in self.labels else 0) self.members = {} self.core_members = {} for label in set(self.labels): if int(label) == -1: continue self.members[int(label)] = [index[0] for index in numpy.argwhere(self.labels == label)] self.core_members[int(label)] = [ index for index in self._core_samples if self.labels[index] == label] if self._scaling == 'standard': self._X = self._scaler.inverse_transform(self._X) elif self._scaling == 'astro': self._X = self._X * scaling_vector[None, :]
def eph_matrix(asts, t, ref_ast=None): """ Given a list `asts` of asteroids (either by IDs, or as PyKEP.planet objects) and an epoch `t` (either as an mjd int/float, or as a PyKEP.epoch object), produce the matrix with their normalized ephemerides. If a reference asteroid `ref_ast` is given, its ephemeris will be used as reference for the normalization. Otherwise, AU, EARTH_VELOCITY will be used instead. """ if type(asts[0]) is int: asts = [asteroids[ast] for a in asts] if type(t) in [float, int]: t = pk.epoch(t, 'mjd') if ref_ast is None: norm_ref = AU, EARTH_VELOCITY else: norm_ref = eph_reference(ref_ast, t) # obtain all asteroids' ephemerides eph = np.array([a.eph(t) for a in asts]) # reshape matrix, so each asteroid's ephemeris will be represented by # a single 6 dimensional vector eph = eph.reshape((-1, 6)) # normalize the full matrix return eph_normalize(eph, *norm_ref)
def __init__(self, mass=1000, Tmax=0.05, Isp=2500, Vinf_0=3, Vinf_f=0, nseg=10, departure=None, target=None, optimise4mass=False): """__init__(self,mass=1000,Tmax=0.05,Isp=2500,Vinf_0=3,Vinf_f=0,nseg=10,departure = erath, target = mars)""" try: import PyKEP except ImportError: print("Error while trying 'import PyKEP': is PyKEP installed?") raise if departure is None: departure = PyKEP.planet_ss('earth') if target is None: target = mars = PyKEP.planet_ss('mars') super(py_pl2pl, self).__init__(9 + nseg * 3, 0, 1, 9 + nseg, nseg + 2, 1e-5) self.__departure = departure self.__target = target self.__sc = PyKEP.sims_flanagan.spacecraft(mass, Tmax, Isp) self.__Vinf_0 = Vinf_0 * 1000 self.__Vinf_f = Vinf_f * 1000 self.__leg = PyKEP.sims_flanagan.leg() self.__leg.set_mu(PyKEP.MU_SUN) self.__leg.set_spacecraft(self.__sc) self.__nseg = nseg self.set_bounds([ 0, 10, self.__sc.mass / 10, -abs(self.__Vinf_0), -abs(self.__Vinf_0), -abs(self.__Vinf_0), -abs(self.__Vinf_f), -abs(self.__Vinf_f), -abs(self.__Vinf_f) ] + [-1] * 3 * nseg, [ 3000, 1500, self.__sc.mass, abs(self.__Vinf_0), abs(self.__Vinf_0), abs(self.__Vinf_0), abs(self.__Vinf_f), abs(self.__Vinf_f), abs(self.__Vinf_f) ] + [1] * 3 * nseg) self.__optimise4mass = optimise4mass
def jde_mga_1dsm(seq, t0, tof, slack=5, pop_size=50, n_evolve=10, dv_launch=6127., verbose=False): """Runs jDE with mga_1dsm problem.""" from PyGMO.problem import mga_1dsm_tof from PyGMO.algorithm import jde from PyGMO import population prob = mga_1dsm_tof(seq=[kep.planet_ss(name) for name in seq], t0=[kep.epoch(t0-slack), kep.epoch(t0+slack)], tof=[[t-slack, t+slack] for t in tof], vinf=[0., dv_launch/1000.], add_vinf_arr=False) algo = jde(gen=500, memory=True) pop = population(prob, pop_size) if verbose: print pop.champion.f[0] for i in xrange(n_evolve): pop = algo.evolve(pop) if verbose: print pop.champion.f
def lambert_leg(P1, P2, t0, tof): ast1 = ASTEROIDS[P1] ast2 = ASTEROIDS[P2] r1, v1 = ast1.eph(kep.epoch(t0)) r2, v2 = ast2.eph(kep.epoch(t0 + tof)) lambert = kep.lambert_problem(r1, r2, tof * kep.DAY2SEC, ast1.mu_central_body) vrel_in = tuple(map(lambda x, y: -x + y, lambert.get_v1()[0], v1)) vrel_out = tuple(map(lambda x, y: -x + y, lambert.get_v2()[0], v2)) dv_lambert = np.linalg.norm(vrel_out) + np.linalg.norm(vrel_in) a, _, _, dv_damon = kep.damon(vrel_in, vrel_out, tof*kep.DAY2SEC) m_star = kep.max_start_mass(np.linalg.norm(a), dv_damon, T_max, Isp) return dv_lambert, dv_damon, m_star
def lambert_leg(P1, P2, i, j, t1, t2, tof, vrel=None, dv_launch=0., rendezvous=False): """Compute a lambert leg from planet to planet. Arguments: p1 -- starting planet (str or PyKEP.planet object) p2 -- final planet (str or PyKEP.planet object) t0 -- start time of leg in MJD2000 tof -- time of flight in days Keyword arguments: vrel -- caresian coordinates of the relative velocity before the flyby at p1 dv_launch -- dv discounted at lunch (i.e. if vrel is None) rendezvous -- add final dv Returns: dV, vrel_out, where vrel_out is the relative velocity at the end of the leg at p2 """ p1 = PLANETS[str(P1)] p2 = PLANETS[str(P2)] r1 = state_rosetta.EPH[i][t1][0] v1 = state_rosetta.EPH[i][t1][1] r2 = state_rosetta.EPH[j][t2][0] v2 = state_rosetta.EPH[j][t2][1] lambert = kep.lambert_problem(r1, r2, tof * kep.DAY2SEC, p1.mu_central_body, False, 0) vrel_in = tuple(map(lambda x, y: x - y, lambert.get_v1()[0], v1)) vrel_out = tuple(map(lambda x, y: x - y, lambert.get_v2()[0], v2)) if vrel is None: # launch dv = max(np.linalg.norm(vrel_in) - dv_launch, 0) else: # flyby #print p1.name, p2.name, np.linalg.norm(vrel_in), np.linalg.norm(vrel_out) dv = kep.fb_vel(vrel, vrel_in, p1) if rendezvous: dv += np.linalg.norm(vrel_out) return dv, vrel_out
def write_output_vts(output_vts_format_file, trajectory, earth, mars): """ Function for generating the trajectory of the CubeSat by traj.xyzv in the VTS format """ def tab_write(value): output_vts_format_file.write('%s\t' % value) for value in trajectory: time = value[0] pos = value[1:4] time_integer_part = int(pk.epoch(time).mjd // 1) # integer part of mjd time time_decimal_part = (pk.epoch(time).mjd % 1)*pk.DAY2SEC # converting the decimal part of mjd time to seconds tab_write(time_integer_part) tab_write(time_decimal_part) tab_write(pos[0]/1000.) # the position of the CubeSat along the X axis (in km) tab_write(pos[1]/1000.) tab_write(pos[2]/1000.) tab_write(value[4]) # the velocity of the CubeSat along the X axis (in m/s) tab_write(value[5]) tab_write(value[6]) output_vts_format_file.write('\n')
def pretty(self, x): """Decodes the decision vector x""" import PyKEP start = PyKEP.epoch(x[0]) end = PyKEP.epoch(x[0] + x[1]) r, v = self.__departure.eph(start) v_list = list(v) v_list[0] += x[3] v_list[1] += x[4] v_list[2] += x[5] x0 = PyKEP.sims_flanagan.sc_state(r, v_list, self.__sc.mass) r, v = self.__target.eph(end) xe = PyKEP.sims_flanagan.sc_state(r, v, x[2]) self.__leg.set(start, x0, x[-3 * self.__nseg:], end, xe) print("A direct interplantary transfer\n") print("FROM:") print(self.__departure) print("TO:") print(self.__target) print(self.__leg)
def J(t0, tof): ep1 = pk.epoch(t0) ep2 = pk.epoch(t0 + tof) r1, v1 = p1.eph(ep1) r2, v2 = p2.eph(ep2) resJ = [] for lw in [False, True]: prob = pk.lambert_exposin(r1, r2, tof * pk.DAY2SEC, pk.MU_SUN, lw, n, k2) for i in range(prob.num_solutions()): exps = prob.get_exposins()[i] dv1 = Vector.mag(Vector.sub(prob.get_v1()[i], v1)) dv2 = Vector.mag(Vector.sub(prob.get_v2()[i], v2)) dvlt = exps.get_delta_v(pk.MU_SUN) resJ.append(1.0 - math.exp(-(dv1 + dv2) / 9.81 / isp_chem - dvlt / 9.81 / isp_lt)) if len(resJ) == 0: return numpy.nan else: return numpy.nanmin(resJ)
def cluster(self, t, eps=0.125, min_samples=10, metric='orbital', T=180, ref_r=AU, ref_v=EARTH_VELOCITY): """ USAGE: cl.cluster(t, eps=0.125, min_samples=10, metric='orbital', T=180, ref_r=AU, ref_v=EARTH_VELOCITY): - t: epoch (in MJD2000) - eps: max distance between points in a cluster - min_samples: minimum number of samples per cluster - metric: one of 'euclidean', 'euclidean_r', orbital' - T: average transfer time (used in the definition of the 'orbital' metric) - ref_r reference radius (used as a scaling factor for r if the metric is 'euclidean' or 'euclidean_r') - ref_v reference velocity (used as a scaling factor for v if the metric is 'euclidean') """ import PyKEP import numpy from sklearn.cluster import DBSCAN self._epoch = PyKEP.epoch(t) if metric == 'euclidean': self._X = [ [elem for tupl in p.eph(self._epoch) for elem in tupl] for p in self._asteroids] scaling_vector = [ref_r] * 3 scaling_vector += [ref_v] * 3 elif metric == 'euclidean_r': self._X = [list(p.eph(self._epoch)[0]) for p in self._asteroids] scaling_vector = [ref_r] * 3 elif metric == 'orbital': self._T = T self._X = [self._orbital_metric(*p.eph(self._epoch)) for p in self._asteroids] scaling_vector = [1.] * 6 # no scaling self._X = numpy.array(self._X) scaling_vector = numpy.array(scaling_vector) self._X = self._X / scaling_vector[None, :] self._db = DBSCAN(eps=eps, min_samples=min_samples).fit(self._X) self._core_samples = self._db.core_sample_indices_ self.labels = self._db.labels_ self.n_clusters = len( set(self.labels)) - (1 if -1 in self.labels else 0) self.members = {} self.core_members = {} for label in set(self.labels): if int(label) == -1: continue self.members[int(label)] = [index[0] for index in numpy.argwhere(self.labels == label)] self.core_members[int(label)] = [ index for index in self._core_samples if self.labels[index] == label] self._X = self._X * scaling_vector[None, :]
def parse_trajectory(trajectory_file): dates = [] positions = [] velocities = [] for line in trajectory_file.read().splitlines(): values = [float(element) for element in line.split(' ')] dates.append(pk.epoch(values[0], 'jd')) positions.append([values[1], values[2], values[3]]) velocities.append([values[4], values[5], values[6]]) positions = np.array(positions)*1000 velocities = np.array(velocities)*1000 return dates, positions, velocities
def parse_trajectory(trajectory_file): dates = [] positions = [] velocities = [] for line in trajectory_file.read().splitlines(): values = [float(element) for element in line.split(' ')] dates.append(pk.epoch(values[0], 'jd')) positions.append([values[1], values[2], values[3]]) velocities.append([values[4], values[5], values[6]]) positions = np.array(positions) * 1000 velocities = np.array(velocities) * 1000 return dates, positions, velocities
def lambert_leg(P1, P2, i, j, t1, t2, tof): ast1 = ASTEROIDS[P1] ast2 = ASTEROIDS[P2] r1 = state_asteroids.EPH[i][t1][0] v1 = state_asteroids.EPH[i][t1][1] r2 = state_asteroids.EPH[j][t2][0] v2 = state_asteroids.EPH[j][t2][1] lambert = kep.lambert_problem(r1, r2, tof * kep.DAY2SEC, ast1.mu_central_body) vrel_in = tuple(map(lambda x, y: -x + y, lambert.get_v1()[0], v1)) vrel_out = tuple(map(lambda x, y: -x + y, lambert.get_v2()[0], v2)) dv_lambert = np.linalg.norm(vrel_out) + np.linalg.norm(vrel_in) a, _, _, dv_damon = kep.damon(vrel_in, vrel_out, tof*kep.DAY2SEC) m_star = kep.max_start_mass(np.linalg.norm(a), dv_damon, T_max, Isp) return dv_lambert, dv_damon, m_star
def plot_trajectory(dates, positions, flight_duration): earth = pk.planet.jpl_lp('earth') mars = pk.planet.jpl_lp('mars') fig = pyplot.figure() ax = fig.gca(projection='3d') unzip = zip(*positions) pk.orbit_plots.plot_planet(earth, ax=ax, t0=dates[0]) mars_arrival = pk.epoch(dates[0].mjd2000 + flight_duration) pk.orbit_plots.plot_planet(mars, ax=ax, t0=mars_arrival) ax.plot(unzip[0], unzip[1], unzip[2], color='red') return ax
def __init__(self,mass=1000,Tmax=0.05,Isp=2500,Vinf_0=3,Vinf_f=0,nseg=10,departure = None, target = None, optimise4mass = False): """__init__(self,mass=1000,Tmax=0.05,Isp=2500,Vinf_0=3,Vinf_f=0,nseg=10,departure = erath, target = mars)""" try: import PyKEP except ImportError: print("Error while trying 'import PyKEP': is PyKEP installed?") raise if departure is None: departure = PyKEP.planet_ss('earth') if target is None: target = mars = PyKEP.planet_ss('mars') super(py_pl2pl,self).__init__(9 + nseg*3,0,1,9 + nseg,nseg+2,1e-5) self.__departure = departure self.__target = target self.__sc = PyKEP.sims_flanagan.spacecraft(mass,Tmax,Isp) self.__Vinf_0 = Vinf_0*1000 self.__Vinf_f = Vinf_f*1000 self.__leg = PyKEP.sims_flanagan.leg() self.__leg.set_mu(PyKEP.MU_SUN) self.__leg.set_spacecraft(self.__sc) self.__nseg = nseg self.set_bounds([0,10,self.__sc.mass/10,-abs(self.__Vinf_0),-abs(self.__Vinf_0),-abs(self.__Vinf_0),-abs(self.__Vinf_f),-abs(self.__Vinf_f),-abs(self.__Vinf_f)] + [-1] * 3 *nseg,[3000,1500,self.__sc.mass,abs(self.__Vinf_0),abs(self.__Vinf_0),abs(self.__Vinf_0),abs(self.__Vinf_f),abs(self.__Vinf_f),abs(self.__Vinf_f)] + [1] * 3 * nseg) self.__optimise4mass = optimise4mass
def _create_tles(ep, source, fragments): res = [] ep_date = (datetime.datetime(2000, 1, 1) + datetime.timedelta(ep)).timetuple() ep_day = ep_date.tm_yday + ep_date.tm_hour / 24. + ep_date.tm_min / 24. / 60. + ep_date.tm_sec / 24. / 60. / 60. ep_str = (str(ep_date.tm_year)[2:] + '{:12.8f}'.format(ep_day))[:14] # TODO change satellite ID and posibly alter international identifier? line1 = source.line1[:18] + ep_str + source.line1[32:-1] line1 += str(_checksum(line1)) for fragment in fragments: r, v = source.eph(ep) v = np.array(v) + fragment[-3:] # add dV el = kep.ic2par(r, v, source.mu_central_body) try: n = math.sqrt(source.mu_central_body / (4. * math.pi**2 * el[0]**3)) * kep.DAY2SEC # mean motion in days except: continue # continue to next fragment M = el[5] - el[1] * math.sin(el[5]) if M < 0: M += 2 * math.pi line2 = source.line2[:8] line2 += '{:8.4f} '.format(el[2] * kep.RAD2DEG) # inclination (i) line2 += '{:8.4f} '.format(el[3] * kep.RAD2DEG) # RA (W) line2 += '{:.7f} '.format(el[1])[2:] # eccentrictiy (e) line2 += '{:8.4f} '.format(el[4] * kep.RAD2DEG) # argument of perigee (w) line2 += '{:8.4f} '.format(M * kep.RAD2DEG) # mean anomaly (M) line2 += '{:11.8f}'.format(n) # mean motion # line2 += source.line2[63:68] #'{:5d}'.format(1) # revolutions line2 += '{:5d}'.format(0) # revolutions line2 += str(_checksum(line2)) # sometimes there is an error 'Eccentricity out of range' try: res.append(kep.planet.tle(line1, line2)) except: pass return res
def body_eph_gen_vts(output_vts_format_file, trajectory, body): """ Function for generating the ephemeris of a body by traj.xyzv in the VTS format """ def tab_write(value): output_vts_format_file.write('%s\t' % value) def car2sph(car_pos): r = np.linalg.norm(car_pos) # km lat = np.arcsin(car_pos[2]/r)*180./np.pi # degree lon = np.arctan2(car_pos[1], car_pos[0])*180./np.pi # degree return np.array([lon,lat,r/1000.]) for value in trajectory: time = value[0] pos = value[1:4] sph_temp = car2sph( body.get_relative_position(time, pos) ) time_integer_part = int(pk.epoch(time).mjd // 1) # integer part of mjd time time_decimal_part = (pk.epoch(time).mjd % 1)*pk.DAY2SEC # converting the decimal part of mjd time to seconds tab_write(time_integer_part) tab_write(time_decimal_part) tab_write(sph_temp[1]) # latitude tab_write(sph_temp[0]) # longitude tab_write(sph_temp[2]) output_vts_format_file.write('\n')
def rate__orbital(dep_ast, dep_t, leg_dT, **kwargs): """ Orbital Phasing Indicator. See: http://arxiv.org/pdf/1511.00821.pdf#page=12 Estimates the cost of a `leg_dT` days transfer from departure asteroid `dep_ast` at epoch `dep_t`, towards each of the available asteroids. """ dep_t = pk.epoch(dep_t, 'mjd') leg_dT *= DAY2SEC orbi = [ orbital_indicator(ast, dep_t, leg_dT, **kwargs) for ast in asteroids ] ast_orbi = np.array(orbi[dep_ast]) return np.linalg.norm(ast_orbi - orbi, axis=1)
def _create_tles(ep, source, fragments): res = [] ep_date = (datetime.datetime(2000, 1, 1) + datetime.timedelta(ep)).timetuple() ep_day = ep_date.tm_yday + ep_date.tm_hour/24. + ep_date.tm_min/24./60. + ep_date.tm_sec/24./60./60. ep_str = (str(ep_date.tm_year)[2:] + '{:12.8f}'.format(ep_day))[:14] # TODO change satellite ID and posibly alter international identifier? line1 = source.line1[:18] + ep_str + source.line1[32:-1] line1 += str(_checksum(line1)) for fragment in fragments: r, v = source.eph(ep) v = np.array(v) + fragment[-3:] # add dV el = kep.ic2par(r, v, source.mu_central_body) try: n = math.sqrt(source.mu_central_body/(4.*math.pi**2*el[0]**3)) * kep.DAY2SEC # mean motion in days except: continue # continue to next fragment M = el[5] - el[1] * math.sin(el[5]) if M < 0: M += 2 * math.pi line2 = source.line2[:8] line2 += '{:8.4f} '.format(el[2] * kep.RAD2DEG) # inclination (i) line2 += '{:8.4f} '.format(el[3] * kep.RAD2DEG) # RA (W) line2 += '{:.7f} '.format(el[1])[2:] # eccentrictiy (e) line2 += '{:8.4f} '.format(el[4] * kep.RAD2DEG) # argument of perigee (w) line2 += '{:8.4f} '.format(M * kep.RAD2DEG) # mean anomaly (M) line2 += '{:11.8f}'.format(n) # mean motion # line2 += source.line2[63:68] #'{:5d}'.format(1) # revolutions line2 += '{:5d}'.format(0) # revolutions line2 += str(_checksum(line2)) # sometimes there is an error 'Eccentricity out of range' try: res.append(kep.planet.tle(line1, line2)) except: pass return res
def eph_reference(ref_ast, t): """ Calculate reference r and v magnitudes for use in the normalization of asteroid ephemeris. Returns: (|r|, |v|) where (r,v) is the ephemeris of the given asteroid `ref_ast` (id, or object) at epoch `t` (int/float, or epoch object). """ if type(ref_ast) is int: ref_ast = asteroids[ref_ast] if type(t) in [float, int]: t = pk.epoch(t, 'mjd') r, v = ref_ast.eph(t) return np.linalg.norm(r), np.linalg.norm(v)
def search_min_dv_to_body(body, departure_date, departure_position, host_velocity, min_time_of_flight, time_delta, number): time_range = [min_time_of_flight + time_delta * i for i in xrange(number)] body_positions = [ body.eph(time + departure_date.mjd2000)[0] for time in time_range ] departure_velocities = [ pk.lambert_problem(departure_position, pos, time * pk.DAY2SEC, pk.MU_SUN, False, 0).get_v1()[0] for pos, time in zip(body_positions, time_range) ] deltaV = [ np.linalg.norm(np.array(velocity) - host_velocity) for velocity in departure_velocities ] index_min = np.array(deltaV).argmin() return index_min, departure_velocities[index_min]
def plotOrbits(planets_tle): fig = plt.figure() ax = fig.add_subplot(111, projection='3d') ep = kep.epoch(17) for pln in planets_tle: e = float("0." + pln.line2[26:32]) i = float(pln.line2[8:15]) W = float(pln.line2[17:24]) w = float(pln.line2[34:41]) M = 20 # print e,i,W,w oe = [ 2000000 + 6378000, e, i * kep.DEG2RAD, W * kep.DEG2RAD, w * kep.DEG2RAD, M * kep.DEG2RAD ] pl = kep.planet.keplerian(ep, oe, earth.mu_self, 0, 0, 0, '') kep.orbit_plots.plot_planet(pl, ax=ax, alpha=0.2, s=0, color='red') plt.show()
def jup_eph_gen(output_file, trajectory, jupiter): def tab_write(value): output_file.write('%s\t' % value) def car2sph(car_pos): r = np.linalg.norm(car_pos) # km lat = np.arcsin(car_pos[2]/r)*180./np.pi # degree lon = np.arctan2(car_pos[1], car_pos[0])*180./np.pi # degree return np.array([lon,lat,r/1000.]) for value in trajectory: time = value[0] pos = value[1:4] sph_temp = car2sph( jupiter.get_relative_position(time, pos) ) tab_write(pk.epoch(time).jd) tab_write(sph_temp[1]) # latitude tab_write(sph_temp[0]) # longitude tab_write(sph_temp[2]) output_file.write('\n')
def jup_eph_gen(output_file, trajectory, jupiter): def tab_write(value): output_file.write('%s\t' % value) def car2sph(car_pos): r = np.linalg.norm(car_pos) # km lat = np.arcsin(car_pos[2] / r) * 180. / np.pi # degree lon = np.arctan2(car_pos[1], car_pos[0]) * 180. / np.pi # degree return np.array([lon, lat, r / 1000.]) for value in trajectory: time = value[0] pos = value[1:4] sph_temp = car2sph(jupiter.get_relative_position(time, pos)) tab_write(pk.epoch(time).jd) tab_write(sph_temp[1]) # latitude tab_write(sph_temp[0]) # longitude tab_write(sph_temp[2]) output_file.write('\n')
def body_eph_gen(output_file, trajectory, body): """ Function for generating the ephemeris of a body by traj.xyzv """ def tab_write(value): output_file.write('%s\t' % value) def car2sph(car_pos): r = np.linalg.norm(car_pos) # km lat = np.arcsin(car_pos[2] / r) * 180. / np.pi # degree lon = np.arctan2(car_pos[1], car_pos[0]) * 180. / np.pi # degree return np.array([lon, lat, r / 1000.]) for value in trajectory: time = value[0] pos = value[1:4] sph_temp = car2sph(body.get_relative_position(time, pos)) tab_write(pk.epoch(time).jd) tab_write(sph_temp[1]) # latitude tab_write(sph_temp[0]) # longitude tab_write(sph_temp[2]) output_file.write('\n')
def parse_traj(self, trajectory_file): """Method reading the contents of a specified trajectory file and returning the data from last line of file as a tuple of an epoch, an array of position vector and an array of velocity vector. Returns date (string format), position (m), velocity (km). """ d = motion.Date() p = motion.Position() v = motion.Velocity() for line in trajectory_file.read().splitlines(): values = [float(element) for element in line.split(' ')] d.date = pk.epoch(values[0], 'jd') p.x = values[1] p.y = values[2] p.z = values[3] v.vx = values[4] v.vy = values[5] v.vz = values[6] return d.date, p.xyz_array() * 1000, v.vxvyvz_array() * 1000
def write_output(output_file, trajectory, earth, mars): def tab_write(value): output_file.write('%s\t' % value) for value in trajectory: time = value[0] pos = value[1:4] tab_write(pk.epoch(time).jd) tab_write(pos[0]/1000.) # the position of the CubeSat along the X axis (in km) tab_write(pos[1]/1000.) tab_write(pos[2]/1000.) tab_write(value[4]) # the velocity of the CubeSat along the X axis (in m/s) tab_write(value[5]) tab_write(value[6]) tab_write(np.linalg.norm(pos)/1000.) # the radii of the CubeSat from the Sun (in km) tab_write(np.linalg.norm(earth.get_relative_position(time, pos))/1000.) # the radii of the CubeSat from the Earth (in km) tab_write(np.linalg.norm(mars.get_relative_position(time, pos))/1000.) # the radii of the CubeSat from the Mars (in km) tab_write(np.linalg.norm(earth.eph(time))/1000.) # the radii of Earth from the Sun (in km) output_file.write('%s' % (np.linalg.norm(mars.eph(time))/1000.) ) # the radii of Mars from the Sun (in km) output_file.write('\n')
def computeSpatialDensities(planets): altStart = 200 # altitude from [km] step = 20 # size of bins [km] spaceDens = [] for alt in range(altStart, 2000, step): noOfPlanInAlt = 0 for i in range(1, len(debris)): try: r, v = debris[i].eph(16 * 365) except: continue el = kep.ic2par(r, v, debris[i].mu_central_body) altitude = (el[0] - 6378000) / 1000 if altitude >= alt and altitude < (alt + step): noOfPlanInAlt += 1 vol1 = (alt + 6378)**3 * math.pi * 4 / 3 vol2 = (alt + step + 6378)**3 * math.pi * 4 / 3 totVol = vol2 - vol1 spaceDens.append(noOfPlanInAlt / totVol) return spaceDens
def body_eph_gen(output_file, trajectory, body): """ Function for generating the ephemeris of a body by traj.xyzv """ def tab_write(value): output_file.write('%s\t' % value) def car2sph(car_pos): r = np.linalg.norm(car_pos) # km lat = np.arcsin(car_pos[2]/r)*180./np.pi # degree lon = np.arctan2(car_pos[1], car_pos[0])*180./np.pi # degree return np.array([lon,lat,r/1000.]) for value in trajectory: time = value[0] pos = value[1:4] sph_temp = car2sph( body.get_relative_position(time, pos) ) tab_write(pk.epoch(time).jd) tab_write(sph_temp[1]) # latitude tab_write(sph_temp[0]) # longitude tab_write(sph_temp[2]) output_file.write('\n')
def computeSpatialDensities(planets): altStart = 200 # altitude from [km] step = 20 # size of bins [km] spaceDens = [] for alt in range(altStart, 2000, step): noOfPlanInAlt = 0 for i in range(1,len(debris)): try: r, v = debris[i].eph(16*365) except: continue el = kep.ic2par(r, v, debris[i].mu_central_body) altitude = (el[0]-6378000)/1000 if altitude >= alt and altitude < (alt+step): noOfPlanInAlt += 1 vol1 = (alt+6378)**3 * math.pi * 4 / 3 vol2 = (alt+step+6378)**3 * math.pi * 4 / 3 totVol = vol2-vol1 spaceDens.append(noOfPlanInAlt/totVol) return spaceDens
def _create_tles(ep, source, fragments): res = [] ep_date = (datetime.datetime(2000, 1, 1) + datetime.timedelta(ep)).timetuple() ep_day = ep_date.tm_yday + ep_date.tm_hour / 24. + ep_date.tm_min / 24. / 60. + ep_date.tm_sec / 24. / 60. / 60. ep_str = (str(ep_date.tm_year)[2:] + '{:12.8f}'.format(ep_day))[:14] ep_year = ep_date.tm_year line10 = source.line1[:18] + ep_str + source.line1[32:-1] r0, v0 = source.eph(ep) v0 = np.array(v0) for fragment in fragments: v = v0 + fragment[-3:] # add dV r = r0 el = kep.ic2par(r, v, source.mu_central_body) try: n = math.sqrt(source.mu_central_body / (4. * math.pi**2 * el[0]**3)) * kep.DAY2SEC # mean motion in days except: continue # continue to next fragment M = el[5] - el[1] * math.sin(el[5]) if M < 0: M += 2 * math.pi # added by Alex Wittig to include also individual drag coefficients for fragments bstar = 0.5 * 2.2 * fragment[ 2] * 2.461e-5 # compute B* from A/m and assumed CD=2.2 (see https://en.wikipedia.org/wiki/BSTAR for magic constant) logb = np.log10(abs(bstar)) iexp = int(logb) if logb >= 0: iexp = iexp + 1 mant = 10.0**(logb - iexp) line1 = line10[0:53] + '{:1s}{:05d}{:1s}{:01d}'.format( ' ' if bstar >= 0.0 else '-', int(mant * 100000), '0' if iexp >= 0 else '-', abs(iexp)) + line10[61:] line1 += str(_checksum(line1)) line2 = source.line2[:8] line2 += '{:8.4f} '.format(el[2] * kep.RAD2DEG) # inclination (i) line2 += '{:8.4f} '.format(el[3] * kep.RAD2DEG) # RA (W) line2 += '{:.7f} '.format(el[1])[2:] # eccentrictiy (e) line2 += '{:8.4f} '.format(el[4] * kep.RAD2DEG) # argument of perigee (w) line2 += '{:8.4f} '.format(M * kep.RAD2DEG) # mean anomaly (M) line2 += '{:11.8f}'.format(n) # mean motion line2 += '{:5d}'.format(0) # revolutions line2 += str(_checksum(line2)) try: tle_new = kep.planet.tle(line1, line2) tle_new.set_epoch(int(ep_year), float(ep_day)) tle_new.mass = fragment[3] tle_new.radius = (tle_new.mass / ( (4. / 3.) * math.pi * 92.937 * 2**(-0.74)))**(1 / 2.26) tle_new.name = tle_new.name.strip() + "-DEB" res.append(tle_new) except: pass # print kep.planet.tle(line1, line2).mass return res
def __init__(self, mass=1000, Tmax=0.05, Isp=2500, Vinf_0=3, Vinf_f=1e-12, nseg=10, departure=None, target=None, optimise4mass=False): """ Constructs a low-thrust transfer between a departure planet and a target planet (Constrained Continuous Single-Objective) NOTE: An impulsive transcription is used to transform into an NLP the Optimal Control Problem USAGE: problem.py_pl2pl(self,mass=1000,Tmax=0.05,Isp=2500,Vinf_0=3,Vinf_f=0,nseg=10,departure = PyKEP.planet_ss('earth'), target = PyKEP.planet_ss('mars')) * mass: spacecraft mass at departure [kg] * Tmax: maximum allowed thrust [N] * Isp: spacecarft engine specific impulse [Isp] * Vinf_0: allowed maximum starting velocity [km/s] * Vinf_f: allowed maximum arrival velocity [km/s] (if negative it is interpreted as a minimum arrival velocity) * nseg: number of segments used for the impulsive transcription * departure: departure planet (a PyKEP planet) * target: arrival planet (a PyKEP planet) """ try: import PyKEP except ImportError: raise ImportError( "Error while trying 'import PyKEP': is PyKEP installed?") if departure is None: departure = PyKEP.planet_ss('earth') if target is None: target = mars = PyKEP.planet_ss('mars') super(py_pl2pl, self).__init__(9 + nseg * 3, 0, 1, 9 + nseg, nseg + 2, 1e-5) self.__departure = departure self.__target = target self.__sc = PyKEP.sims_flanagan.spacecraft(mass, Tmax, Isp) self.__Vinf_0 = Vinf_0 * 1000 self.__Vinf_f = Vinf_f * 1000 self.__leg = PyKEP.sims_flanagan.leg() self.__leg.set_mu(departure.mu_central_body) self.__leg.set_spacecraft(self.__sc) self.__nseg = nseg self.set_bounds([ 0, 10, self.__sc.mass / 10, -abs(self.__Vinf_0), -abs(self.__Vinf_0), -abs(self.__Vinf_0), -abs(self.__Vinf_f), -abs(self.__Vinf_f), -abs(self.__Vinf_f) ] + [-1] * 3 * nseg, [ 3000, 1500, self.__sc.mass, abs(self.__Vinf_0), abs(self.__Vinf_0), abs(self.__Vinf_0), abs(self.__Vinf_f), abs(self.__Vinf_f), abs(self.__Vinf_f) ] + [1] * 3 * nseg) self.__optimise4mass = optimise4mass
# "The weight of such a scientific equipment is set to be 40 kg at each # asteroid. The second asteroid encounter (fly-by) corresponds to the delivery # of a 1 kg penetrator." MASS_EQUIPMENT = 40.0 MASS_PENETRATOR = 1.0 # constraint for the flyby to deliver the penetrator: # "flyby asteroid with a velocity not less than dV_min = 0.4 km/s." dV_fb_min = 400.0 # m/s # "The flight time, measured from start to the end must not exceed 15 years" TIME_MAX = 15 * YEAR2DAY # 5478.75 days # "The year of launch must lie in the range 2015 to 2025, inclusive: # 57023 MJD <= t_s <= 61041 MJD." TRAJ_START_MIN = pk.epoch(57023, 'mjd') TRAJ_START_MAX = pk.epoch(61041, 'mjd') # >>> TRAJ_START_MIN, TRAJ_START_MAX # (2015-Jan-01 00:00:00, 2026-Jan-01 00:00:00) TRAJ_END_MIN = pk.epoch(TRAJ_START_MIN.mjd + TIME_MAX, 'mjd') TRAJ_END_MAX = pk.epoch(TRAJ_START_MAX.mjd + TIME_MAX, 'mjd') # >>> TRAJ_END_MIN, TRAJ_END_MAX # (2029-Dec-31 18:00:00, 2040-Dec-31 18:00:00) # ==================================== # GTOC5 asteroids (body objects) # Earth's Keplerian orbital parameters # Source: http://dx.doi.org/10.2420/AF08.2014.9 (Table 1) _earth_op = ( pk.epoch(54000, 'mjd'), # t
def __init__(self, *args, **kwargs): super(BasePlanet, self).__init__(*args, **kwargs) self.semi_major_axis, self.eccentricity, self.inclination, self.longitude_asc_node, self.arg_periapsis, _ = self.osculating_elements(pk.epoch(0)) self.soi = self.semi_major_axis*(self.mu_self/self.mu_central_body)**(2./5)
def __init__(self, seq=[ PyKEP.planet_gtoc7(3413), PyKEP.planet_gtoc7(234), PyKEP.planet_gtoc7(11432) ], n_seg=5, t0=[13000, 13200], leg_tof=[1, 365.25 * 3], rest=[30., 365.25], mass=[800, 2000], Tmax=0.3, Isp=3000., traj_tof=365.25 * 6, objective='mass', c_tol=1e-05): """ prob = mr_lt_nep(seq=[PyKEP.planet_gtoc7(3413),PyKEP.planet_gtoc7(234), PyKEP.planet_gtoc7(11432)], n_seg=5, t0=[13000, 13200], leg_tof=[1, 365.25 * 3], rest=[30., 365.25], mass=[800, 2000], Tmax=0.3, Isp=3000., traj_tof=365.25 * 6, objective='mass', c_tol=1e-05) * seq: list of PyKEP.planet defining the encounter sequence for the trajectoty (including the initial planet) * n_seg: list of integers containing the number of segments to be used for each leg (len(n_seg) = len(seq)-1) * t0: list of two PyKEP epochs defining the launch window * leg_tof: list of two floats defining the minimum and maximum time of each leg (days) * rest: list of two floats defining the minimum and maximum time the spacecraft can rest at one planet (days) * mass: list of two floats defining the minimum final spacecraft mass and the starting spacecraft mass (kg) * Tmax: maximum thrust (N) * Isp: engine specific impulse (sec) * traj_tof maximum total mission duration (days) * c_tol: tolerance on the constraints """ # Number of legs n = len(seq) - 1 # Problem dimension dim = (4 + n_seg * 3) * n + 1 # Number of equality constraints dim_eq = 7 * n # Number of Inequality constraints dim_ineq = n * n_seg + n # We call the base problem constaructor super(mr_lt_nep, self).__init__( dim, 0, 1, dim_eq + dim_ineq, # constraint dimension dim_ineq, # inequality constraints 1e-5) # constrain tolerance # We define data members self.__seq = seq self.__num_legs = n self.__nseg = n_seg self.__dim_leg = 4 + n_seg * 3 self.__start_mass = mass[1] self.__max_total_time = traj_tof # We create n distinct legs objects self.__legs = [] for i in range(n): self.__legs.append(PyKEP.sims_flanagan.leg()) for leg in self.__legs: leg.high_fidelity = True leg.set_mu(PyKEP.MU_SUN) if not objective in ['mass', 'time']: raise ValueError( "Error in defining the objective. Was it one of mass or time?") self.__objective = objective # We set the ptoblem box-bounds # set leg bounds lb_leg = [t0[0], leg_tof[0], rest[0], mass[0]] + [-1] * n_seg * 3 ub_leg = [t0[1] + traj_tof * n, leg_tof[1], rest[1], mass[1] ] + [1] * n_seg * 3 # set n leg bounds lb = lb_leg * n ub = [t0[1], leg_tof[1], rest[1], mass[1] ] + [1] * n_seg * 3 + ub_leg * (n - 1) # set total time bounds lb += [1.] ub += [self.__max_total_time] self.set_bounds(lb, ub)
def plot_track(self,data,predict=True,longplot=False): UT = data[0] shippids = data[1] fig = plt.figure(figsize=(20,10)) kmap = mpl_toolkits.basemap.Basemap(rsphere=600000,celestial=True,resolution=None) im = plt.imread("Kerbin_elevation.png") #implot = plt.imshow(im) kmap.imshow(im,origin="upper") #UT = float(ss["UT"]) / 60 / 60 / 24 #ships = ss["VESSELS"] #colors = ["red","green","white","cyan","orange","yellow","purple","brown"] nearest=lambda a,l:min(l,key=lambda x:abs(x-a)) # Thanks stackexchange if longplot: steps = 720 #Minutes else: steps = 30 #Minutes trackTime = steps/60/24 # 30 minutes stepTime = 1.0/60.0/24.0 # 1 minute reserved = [] for ship in shippids.values(): last_rascension = None last_declination = None if "debris" in ship.name.lower(): continue XY = [] for i in xrange(steps): stepEpoch = UT - i*stepTime if stepEpoch<ship.min and not predict: #TODO: predictorbits stepEpoch = ship.min #This is to ensure that no orbits are drawn which have unsure stuff nt = nearest(stepEpoch,ship.datapoints.keys()) print "Epoch ",stepEpoch,"using datapoint",nt dp = ship.datapoints[nt] if len(dp) == 2: XY.append([dp[0],dp[1]]) elif len(dp) == 7: E = PyKEP.epoch(dp[0]) KepShip = PyKEP.planet(E,[dp[1],dp[2],dp[3],dp[4],dp[5],dp[6]],3531600000000,1,1,1) r,v = KepShip.eph(PyKEP.epoch(stepEpoch)) r = np.array(r) theta = -0.000290888209 * stepEpoch * 60 * 60 * 24 rmatrix = np.array([[np.cos(theta),np.sin(theta),0],[-np.sin(theta),np.cos(theta),0],[0,0,1]]) rr=np.dot(r,rmatrix) ur = rr / np.linalg.norm(rr) declination = np.arcsin(ur[2]) if ur[1] > 0: rascension = np.degrees(np.arccos(ur[0] / np.cos(declination))) elif ur[1] <= 0: rascension = - np.degrees(np.arccos(ur[0]/ np.cos(declination))) # print "360-",np.degrees(np.arccos(ur[0]/ np.cos(declination))) declination = np.degrees(declination) # Insert NaN if crossing 180 or -180 if last_rascension != None: dif = rascension - last_rascension if dif > 180 or dif < -180: if dif < -180: # Going from 180 to -180 k = (declination - last_declination) / ((rascension - 180) + (180-last_rascension)) d = (180 - last_rascension)*k + last_declination XY.append([180,d]) XY.append([np.NaN,np.NaN]) XY.append([-180,d]) else: # Going from -180 to 180 k = (declination - last_declination) / ((180-rascension) + (last_rascension-180)) d = (last_rascension-180)*k + last_declination XY.append([-180,d]) XY.append([np.NaN,np.NaN]) XY.append([180,d]) XY.append([np.NaN,np.NaN]) #FLIP last_rascension = rascension last_declination = declination XY.append([rascension,declination]) else: print "Error" sys.exit(1) lastx = None lasty = None #color = random.choice(colors) r = random.randint(100,255) / 255.0 g = random.randint(100,255)/ 255.0 b = random.randint(100,255)/ 255.0 color = (r,g,b) #colors.remove(color) alphafade = 1.0 / len(XY) for i,point in enumerate(XY): if i == 0: lastx = point[0] lasty = point[1] continue x = point[0] y = point[1] if lastx and lasty: kmap.plot([x,lastx],[y,lasty],color=color,alpha=1-i*alphafade) lastx = x lasty = y kmap.plot(XY[0][0],XY[0][1],marker="x",markersize=10,color=color) kmap.plot(XY[0][0],XY[0][1],marker="+",markersize=10,color=color) if XY[0][0] > 0: mx = -4*len(ship.name) else: mx = 2*len(ship.name) if XY[0][1] >= 0: my = -20+XY[0][1] while int(my/5) in reserved: my-=5 reserved.append(int(my/5)) elif XY[0][1] < 0: my = 20+XY[0][1] while int(my/5) in reserved: my+=5 reserved.append(int(my/5)) print "ship:",ship.name,mx,my print "reserved",reserved plt.annotate(ship.name,xy=(XY[0][0],XY[0][1]), xycoords="data",xytext=(mx+XY[0][0],my),textcoords="data",color=color,arrowprops=dict(arrowstyle="->",color=color)) days = int(UT) years = days / 365 + 1 days %= 365 days += 1 plt.title("Kerbin satellite ground track - Year %i, Day %i"%(years,days)) print ("Track.py completed succesfully") return plt
''' Check the state vector of an exposin for discrepancies ''' import PyKEP earth = PyKEP.planet.jpl_lp('earth') mars = PyKEP.planet.jpl_lp('mars') k2 = 0.6 n = 1 t0 = 250.0 tof = 520.0 lw = True r1, v1 = earth.eph(PyKEP.epoch(t0, "mjd2000")) r2, v2 = mars.eph(PyKEP.epoch(t0 + tof, "mjd2000")) prob = PyKEP.lambert_exposin(r1, r2, tof * PyKEP.DAY2SEC, PyKEP.MU_SUN, lw, n, k2) print prob ''' To look for discrepancies in propagated state, we find v by propagation as well as the implemented analytical v ''' import random import Vector exps = prob.get_exposins()[0] # any random progress into the trajectory rand_psi = random.uniform(0.0, exps.get_psi()) r, v, a = exps.get_state(rand_psi, PyKEP.MU_SUN)
def set_t_res(t_res): global T_RES global T_SCALE T_RES = t_res T_SCALE = {name: np.arange(T_MIN, T_MAX, tools.PLANETS[name].compute_period(kep.epoch(0))/+ kep.DAY2SEC/T_RES) for name in PLANET_NAMES}
PLANET_TOF[('venus', 'jupiter')] = (400., 1600.) PLANET_TOF[('venus', '67p')] = (500., 3000.) PLANET_TOF[('mars', 'mars')] = (780., 1600.) PLANET_TOF[('mars', 'jupiter')] = (400., 1600.) PLANET_TOF[('mars', '67p')] = (500., 3000.) PLANET_TOF[('jupiter', 'jupiter')] = (4332., 9000.) PLANET_TOF[('jupiter', '67p')] = (500., 3000.) #TOF the same coming and going for (p1, p2) in PLANET_TOF.keys(): PLANET_TOF[(p2, p1)] = PLANET_TOF[(p1, p2)] #Comet = Final Destination chury = kep.planet.keplerian(kep.epoch(2456879.5, 'jd'), ( 3.4630 * kep.AU, # a 0.64102, # e 7.0405 * kep.DEG2RAD, # i 50.147 * kep.DEG2RAD, # W 12.780 * kep.DEG2RAD, # w 303.71 * kep.DEG2RAD # M ), kep.MU_SUN, 1e-10, # mu_self 5.e3, # radius 100.e3, # save_radius '67p' ) tools.PLANETS[chury.name] = chury