예제 #1
0
    def plot_orbits(self, pop, ax=None):
        import matplotlib.pylab as plt
        from mpl_toolkits.mplot3d import Axes3D

        A1, A2 = self._ast1, self._ast2

        if ax is None:
            fig = plt.figure()
            axis = fig.add_subplot(111, projection='3d')
        else:
            axis = ax

        plot_planet(A1, axes=axis, s=10, t0=epoch(self.lb[0]))
        plot_planet(A2, axes=axis, s=10, t0=epoch(self.ub[0]))
        for ind in pop:
            if ind.cur_f[0] == self._UNFEASIBLE:
                continue
            dep, arr = ind.cur_x
            rdep, vdep = A1.eph(epoch(dep))
            rarr, varr = A2.eph(epoch(arr))
            l = lambert_problem(rdep, rarr, (arr - dep) *
                                DAY2SEC, A1.mu_central_body, False, 1)
            axis = plot_lambert(l, axes=axis, alpha=0.8, color='k')

        if ax is None:
            plt.show()

        return axis
예제 #2
0
파일: _lambert.py 프로젝트: darioizzo/pykep
    def plot_orbits(self, pop, ax=None):
        import matplotlib.pylab as plt
        from mpl_toolkits.mplot3d import Axes3D

        A1, A2 = self._ast1, self._ast2

        if ax is None:
            fig = plt.figure()
            axis = fig.add_subplot(111, projection='3d')
        else:
            axis = ax

        plot_planet(A1, ax=axis, s=10, t0=epoch(self.lb[0]))
        plot_planet(A2, ax=axis, s=10, t0=epoch(self.ub[0]))
        for ind in pop:
            if ind.cur_f[0] == self._UNFEASIBLE:
                continue
            dep, arr = ind.cur_x
            rdep, vdep = A1.eph(epoch(dep))
            rarr, varr = A2.eph(epoch(arr))
            l = lambert_problem(rdep, rarr, (arr - dep) *
                                DAY2SEC, A1.mu_central_body, False, 1)
            axis = plot_lambert(l, ax=axis, alpha=0.8, color='k')

        if ax is None:
            plt.show()

        return axis
예제 #3
0
    def pretty(self, x):
        # 1 -  we 'decode' the chromosome recording the various deep space
        # manouvres timing (days) in the list T
        T = list([0] * (self.N_max - 1))

        for i in range(len(T)):
            T[i] = log(x[2 + 4 * i])
        total = sum(T)
        T = [x[1] * time / total for time in T]

        # 2 - We compute the starting and ending position
        r_start, v_start = self.start.eph(epoch(x[0]))
        if self.phase_free:
            r_target, v_target = self.target.eph(epoch(x[-1]))
        else:
            r_target, v_target = self.target.eph(epoch(x[0] + x[1]))

        # 3 - We loop across inner impulses
        rsc = r_start
        vsc = v_start
        for i, time in enumerate(T[:-1]):
            theta = 2 * pi * x[3 + 4 * i]
            phi = acos(2 * x[4 + 4 * i] - 1) - pi / 2

            Vinfx = x[5 + 4 * i] * cos(phi) * cos(theta)
            Vinfy = x[5 + 4 * i] * cos(phi) * sin(theta)
            Vinfz = x[5 + 4 * i] * sin(phi)

            # We apply the (i+1)-th impulse
            vsc = [a + b for a, b in zip(vsc, [Vinfx, Vinfy, Vinfz])]
            rsc, vsc = propagate_lagrangian(
                rsc, vsc, T[i] * DAY2SEC, self.__common_mu)
        cw = (ic2par(rsc, vsc, self.start.mu_central_body)[2] > pi / 2)

        # We now compute the remaining two final impulses
        # Lambert arc to reach seq[1]
        dt = T[-1] * DAY2SEC
        l = lambert_problem(rsc, r_target, dt, self.__common_mu, cw, False)
        v_end_l = l.get_v2()[0]
        v_beg_l = l.get_v1()[0]

        DV1 = norm([a - b for a, b in zip(v_beg_l, vsc)])
        DV2 = norm([a - b for a, b in zip(v_end_l, v_target)])

        DV_others = list(x[5::4])
        DV_others.extend([DV1, DV2])

        print("Total DV (m/s): ", sum(DV_others))
        print("Dvs (m/s): ", DV_others)
        print("Tofs (days): ", T)
예제 #4
0
    def fitness(self, x):
        # 1 -  we 'decode' the chromosome into the various deep space
        # manouvres times (days) in the list T
        T = list([0] * (self.N_max - 1))

        for i in range(len(T)):
            T[i] = log(x[2 + 4 * i])
        total = sum(T)
        T = [x[1] * time / total for time in T]

        # 2 - We compute the starting and ending position
        r_start, v_start = self.start.eph(epoch(x[0]))
        if self.phase_free:
            r_target, v_target = self.target.eph(epoch(x[-1]))
        else:
            r_target, v_target = self.target.eph(epoch(x[0] + x[1]))

        # 3 - We loop across inner impulses
        rsc = r_start
        vsc = v_start
        for i, time in enumerate(T[:-1]):
            theta = 2 * pi * x[3 + 4 * i]
            phi = acos(2 * x[4 + 4 * i] - 1) - pi / 2

            Vinfx = x[5 + 4 * i] * cos(phi) * cos(theta)
            Vinfy = x[5 + 4 * i] * cos(phi) * sin(theta)
            Vinfz = x[5 + 4 * i] * sin(phi)

            # We apply the (i+1)-th impulse
            vsc = [a + b for a, b in zip(vsc, [Vinfx, Vinfy, Vinfz])]
            rsc, vsc = propagate_lagrangian(
                rsc, vsc, T[i] * DAY2SEC, self.__common_mu)
        cw = (ic2par(rsc, vsc, self.start.mu_central_body)[2] > pi / 2)

        # We now compute the remaining two final impulses
        # Lambert arc to reach seq[1]
        dt = T[-1] * DAY2SEC
        l = lambert_problem(rsc, r_target, dt, self.__common_mu, cw, False)
        v_end_l = l.get_v2()[0]
        v_beg_l = l.get_v1()[0]

        DV1 = norm([a - b for a, b in zip(v_beg_l, vsc)])
        DV2 = norm([a - b for a, b in zip(v_end_l, v_target)])

        DV_others = sum(x[5::4])
        if self.obj_dim == 1:
            return (DV1 + DV2 + DV_others,)
        else:
            return (DV1 + DV2 + DV_others, x[1])
예제 #5
0
    def plot(self, x, axes=None, units=AU, N=60):
        """plot(self, x, axes=None, units=pk.AU, N=60)

        Plots the spacecraft trajectory.

        Args:
            - x (``tuple``, ``list``, ``numpy.ndarray``): Decision chromosome.
            - axes (``matplotlib.axes._subplots.Axes3DSubplot``): 3D axes to use for the plot
            - units (``float``, ``int``): Length unit by which to normalise data.
            - N (``float``): Number of points to plot per leg
        """
        import matplotlib as mpl
        import matplotlib.pyplot as plt
        from mpl_toolkits.mplot3d import Axes3D

        from pykep.orbit_plots import plot_planet, plot_lambert

        # Creating the axes if necessary
        if axes is None:
            mpl.rcParams['legend.fontsize'] = 10
            fig = plt.figure()
            axes = fig.gca(projection='3d')

        T = self._decode_tofs(x)
        ep = np.insert(T, 0, x[0])  # [t0, T1, T2 ...]
        ep = np.cumsum(ep)  # [t0, t1, t2, ...]
        _, _, _, l, _ = self._compute_dvs(x)
        for pl, e in zip(self.seq, ep):
            plot_planet(pl, epoch(e), units=units, legend=True,
                        color=(0.7, 0.7, 1), axes=axes)
        for lamb in l:
            plot_lambert(lamb, N=N, sol=0, units=units, color='k',
                         legend=False, axes=axes, alpha=0.8)
        return axes
예제 #6
0
    def fitness(self, x):
        # 1 -  we 'decode' the chromosome recording the various times of flight
        # (days) in the list T and the cartesian components of vinf
        T, Vinfx, Vinfy, Vinfz = self._decode_times_and_vinf(x)

        # 2 - We compute the epochs and ephemerides of the planetary encounters
        t_P = list([None] * (self.__n_legs + 1))
        r_P = list([None] * (self.__n_legs + 1))
        v_P = list([None] * (self.__n_legs + 1))
        DV = list([0.0] * (self.__n_legs + 1))
        for i, planet in enumerate(self.seq):
            t_P[i] = epoch(x[0] + sum(T[0:i]))
            r_P[i], v_P[i] = self.seq[i].eph(t_P[i])

        # 3 - We start with the first leg
        v0 = [a + b for a, b in zip(v_P[0], [Vinfx, Vinfy, Vinfz])]
        r, v = propagate_lagrangian(r_P[0], v0, x[5] * T[0] * DAY2SEC,
                                    self.common_mu)

        # Lambert arc to reach seq[1]
        dt = (1 - x[5]) * T[0] * DAY2SEC
        l = lambert_problem(r, r_P[1], dt, self.common_mu, False, False)
        v_end_l = l.get_v2()[0]
        v_beg_l = l.get_v1()[0]

        # First DSM occuring at time nu1*T1
        DV[0] = norm([a - b for a, b in zip(v_beg_l, v)])

        # 4 - And we proceed with each successive leg
        for i in range(1, self.__n_legs):
            # Fly-by
            v_out = fb_prop(v_end_l, v_P[i],
                            x[8 + (i - 1) * 4] * self.seq[i].radius,
                            x[7 + (i - 1) * 4], self.seq[i].mu_self)
            # s/c propagation before the DSM
            r, v = propagate_lagrangian(r_P[i], v_out,
                                        x[9 + (i - 1) * 4] * T[i] * DAY2SEC,
                                        self.common_mu)
            # Lambert arc to reach Earth during (1-nu2)*T2 (second segment)
            dt = (1 - x[9 + (i - 1) * 4]) * T[i] * DAY2SEC
            l = lambert_problem(r, r_P[i + 1], dt, self.common_mu, False,
                                False)
            v_end_l = l.get_v2()[0]
            v_beg_l = l.get_v1()[0]
            # DSM occuring at time nu2*T2
            DV[i] = norm([a - b for a, b in zip(v_beg_l, v)])

        # Last Delta-v
        if self.__add_vinf_arr:
            DV[-1] = norm([a - b for a, b in zip(v_end_l, v_P[-1])])

        if self.__add_vinf_dep:
            DV[0] += x[3]

        if self._obj_dim == 1:
            return (sum(DV), )
        else:
            return (sum(DV), sum(T))
예제 #7
0
    def fitness(self, x):
        # 1 -  we 'decode' the chromosome recording the various times of flight
        # (days) in the list T and the cartesian components of vinf
        T, Vinfx, Vinfy, Vinfz = self._decode_times_and_vinf(x)

        # 2 - We compute the epochs and ephemerides of the planetary encounters
        t_P = list([None] * (self.__n_legs + 1))
        r_P = list([None] * (self.__n_legs + 1))
        v_P = list([None] * (self.__n_legs + 1))
        DV = list([0.0] * (self.__n_legs + 1))
        for i, planet in enumerate(self.seq):
            t_P[i] = epoch(x[0] + sum(T[0:i]))
            r_P[i], v_P[i] = self.seq[i].eph(t_P[i])

        # 3 - We start with the first leg
        v0 = [a + b for a, b in zip(v_P[0], [Vinfx, Vinfy, Vinfz])]
        r, v = propagate_lagrangian(
            r_P[0], v0, x[5] * T[0] * DAY2SEC, self.common_mu)

        # Lambert arc to reach seq[1]
        dt = (1 - x[5]) * T[0] * DAY2SEC
        l = lambert_problem(r, r_P[1], dt, self.common_mu, False, False)
        v_end_l = l.get_v2()[0]
        v_beg_l = l.get_v1()[0]

        # First DSM occuring at time nu1*T1
        DV[0] = norm([a - b for a, b in zip(v_beg_l, v)])

        # 4 - And we proceed with each successive leg
        for i in range(1, self.__n_legs):
            # Fly-by
            v_out = fb_prop(v_end_l, v_P[i], x[
                            8 + (i - 1) * 4] * self.seq[i].radius, x[7 + (i - 1) * 4], self.seq[i].mu_self)
            # s/c propagation before the DSM
            r, v = propagate_lagrangian(
                r_P[i], v_out, x[9 + (i - 1) * 4] * T[i] * DAY2SEC, self.common_mu)
            # Lambert arc to reach Earth during (1-nu2)*T2 (second segment)
            dt = (1 - x[9 + (i - 1) * 4]) * T[i] * DAY2SEC
            l = lambert_problem(r, r_P[i + 1], dt,
                                self.common_mu, False, False)
            v_end_l = l.get_v2()[0]
            v_beg_l = l.get_v1()[0]
            # DSM occuring at time nu2*T2
            DV[i] = norm([a - b for a, b in zip(v_beg_l, v)])

        # Last Delta-v
        if self.__add_vinf_arr:
            DV[-1] = norm([a - b for a, b in zip(v_end_l, v_P[-1])])

        if self.__add_vinf_dep:
            DV[0] += x[3]

        if self._obj_dim == 1:
            return (sum(DV),)
        else:
            return (sum(DV), sum(T))
def get_orbit(planet, day):
    planet = pk.planet.jpl_lp(planet)
    epoch_ = epoch(day)

    T = planet.compute_period(epoch_) * SEC2DAY
    N = int(round(T))
    when = np.linspace(0, T, N)

    x = np.array([0.0] * N)
    y = np.array([0.0] * N)
    z = np.array([0.0] * N)

    for i, day in enumerate(when):
        r, v = planet.eph(epoch(epoch_.mjd2000 + day))
        x[i] = r[0] / AU
        y[i] = r[1] / AU
        z[i] = r[2] / AU

    return x, y, z
예제 #9
0
    def __init__(self,
                 seq=[jpl_lp('earth'),
                      jpl_lp('venus'),
                      jpl_lp('earth')],
                 t0=[epoch(0), epoch(1000)],
                 tof=[1.0, 5.0],
                 vinf=[0.5, 2.5],
                 add_vinf_dep=False,
                 add_vinf_arr=True,
                 multi_objective=False):
        """
        pykep.trajopt.mga_1dsm(seq = [jpl_lp('earth'), jpl_lp('venus'), jpl_lp('earth')], t0 = [epoch(0),epoch(1000)], tof = [1.0,5.0], vinf = [0.5, 2.5], multi_objective = False, add_vinf_dep = False, add_vinf_arr=True)

        - seq: list of pykep planets defining the encounter sequence (including the starting launch)
        - t0: list of two epochs defining the launch window
        - tof: list of two floats defining the minimum and maximum allowed mission lenght (days)
        - vinf: list of two floats defining the minimum and maximum allowed initial hyperbolic velocity (at launch), in km/sec
        - multi_objective: when True constructs a multiobjective problem (dv, T)
        - add_vinf_dep: when True the computed Dv includes the initial hyperbolic velocity (at launch)
        - add_vinf_arr: when True the computed Dv includes the final hyperbolic velocity (at the last planet)
        """

        # Sanity checks ...... all planets need to have the same
        # mu_central_body
        if ([r.mu_central_body
             for r in seq].count(seq[0].mu_central_body) != len(seq)):
            raise ValueError(
                'All planets in the sequence need to have exactly the same mu_central_body'
            )
        self.__add_vinf_dep = add_vinf_dep
        self.__add_vinf_arr = add_vinf_arr
        self.__n_legs = len(seq) - 1
        self._t0 = t0
        self._tof = tof
        self._vinf = vinf
        self._obj_dim = multi_objective + 1

        # We then define all planets in the sequence  and the common central
        # body gravity as data members
        self.seq = seq
        self.common_mu = seq[0].mu_central_body
예제 #10
0
    def __init__(self,
                 seq=[jpl_lp('earth'), jpl_lp('venus'), jpl_lp('earth')],
                 t0=[epoch(0), epoch(1000)],
                 tof=[1.0, 5.0],
                 vinf=[0.5, 2.5],
                 add_vinf_dep=False,
                 add_vinf_arr=True,
                 multi_objective=False):
        """
        pykep.trajopt.mga_1dsm(seq = [jpl_lp('earth'), jpl_lp('venus'), jpl_lp('earth')], t0 = [epoch(0),epoch(1000)], tof = [1.0,5.0], vinf = [0.5, 2.5], multi_objective = False, add_vinf_dep = False, add_vinf_arr=True)

        - seq: list of pykep planets defining the encounter sequence (including the starting launch)
        - t0: list of two epochs defining the launch window
        - tof: list of two floats defining the minimum and maximum allowed mission lenght (days)
        - vinf: list of two floats defining the minimum and maximum allowed initial hyperbolic velocity (at launch), in km/sec
        - multi_objective: when True constructs a multiobjective problem (dv, T)
        - add_vinf_dep: when True the computed Dv includes the initial hyperbolic velocity (at launch)
        - add_vinf_arr: when True the computed Dv includes the final hyperbolic velocity (at the last planet)
        """

        # Sanity checks ...... all planets need to have the same
        # mu_central_body
        if ([r.mu_central_body for r in seq].count(seq[0].mu_central_body) != len(seq)):
            raise ValueError(
                'All planets in the sequence need to have exactly the same mu_central_body')
        self.__add_vinf_dep = add_vinf_dep
        self.__add_vinf_arr = add_vinf_arr
        self.__n_legs = len(seq) - 1
        self._t0 = t0
        self._tof = tof
        self._vinf = vinf
        self._obj_dim = multi_objective + 1

        # We then define all planets in the sequence  and the common central
        # body gravity as data members
        self.seq = seq
        self.common_mu = seq[0].mu_central_body
예제 #11
0
    def __init__(self,
                 planet,
                 rvt_in,
                 rvt_pl,
                 resonances=[[1, 1], [5, 4], [4, 3], [3, 2], [5, 3]]):
        """
        Args:
            - planet (``planet``): resonance planet. 
            - rvt_in: (``rvt``): incoming orbit.
            - rvt_pl: (``rvt``): planet orbit.
            - resonances (``list`` of ``int``): resonance options. 
        """
        assert rvt_in._t == rvt_pl._t  # timing must be consistent

        self._planet = planet
        self._rvt_in = rvt_in
        self._rvt_pl = rvt_pl
        self._time = rvt_in._t
        self._resonances = resonances
        self._period = planet.compute_period(epoch(self._time * SEC2DAY))
        self._mu = planet.mu_self
        self._timing_error = -1
        self._rvt_out = None
        self._resonance = None
예제 #12
0
    def __init__(self,
                 start=jpl_lp('earth'),
                 target=jpl_lp('venus'),
                 N_max=3,
                 tof=[20., 400.],
                 vinf=[0., 4.],
                 phase_free=True,
                 multi_objective=False,
                 t0=None
                 ):
        """
        prob = pykep.trajopt.pl2pl_N_impulses(start=jpl_lp('earth'), target=jpl_lp('venus'), N_max=3, tof=[20., 400.], vinf=[0., 4.], phase_free=True, multi_objective=False, t0=None)

        Args: 
            - start (``pykep.planet``): the starting planet
            - target (``pykep.planet``): the target planet
            - N_max (``int``): maximum number of impulses
            - tof (``list``): the box bounds [lower,upper] for the time of flight (days)
            - vinf (``list``): the box bounds [lower,upper] for each DV magnitude (km/sec)
            - phase_free (``bool``): when True, no randezvous condition are enforced and start and arrival anomalies will be free
            - multi_objective (``bool``):  when True, a multi-objective problem is constructed with DV and time of flight as objectives
            - t0 (``list``):  the box bounds on the launch window containing two pykep.epoch. This is not needed if phase_free is True.
        """

        # Sanity checks
        # 1) all planets need to have the same mu_central_body
        if (start.mu_central_body != target.mu_central_body):
            raise ValueError(
                'Starting and ending pykep.planet must have the same mu_central_body')
        # 2) Number of impulses must be at least 2
        if N_max < 2:
            raise ValueError('Number of impulses N is less than 2')
        # 3) If phase_free is True, t0 does not make sense
        if (t0 is None and not phase_free):
            t0 = [epoch(0), epoch(1000)]
        if (t0 is not None and phase_free):
            raise ValueError('When phase_free is True no t0 can be specified')
        if (type(t0[0]) != type(epoch(0))):
            t0[0] = epoch(t0[0])
        if (type(t0[1]) != type(epoch(0))):
            t0[1] = epoch(t0[1])

        self.obj_dim = multi_objective + 1
        # We then define all class data members
        self.start = start
        self.target = target
        self.N_max = N_max
        self.phase_free = phase_free
        self.multi_objective = multi_objective
        self.vinf = [s * 1000 for s in vinf]

        self.__common_mu = start.mu_central_body

        # And we compute the bounds
        if phase_free:
            self._lb = [0, tof[0]] + [1e-3, 0.0, 0.0,
                                      vinf[0] * 1000] * (N_max - 2) + [1e-3] + [0]
            self._ub = [2 * start.compute_period(epoch(0)) * SEC2DAY, tof[1]] + [1.0-1e-3, 1.0, 1.0, vinf[
                1] * 1000] * (N_max - 2) + [1.0-1e-3] + [2 * target.compute_period(epoch(0)) * SEC2DAY]
        else:
            self._lb = [t0[0].mjd2000, tof[0]] + \
                [1e-3, 0.0, 0.0, vinf[0] * 1000] * (N_max - 2) + [1e-3]
            self._ub = [t0[1].mjd2000, tof[1]] + \
                [1.0-1e-3, 1.0, 1.0, vinf[1] * 1000] * (N_max - 2) + [1.0-1e-3]
예제 #13
0
    def ic_from_mga_1dsm(self, x):
        """
        x_lt = prob.ic_from_mga_1dsm(x_mga)

        - x_mga: compatible trajectory as encoded by an mga_1dsm problem

        Returns an initial guess for the low-thrust trajectory, converting the mga_1dsm solution x_dsm. The user
        is responsible that x_mga makes sense (i.e. it is a viable mga_1dsm representation). The conversion is done by importing in the
        low-thrust encoding a) the launch date b) all the legs durations, c) the in and out relative velocities at each planet.
        All throttles are put to zero.

        Example::

          x_lt= prob.ic_from_mga_1dsm(x_mga)
        """
        from math import pi, cos, sin, acos
        from scipy.linalg import norm
        from pykep import propagate_lagrangian, lambert_problem, DAY2SEC, fb_prop

        retval = list([0.0] * self.dimension)
        # 1 -  we 'decode' the chromosome recording the various times of flight
        # (days) in the list T
        T = list([0] * (self.__n_legs))

        for i in range(len(T)):
            T[i] = log(x[2 + 4 * i])
        total = sum(T)
        T = [x[1] * time / total for time in T]

        retval[0] = x[0]
        for i in range(self.__n_legs):
            retval[1 + 8 * i] = T[i]
            retval[2 + 8 * i] = self.__sc.mass

        # 2 - We compute the epochs and ephemerides of the planetary encounters
        t_P = list([None] * (self.__n_legs + 1))
        r_P = list([None] * (self.__n_legs + 1))
        v_P = list([None] * (self.__n_legs + 1))
        DV = list([None] * (self.__n_legs + 1))

        for i, planet in enumerate(self.seq):
            t_P[i] = epoch(x[0] + sum(T[0:i]))
            r_P[i], v_P[i] = self.seq[i].eph(t_P[i])

        # 3 - We start with the first leg
        theta = 2 * pi * x[1]
        phi = acos(2 * x[2] - 1) - pi / 2

        Vinfx = x[3] * cos(phi) * cos(theta)
        Vinfy = x[3] * cos(phi) * sin(theta)
        Vinfz = x[3] * sin(phi)

        retval[3:6] = [Vinfx, Vinfy, Vinfz]

        v0 = [a + b for a, b in zip(v_P[0], [Vinfx, Vinfy, Vinfz])]
        r, v = propagate_lagrangian(r_P[0], v0, x[4] * T[0] * DAY2SEC, MU_SUN)

        # Lambert arc to reach seq[1]
        dt = (1 - x[4]) * T[0] * DAY2SEC
        l = lambert_problem(r, r_P[1], dt, MU_SUN)
        v_end_l = l.get_v2()[0]
        v_beg_l = l.get_v1()[0]

        retval[6:9] = [a - b for a, b in zip(v_end_l, v_P[1])]

        # 4 - And we proceed with each successive leg
        for i in range(1, self.__n_legs):
            # Fly-by
            v_out = fb_prop(v_end_l, v_P[i], x[
                            7 + (i - 1) * 4] * self.seq[i].radius, x[6 + (i - 1) * 4], self.seq[i].mu_self)
            retval[3 + i * 8:6 + i * 8] = [a -
                                           b for a, b in zip(v_out, v_P[i])]
            # s/c propagation before the DSM
            r, v = propagate_lagrangian(
                r_P[i], v_out, x[8 + (i - 1) * 4] * T[i] * DAY2SEC, MU_SUN)
            # Lambert arc to reach Earth during (1-nu2)*T2 (second segment)
            dt = (1 - x[8 + (i - 1) * 4]) * T[i] * DAY2SEC
            l = lambert_problem(r, r_P[i + 1], dt, MU_SUN)
            v_end_l = l.get_v2()[0]
            v_beg_l = l.get_v1()[0]
            # DSM occuring at time nu2*T2
            DV[i] = norm([a - b for a, b in zip(v_beg_l, v)])
            retval[6 + i * 8:9 + i * 8] = [a -
                                           b for a, b in zip(v_end_l, v_P[i + 1])]
        return retval
예제 #14
0
    def plot(self, x, axes=None):
        """
        ax = prob.plot(x, ax=None)

        - x: encoded trajectory
        - ax: matplotlib axis where to plot. If None figure and axis will be created
        - [out] ax: matplotlib axis where to plot

        Plots the trajectory represented by a decision vector x on the 3d axis ax

        Example::

          ax = prob.plot(x)
        """
        import matplotlib as mpl
        from mpl_toolkits.mplot3d import Axes3D
        import matplotlib.pyplot as plt
        from pykep.orbit_plots import plot_sf_leg, plot_planet

        # Creating the axis if necessary
        if axes is None:
            mpl.rcParams['legend.fontsize'] = 10
            fig = plt.figure()
            ax = fig.gca(projection='3d')
        else:
            ax = axes

        # Plotting the Sun ........
        ax.scatter([0], [0], [0], color=['y'])

        # We compute the epochs and ephemerides of the planetary encounters
        t_P = list([None] * (self._n_legs + 1))
        r_P = list([None] * (self._n_legs + 1))
        v_P = list([None] * (self._n_legs + 1))
        for i in range(len(self._seq)):
            t_P[i] = epoch(x[0] + sum(x[1:i * 8:8]))
            r_P[i], v_P[i] = self._seq[i].eph(t_P[i])
            plot_planet(self._seq[i],
                        t0=t_P[i],
                        units=AU,
                        legend=False,
                        color=(0.7, 0.7, 0.7),
                        s=30,
                        axes=ax)

        # We assemble the constraints.
        # 1 - Mismatch Constraints
        for i in range(self._n_legs):
            # Departure velocity of the spacecraft in the heliocentric frame
            v0 = [a + b for a, b in zip(v_P[i], x[3 + 8 * i:6 + 8 * i])]
            if i == 0:
                m0 = self._mass[1]
            else:
                m0 = x[2 + 8 * (i - 1)]
            x0 = sc_state(r_P[i], v0, m0)
            vf = [a + b for a, b in zip(v_P[i + 1], x[6 + 8 * i:9 + 8 * i])]
            xf = sc_state(r_P[i + 1], vf, x[2 + 8 * i])
            idx_start = 1 + 8 * self._n_legs + sum(self._n_seg[:i]) * 3
            idx_end = 1 + 8 * self._n_legs + sum(self._n_seg[:i + 1]) * 3
            self._leg.set(t_P[i], x0, x[idx_start:idx_end], t_P[i + 1], xf)
            plot_sf_leg(self._leg, units=AU, N=10, axes=ax, legend=False)

        return axes
예제 #15
0
    def plot(self, x, axes=None):
        """
        ax = prob.plot_trajectory(x, axes=None)

        - x: encoded trajectory
        - axes: matplotlib axis where to plot. If None figure and axis will be created
        - [out] ax: matplotlib axis where to plot

        Plots the trajectory represented by a decision vector x on the 3d axis ax

        Example::

          ax = prob.plot(x)
        """
        import matplotlib as mpl
        from mpl_toolkits.mplot3d import Axes3D
        import matplotlib.pyplot as plt
        from pykep.orbit_plots import plot_planet, plot_lambert, plot_kepler

        if axes is None:
            mpl.rcParams['legend.fontsize'] = 10
            fig = plt.figure()
            axes = fig.gca(projection='3d')

        axes.scatter(0, 0, 0, color='y')

        # 1 -  we 'decode' the chromosome recording the various deep space
        # manouvres timing (days) in the list T
        T = list([0] * (self.N_max - 1))

        for i in range(len(T)):
            T[i] = log(x[2 + 4 * i])
        total = sum(T)
        T = [x[1] * time / total for time in T]

        # 2 - We compute the starting and ending position
        r_start, v_start = self.start.eph(epoch(x[0]))
        if self.phase_free:
            r_target, v_target = self.target.eph(epoch(x[-1]))
        else:
            r_target, v_target = self.target.eph(epoch(x[0] + x[1]))
        plot_planet(self.start, t0=epoch(x[0]), color=(
            0.8, 0.6, 0.8), legend=True, units=AU, ax=axes, s=0)
        plot_planet(self.target, t0=epoch(
            x[0] + x[1]), color=(0.8, 0.6, 0.8), legend=True, units=AU, ax=axes, s=0)

        DV_list = x[5::4]
        maxDV = max(DV_list)
        DV_list = [s / maxDV * 30 for s in DV_list]
        colors = ['b', 'r'] * (len(DV_list) + 1)

        # 3 - We loop across inner impulses
        rsc = r_start
        vsc = v_start
        for i, time in enumerate(T[:-1]):
            theta = 2 * pi * x[3 + 4 * i]
            phi = acos(2 * x[4 + 4 * i] - 1) - pi / 2

            Vinfx = x[5 + 4 * i] * cos(phi) * cos(theta)
            Vinfy = x[5 + 4 * i] * cos(phi) * sin(theta)
            Vinfz = x[5 + 4 * i] * sin(phi)

            # We apply the (i+1)-th impulse
            vsc = [a + b for a, b in zip(vsc, [Vinfx, Vinfy, Vinfz])]
            axes.scatter(rsc[0] / AU, rsc[1] / AU, rsc[2] /
                         AU, color='k', s=DV_list[i])
            plot_kepler(rsc, vsc, T[i] * DAY2SEC, self.__common_mu,
                        N=200, color=colors[i], legend=False, units=AU, ax=axes)
            rsc, vsc = propagate_lagrangian(
                rsc, vsc, T[i] * DAY2SEC, self.__common_mu)

        cw = (ic2par(rsc, vsc, self.start.mu_central_body)[2] > pi / 2)
        # We now compute the remaining two final impulses
        # Lambert arc to reach seq[1]
        dt = T[-1] * DAY2SEC
        l = lambert_problem(rsc, r_target, dt, self.__common_mu, cw, False)
        plot_lambert(l, sol=0, color=colors[
                     i + 1], legend=False, units=AU, ax=axes, N=200)
        v_end_l = l.get_v2()[0]
        v_beg_l = l.get_v1()[0]
        DV1 = norm([a - b for a, b in zip(v_beg_l, vsc)])
        DV2 = norm([a - b for a, b in zip(v_end_l, v_target)])

        axes.scatter(rsc[0] / AU, rsc[1] / AU, rsc[2] / AU,
                     color='k', s=min(DV1 / maxDV * 30, 40))
        axes.scatter(r_target[0] / AU, r_target[1] / AU,
                     r_target[2] / AU, color='k', s=min(DV2 / maxDV * 30, 40))

        return axes
예제 #16
0
    def _fitness_impl(self, decoded_x, logging=False, plotting=False, ax=None):
        """ Computation of the objective function. """

        saturn_distance_violated = 0

        # decode x
        t0, u, v, dep_vinf, etas, T, betas, rps = decoded_x

        # convert incoming velocity vector
        theta, phi = 2.0 * pi * u, acos(2.0 * v - 1.0) - pi / 2.0
        Vinfx = dep_vinf * cos(phi) * cos(theta)
        Vinfy = dep_vinf * cos(phi) * sin(theta)
        Vinfz = dep_vinf * sin(phi)

        # epochs and ephemerides of the planetary encounters
        t_P = list([None] * (self._n_legs + 1))
        r_P = list([None] * (self._n_legs + 1))
        v_P = list([None] * (self._n_legs + 1))
        lamberts = list([None] * (self._n_legs))
        v_outs = list([None] * (self._n_legs))
        DV = list([0.0] * (self._n_legs + 1))

        for i, planet in enumerate(self.seq):
            t_P[i] = epoch(t0 + sum(T[0:i]))
            r_P[i], v_P[i] = self.seq[i].eph(t_P[i])

        # first leg
        v_outs[0] = [Vinfx, Vinfy, Vinfz]  # bug fixed

        # check first leg up to DSM
        saturn_distance_violated += self.check_distance(
            r_P[0], v_outs[0], t0, etas[0] * T[0])
        r, v = propagate_lagrangian(r_P[0], v_outs[0],
                                    etas[0] * T[0] * DAY2SEC, self.common_mu)

        # Lambert arc to reach seq[1]
        dt = (1.0 - etas[0]) * T[0] * DAY2SEC
        lamberts[0] = lambert_problem(r, r_P[1], dt, self.common_mu, self.cw,
                                      0)
        v_end_l = lamberts[0].get_v2()[0]
        v_beg_l = lamberts[0].get_v1()[0]

        # First DSM occuring at time eta0*T0
        DV[0] = norm([a - b for a, b in zip(v_beg_l, v)])
        # checking first leg after DSM
        saturn_distance_violated += self.check_distance(
            r, v_beg_l, etas[0] * T[0], T[0])

        # successive legs
        for i in range(1, self._n_legs):
            # Fly-by
            v_outs[i] = fb_prop(v_end_l, v_P[i],
                                rps[i - 1] * self.seq[i].radius, betas[i - 1],
                                self.seq[i].mu_self)
            # checking next leg up to DSM
            saturn_distance_violated += self.check_distance(
                r_P[i], v_outs[i], T[i - 1], etas[i] * T[i])
            # s/c propagation before the DSM
            r, v = propagate_lagrangian(r_P[i], v_outs[i],
                                        etas[i] * T[i] * DAY2SEC,
                                        self.common_mu)
            # Lambert arc to reach next body
            dt = (1 - etas[i]) * T[i] * DAY2SEC
            lamberts[i] = lambert_problem(r, r_P[i + 1], dt, self.common_mu,
                                          self.cw, 0)
            v_end_l = lamberts[i].get_v2()[0]
            v_beg_l = lamberts[i].get_v1()[0]
            # DSM occuring at time eta_i*T_i
            DV[i] = norm([a - b for a, b in zip(v_beg_l, v)])
            # checking next leg after DSM
            saturn_distance_violated += self.check_distance(
                r, v_beg_l, etas[i] * T[i], T[i])

        # single dv penalty for now
        if saturn_distance_violated > 0:
            DV[-1] += DV_PENALTY

        arr_vinf = norm([a - b for a, b in zip(v_end_l, v_P[-1])])

        # last Delta-v
        if self._add_vinf_arr:
            DV[-1] = arr_vinf

        if self._add_vinf_dep:
            DV[0] += dep_vinf

        # pretty printing
        if logging:
            print("First leg: {} to {}".format(self.seq[0].name,
                                               self.seq[1].name))
            print("Departure: {0} ({1:0.6f} mjd2000)".format(
                t_P[0], t_P[0].mjd2000))
            print("Duration: {0:0.6f}d".format(T[0]))
            print("VINF: {0:0.3f}m/s".format(dep_vinf))
            print("DSM after {0:0.6f}d".format(etas[0] * T[0]))
            print("DSM magnitude: {0:0.6f}m/s".format(DV[0]))

            for i in range(1, self._n_legs):
                print("\nleg {}: {} to {}".format(i + 1, self.seq[i].name,
                                                  self.seq[i + 1].name))
                print("Duration: {0:0.6f}d".format(T[i]))
                print("Fly-by epoch: {0} ({1:0.6f} mjd2000)".format(
                    t_P[i], t_P[i].mjd2000))
                print("Fly-by radius: {0:0.6f} planetary radii".format(rps[i -
                                                                           1]))
                print("DSM after {0:0.6f}d".format(etas[i] * T[i]))
                print("DSM magnitude: {0:0.6f}m/s".format(DV[i]))

            print("\nArrival at {}".format(self.seq[-1].name))
            print("Arrival epoch: {0} ({1:0.6f} mjd2000)".format(
                t_P[-1], t_P[-1].mjd2000))
            print("Arrival Vinf: {0:0.3f}m/s".format(arr_vinf))
            print("Total mission time: {0:0.6f}d ({1:0.3f} years)".format(
                sum(T),
                sum(T) / 365.25))

        # plotting
        if plotting:
            ax.scatter(0, 0, 0, color='chocolate')
            for i, planet in enumerate(self.seq):
                plot_planet(planet,
                            t0=t_P[i],
                            color=pl2c[planet.name],
                            legend=True,
                            units=AU,
                            ax=ax)
            for i in range(0, self._n_legs):
                plot_kepler(r_P[i],
                            v_outs[i],
                            etas[i] * T[i] * DAY2SEC,
                            self.common_mu,
                            N=100,
                            color='b',
                            legend=False,
                            units=AU,
                            ax=ax)
            for l in lamberts:
                plot_lambert(l,
                             sol=0,
                             color='r',
                             legend=False,
                             units=AU,
                             N=1000,
                             ax=ax)

        # returning building blocks for objectives
        return (DV, T, arr_vinf, lamberts)
예제 #17
0
# specific impulse
ISP = 308

# constants related to mass
M_WET = 5000  # kg
M_DRY = 3000  # kg
DV_BUDGET = ISP * G0 * log(M_WET / M_DRY)

# additive constant for violation of constraints
DV_PENALTY = 200000

# constants related to time
T_START, T_END = 20000, 24000  # MJD2000

# 2020-01-January, 00:00:00
REF_EPOCH = epoch(2458849.500000000, julian_date_type='jd')

# make the bodies
enceladus = keplerian(REF_EPOCH, ENCELADUS_ELEM, MU_SATURN, MU_ENCELADUS,
                      RADIUS_ENCELADUS, RADIUS_ENCELADUS * 1.1, 'enceladus')
tethys = keplerian(REF_EPOCH, TETHYS_ELEM, MU_SATURN, MU_TETHYS, RADIUS_TETHYS,
                   RADIUS_TETHYS * 1.1, 'tethys')
dione = keplerian(REF_EPOCH, DIONE_ELEM, MU_SATURN, MU_DIONE, RADIUS_DIONE,
                  RADIUS_DIONE * 1.1, 'dione')
rhea = keplerian(REF_EPOCH, RHEA_ELEM, MU_SATURN, MU_RHEA, RADIUS_RHEA,
                 RADIUS_RHEA * 1.1, 'rhea')
titan = keplerian(REF_EPOCH, TITAN_ELEM, MU_SATURN, MU_TITAN, RADIUS_TITAN,
                  RADIUS_TITAN * 1.1, 'titan')

# different colors for plotting
pl2c = {
예제 #18
0
    def plot(self, x, ax=None):
        """
        ax = prob.plot(x, ax=None)

        - x: encoded trajectory
        - ax: matplotlib axis where to plot. If None figure and axis will be created
        - [out] ax: matplotlib axis where to plot

        Plots the trajectory represented by a decision vector x on the 3d axis ax

        Example::

          ax = prob.plot(x)
        """
        import matplotlib as mpl
        from mpl_toolkits.mplot3d import Axes3D
        import matplotlib.pyplot as plt
        from pykep import epoch, AU
        from pykep.sims_flanagan import sc_state
        from pykep.orbit_plots import plot_planet, plot_sf_leg

        # Creating the axis if necessary
        if ax is None:
            mpl.rcParams['legend.fontsize'] = 10
            fig = plt.figure()
            axis = fig.gca(projection='3d')
        else:
            axis = ax

        # Plotting the Sun ........
        axis.scatter([0], [0], [0], color='y')

        # Plotting the legs .......
        # 1 - We decode the chromosome extracting the time of flights
        T = list([0] * (self.__n_legs))
        for i in range(self.__n_legs):
            T[i] = x[1 + i * 8]

        # 2 - We compute the epochs and ephemerides of the planetary encounters
        t_P = list([None] * (self.__n_legs + 1))
        r_P = list([None] * (self.__n_legs + 1))
        v_P = list([None] * (self.__n_legs + 1))

        for i, planet in enumerate(self.seq):
            t_P[i] = epoch(x[0] + sum(T[0:i]))
            r_P[i], v_P[i] = self.seq[i].eph(t_P[i])

        # 3 - We iterate through legs to compute mismatches and throttles
        # constraints
        ceq = list()
        cineq = list()
        m0 = self.__sc.mass
        for i in range(self.__n_legs):
            # First Leg
            v = [a + b for a, b in zip(v_P[i], x[(3 + i * 8):(6 + i * 8)])]
            x0 = sc_state(r_P[i], v, m0)
            v = [
                a + b for a, b in zip(v_P[i + 1], x[(6 + i * 8):(11 + i * 8)])
            ]
            xe = sc_state(r_P[i + 1], v, x[2 + i * 8])
            throttles = x[(1 + 8 * self.__n_legs + 3 * sum(self.__n_seg[:i])):(
                1 + 8 * self.__n_legs + 3 * sum(self.__n_seg[:i]) +
                3 * self.__n_seg[i])]
            self.__leg.set(t_P[i], x0, throttles, t_P[i + 1], xe)
            # update mass!
            m0 = x[2 + 8 * i]
            plot_sf_leg(self.__leg, units=AU, N=10, ax=axis)

        # Plotting planets
        for i, planet in enumerate(self.seq):
            plot_planet(planet,
                        t_P[i],
                        units=AU,
                        legend=True,
                        color=(0.7, 0.7, 1),
                        ax=axis)

        plt.show()
        return axis
예제 #19
0
 def get_patching_conditions(self, x):
     """ returns the final epoch of the trajectory, the last ending point and the outgoing velocity """
     # DV, T, arr_vinf, lamberts = self._fitness_impl(x)
     DV, T, arr_vinf, lamberts = self.decode_state_eval_fitness(x)
     v = lamberts[-1].get_v2()[0]
     return (epoch(x[0] + sum(T)), self.seq[-1], v)
예제 #20
0
    def fitness(self, x):
        # The final mass is the fitness
        objfun = [-x[2 + 8 * (self._n_legs - 1)]]
        eq_c = []
        ineq_c = []
        if self._multiobjective:
            objfun = objfun + [sum(x[1:8 * self._n_legs:8])]
        # We compute the epochs and ephemerides of the planetary encounters
        t_P = list([None] * (self._n_legs + 1))
        r_P = list([None] * (self._n_legs + 1))
        v_P = list([None] * (self._n_legs + 1))
        for i in range(len(self._seq)):
            t_P[i] = epoch(x[0] + sum(x[1:i * 8:8]))
            r_P[i], v_P[i] = self._seq[i].eph(t_P[i])
        # We assemble the constraints.
        # 1 - Mismatch Constraints
        for i in range(self._n_legs):
            # Departure velocity of the spacecraft in the heliocentric frame
            v0 = [a + b for a, b in zip(v_P[i], x[3 + 8 * i:6 + 8 * i])]
            if i == 0:
                m0 = self._mass[1]
            else:
                m0 = x[2 + 8 * (i - 1)]
            x0 = sc_state(r_P[i], v0, m0)
            vf = [a + b for a, b in zip(v_P[i + 1], x[6 + 8 * i:9 + 8 * i])]
            xf = sc_state(r_P[i + 1], vf, x[2 + 8 * i])
            idx_start = 1 + 8 * self._n_legs + sum(self._n_seg[:i]) * 3
            idx_end = 1 + 8 * self._n_legs + sum(self._n_seg[:i + 1]) * 3
            self._leg.set(t_P[i], x0, x[idx_start:idx_end], t_P[i + 1], xf)
            mismatch = list(self._leg.mismatch_constraints())
            # Making the mismatch non dimensional (assumes an heliocentric interplanetary trajectory)
            mismatch[0] /= AU
            mismatch[1] /= AU
            mismatch[2] /= AU
            mismatch[3] /= EARTH_VELOCITY
            mismatch[4] /= EARTH_VELOCITY
            mismatch[5] /= EARTH_VELOCITY
            mismatch[6] /= self._mass[1]
            eq_c = eq_c + mismatch
            ineq_c = ineq_c + list(self._leg.throttles_constraints())

        # 2 - Fly-by constraints
        for i in range(self._n_legs - 1):
            DV_eq, alpha_ineq = fb_con(x[6 + i * 8:9 + i * 8],
                                       x[11 + i * 8:14 + i * 8],
                                       self._seq[i + 1])
            eq_c = eq_c + [DV_eq / (EARTH_VELOCITY * EARTH_VELOCITY)]
            ineq_c = ineq_c + [alpha_ineq]

        # 3 - Departure and arrival Vinf
        # departure
        v_dep_con = (x[3] * x[3] + x[4] * x[4] + x[5] * x[5] - self._vinf_dep *
                     self._vinf_dep) / (EARTH_VELOCITY * EARTH_VELOCITY)
        # arrival
        n_fb = self._n_legs - 1
        v_arr_con = (x[6 + n_fb * 8] * x[6 + n_fb * 8] + x[7 + n_fb * 8] *
                     x[7 + n_fb * 8] + x[8 + n_fb * 8] * x[8 + n_fb * 8] -
                     self._vinf_arr * self._vinf_arr) / (EARTH_VELOCITY *
                                                         EARTH_VELOCITY)
        ineq_c = ineq_c + [v_dep_con, v_arr_con]

        return objfun + eq_c + ineq_c
예제 #21
0
    def plot(self, x, axes=None):
        """
        ax = prob.plot_trajectory(x, axes=None)

        - x: encoded trajectory
        - axes: matplotlib axis where to plot. If None figure and axis will be created
        - [out] ax: matplotlib axis where to plot

        Plots the trajectory represented by a decision vector x on the 3d axis ax

        Example::

          ax = prob.plot(x)
        """
        import matplotlib as mpl
        from mpl_toolkits.mplot3d import Axes3D
        import matplotlib.pyplot as plt
        from pykep.orbit_plots import plot_planet, plot_lambert, plot_kepler

        if axes is None:
            mpl.rcParams['legend.fontsize'] = 10
            fig = plt.figure()
            axes = fig.gca(projection='3d')

        axes.scatter(0, 0, 0, color='y')

        # 1 -  we 'decode' the chromosome recording the various deep space
        # manouvres timing (days) in the list T
        T = list([0] * (self.N_max - 1))

        for i in range(len(T)):
            T[i] = log(x[2 + 4 * i])
        total = sum(T)
        T = [x[1] * time / total for time in T]

        # 2 - We compute the starting and ending position
        r_start, v_start = self.start.eph(epoch(x[0]))
        if self.phase_free:
            r_target, v_target = self.target.eph(epoch(x[-1]))
        else:
            r_target, v_target = self.target.eph(epoch(x[0] + x[1]))
        plot_planet(self.start,
                    t0=epoch(x[0]),
                    color=(0.8, 0.6, 0.8),
                    legend=True,
                    units=AU,
                    ax=axes,
                    s=0)
        plot_planet(self.target,
                    t0=epoch(x[0] + x[1]),
                    color=(0.8, 0.6, 0.8),
                    legend=True,
                    units=AU,
                    ax=axes,
                    s=0)

        DV_list = x[5::4]
        maxDV = max(DV_list)
        DV_list = [s / maxDV * 30 for s in DV_list]
        colors = ['b', 'r'] * (len(DV_list) + 1)

        # 3 - We loop across inner impulses
        rsc = r_start
        vsc = v_start
        for i, time in enumerate(T[:-1]):
            theta = 2 * pi * x[3 + 4 * i]
            phi = acos(2 * x[4 + 4 * i] - 1) - pi / 2

            Vinfx = x[5 + 4 * i] * cos(phi) * cos(theta)
            Vinfy = x[5 + 4 * i] * cos(phi) * sin(theta)
            Vinfz = x[5 + 4 * i] * sin(phi)

            # We apply the (i+1)-th impulse
            vsc = [a + b for a, b in zip(vsc, [Vinfx, Vinfy, Vinfz])]
            axes.scatter(rsc[0] / AU,
                         rsc[1] / AU,
                         rsc[2] / AU,
                         color='k',
                         s=DV_list[i])
            plot_kepler(rsc,
                        vsc,
                        T[i] * DAY2SEC,
                        self.__common_mu,
                        N=200,
                        color=colors[i],
                        legend=False,
                        units=AU,
                        ax=axes)
            rsc, vsc = propagate_lagrangian(rsc, vsc, T[i] * DAY2SEC,
                                            self.__common_mu)

        cw = (ic2par(rsc, vsc, self.start.mu_central_body)[2] > pi / 2)
        # We now compute the remaining two final impulses
        # Lambert arc to reach seq[1]
        dt = T[-1] * DAY2SEC
        l = lambert_problem(rsc, r_target, dt, self.__common_mu, cw, False)
        plot_lambert(l,
                     sol=0,
                     color=colors[i + 1],
                     legend=False,
                     units=AU,
                     ax=axes,
                     N=200)
        v_end_l = l.get_v2()[0]
        v_beg_l = l.get_v1()[0]
        DV1 = norm([a - b for a, b in zip(v_beg_l, vsc)])
        DV2 = norm([a - b for a, b in zip(v_end_l, v_target)])

        axes.scatter(rsc[0] / AU,
                     rsc[1] / AU,
                     rsc[2] / AU,
                     color='k',
                     s=min(DV1 / maxDV * 30, 40))
        axes.scatter(r_target[0] / AU,
                     r_target[1] / AU,
                     r_target[2] / AU,
                     color='k',
                     s=min(DV2 / maxDV * 30, 40))

        return axes
예제 #22
0
    def fitness(self, x):
        # 1 -  we 'decode' the chromosome recording the various times of flight
        # (days) in the list T and the cartesian components of vinf
        T, Vinfx, Vinfy, Vinfz = self._decode_times_and_vinf(x)

        # 2 - We compute the epochs and ephemerides of the planetary encounters
        t_P = list([None] * (self.n_legs + 1))
        r_P = list([None] * (self.n_legs + 1))
        v_P = list([None] * (self.n_legs + 1))
        DV = list([0.0] * (self.n_legs + 1))
        for i in range(len(self._seq)):
            t_P[i] = epoch(x[0] + sum(T[0:i]))
            r_P[i], v_P[i] = self._seq[i].eph(t_P[i])

        # 3 - We start with the first leg
        v0 = [a + b for a, b in zip(v_P[0], [Vinfx, Vinfy, Vinfz])]
        r, v = propagate_lagrangian(r_P[0], v0, x[4] * T[0] * DAY2SEC,
                                    self.common_mu)

        # Lambert arc to reach seq[1]
        dt = (1 - x[4]) * T[0] * DAY2SEC
        l = lambert_problem(r,
                            r_P[1],
                            dt,
                            self.common_mu,
                            cw=False,
                            max_revs=0)
        v_end_l = l.get_v2()[0]
        v_beg_l = l.get_v1()[0]

        # First DSM occuring at time nu1*T1
        DV[0] = norm([a - b for a, b in zip(v_beg_l, v)])

        # 4 - And we proceed with each successive leg
        for i in range(1, self.n_legs):
            # Fly-by
            v_out = fb_prop(v_end_l, v_P[i],
                            x[7 + (i - 1) * 4] * self._seq[i].radius,
                            x[6 + (i - 1) * 4], self._seq[i].mu_self)
            # s/c propagation before the DSM
            r, v = propagate_lagrangian(r_P[i], v_out,
                                        x[8 + (i - 1) * 4] * T[i] * DAY2SEC,
                                        self.common_mu)
            # Lambert arc to reach Earth during (1-nu2)*T2 (second segment)
            dt = (1 - x[8 + (i - 1) * 4]) * T[i] * DAY2SEC
            l = lambert_problem(r,
                                r_P[i + 1],
                                dt,
                                self.common_mu,
                                cw=False,
                                max_revs=0)
            v_end_l = l.get_v2()[0]
            v_beg_l = l.get_v1()[0]
            # DSM occuring at time nu2*T2
            DV[i] = norm([a - b for a, b in zip(v_beg_l, v)])

        # Last Delta-v
        if self._add_vinf_arr:
            DV[-1] = norm([a - b for a, b in zip(v_end_l, v_P[-1])])
            if self._orbit_insertion:
                # In this case we compute the insertion DV as a single pericenter
                # burn
                DVper = np.sqrt(DV[-1] * DV[-1] +
                                2 * self._seq[-1].mu_self / self._rp_target)
                DVper2 = np.sqrt(2 * self._seq[-1].mu_self / self._rp_target -
                                 self._seq[-1].mu_self / self._rp_target *
                                 (1. - self._e_target))
                DV[-1] = np.abs(DVper - DVper2)

        if self._add_vinf_dep:
            DV[0] += x[3]

        if not self._multi_objective:
            return (sum(DV), )
        else:
            return (sum(DV), sum(T))
예제 #23
0
파일: _mga_1dsm.py 프로젝트: tniessen/pykep
    def _compute_dvs(self, x: List[float]) -> Tuple[
            List[float],  # DVs
            List[Any],  # Lambert legs
            List[float],  # T
            List[Tuple[List[float], List[float]]],  # ballistic legs
            List[float],  # epochs of ballistic legs
    ]:
        # 1 -  we 'decode' the chromosome recording the various times of flight
        # (days) in the list T and the cartesian components of vinf
        T, Vinfx, Vinfy, Vinfz = self._decode_times_and_vinf(x)

        # 2 - We compute the epochs and ephemerides of the planetary encounters
        t_P = list([None] * (self.n_legs + 1))
        r_P = list([None] * (self.n_legs + 1))
        v_P = list([None] * (self.n_legs + 1))
        DV = list([0.0] * (self.n_legs + 1))
        for i in range(len(self._seq)):
            t_P[i] = epoch(x[0] + sum(T[0:i]))
            r_P[i], v_P[i] = self._seq[i].eph(t_P[i])
        ballistic_legs: List[Tuple[List[float], List[float]]] = []
        ballistic_ep: List[float] = []
        lamberts = []

        # 3 - We start with the first leg
        v0 = [a + b for a, b in zip(v_P[0], [Vinfx, Vinfy, Vinfz])]
        ballistic_legs.append((r_P[0], v0))
        ballistic_ep.append(t_P[0].mjd2000)
        r, v = propagate_lagrangian(r_P[0], v0, x[4] * T[0] * DAY2SEC,
                                    self.common_mu)

        # Lambert arc to reach seq[1]
        dt = (1 - x[4]) * T[0] * DAY2SEC
        l = lambert_problem_multirev(
            v,
            lambert_problem(r,
                            r_P[1],
                            dt,
                            self.common_mu,
                            cw=False,
                            max_revs=self.max_revs))
        v_end_l = l.get_v2()[0]
        v_beg_l = l.get_v1()[0]
        lamberts.append(l)

        ballistic_legs.append((r, v_beg_l))
        ballistic_ep.append(t_P[0].mjd2000 + x[4] * T[0])

        # First DSM occuring at time nu1*T1
        DV[0] = norm([a - b for a, b in zip(v_beg_l, v)])

        # 4 - And we proceed with each successive leg
        for i in range(1, self.n_legs):
            # Fly-by
            v_out = fb_prop(v_end_l, v_P[i],
                            x[7 + (i - 1) * 4] * self._seq[i].radius,
                            x[6 + (i - 1) * 4], self._seq[i].mu_self)
            ballistic_legs.append((r_P[i], v_out))
            ballistic_ep.append(t_P[i].mjd2000)
            # s/c propagation before the DSM
            r, v = propagate_lagrangian(r_P[i], v_out,
                                        x[8 + (i - 1) * 4] * T[i] * DAY2SEC,
                                        self.common_mu)
            # Lambert arc to reach Earth during (1-nu2)*T2 (second segment)
            dt = (1 - x[8 + (i - 1) * 4]) * T[i] * DAY2SEC
            l = lambert_problem_multirev(
                v,
                lambert_problem(r,
                                r_P[i + 1],
                                dt,
                                self.common_mu,
                                cw=False,
                                max_revs=self.max_revs))
            v_end_l = l.get_v2()[0]
            v_beg_l = l.get_v1()[0]
            lamberts.append(l)
            # DSM occuring at time nu2*T2
            DV[i] = norm([a - b for a, b in zip(v_beg_l, v)])

            ballistic_legs.append((r, v_beg_l))
            ballistic_ep.append(t_P[i].mjd2000 + x[8 + (i - 1) * 4] * T[i])

        # Last Delta-v
        if self._add_vinf_arr:
            DV[-1] = norm([a - b for a, b in zip(v_end_l, v_P[-1])])
            if self._orbit_insertion:
                # In this case we compute the insertion DV as a single pericenter
                # burn
                DVper = np.sqrt(DV[-1] * DV[-1] +
                                2 * self._seq[-1].mu_self / self._rp_target)
                DVper2 = np.sqrt(2 * self._seq[-1].mu_self / self._rp_target -
                                 self._seq[-1].mu_self / self._rp_target *
                                 (1. - self._e_target))
                DV[-1] = np.abs(DVper - DVper2)

        if self._add_vinf_dep:
            DV[0] += x[3]

        return (DV, lamberts, T, ballistic_legs, ballistic_ep)
예제 #24
0
    def __init__(self,
                 seq=[jpl_lp('earth'), jpl_lp('venus'), jpl_lp('earth')],
                 n_seg=[10] * 2,
                 t0=[epoch(0), epoch(1000)],
                 tof=[[200, 500], [200, 500]],
                 vinf_dep=2.5,
                 vinf_arr=2.0,
                 mass=4000.0,
                 Tmax=1.0,
                 Isp=2000.0,
                 fb_rel_vel=6,
                 multi_objective=False,
                 high_fidelity=False):
        """
        prob = mga_lt_nep(seq = [jpl_lp('earth'),jpl_lp('venus'),jpl_lp('earth')], n_seg = [10]*2,
        t0 = [epoch(0),epoch(1000)], tof = [[200,500],[200,500]], vinf_dep=2.5, vinf_arr=2.0, mass=4000.0, Tmax=1.0, Isp=2000.0,
        multi_objective = False, fb_rel_vel = 6, high_fidelity=False)

        - 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 pykep epochs defining the launch window
        - tof: minimum and maximum time of each leg (days)
        - vinf_dep: maximum launch hyperbolic velocity allowed (in km/sec)
        - vinf_arr: maximum arrival hyperbolic velocity allowed (in km/sec)
        - mass: spacecraft starting mass
        - Tmax: maximum thrust
        - Isp: engine specific impulse
        - fb_rel_vel = determines the bounds on the maximum allowed relative velocity at all fly-bys (in km/sec)
        - multi-objective: when True defines the problem as a multi-objective problem, returning total DV and time of flight
        - high_fidelity = makes the trajectory computations slower, but actually dynamically feasible.
        """

        # 1) We compute the problem dimensions .... and call the base problem
        # constructor
        self.__n_legs = len(seq) - 1
        n_fb = self.__n_legs - 1
        # 1a) The decision vector length
        dim = 1 + self.__n_legs * 8 + sum(n_seg) * 3
        # 1b) The total number of constraints (mismatch + fly-by + boundary +
        # throttles
        c_dim = self.__n_legs * 7 + n_fb * 2 + 2 + sum(n_seg)
        # 1c) The number of inequality constraints (boundary + fly-by angle +
        # throttles)
        c_ineq_dim = 2 + n_fb + sum(n_seg)
        # 1d) the number of objectives
        f_dim = multi_objective + 1
        # First we call the constructor for the base pygmo problem
        # As our problem is n dimensional, box-bounded (may be multi-objective), we write
        # (dim, integer dim, number of obj, number of con, number of inequality con, tolerance on con violation)
        super(mga_lt_nep, self).__init__(
            dim, 0, f_dim, c_dim, c_ineq_dim, 1e-4)

        # 2) We then define some class data members
        # public:
        self.seq = seq
        # private:
        self.__n_seg = n_seg
        self.__vinf_dep = vinf_dep * 1000
        self.__vinf_arr = vinf_arr * 1000
        self.__sc = spacecraft(mass, Tmax, Isp)
        self.__leg = leg()
        self.__leg.set_mu(MU_SUN)
        self.__leg.set_spacecraft(self.__sc)
        self.__leg.high_fidelity = high_fidelity
        fb_rel_vel *= 1000
        # 3) We compute the bounds
        lb = [t0[0].mjd2000] + [0, mass / 2, -fb_rel_vel, -fb_rel_vel, -fb_rel_vel, -
                                fb_rel_vel, -fb_rel_vel, -fb_rel_vel] * self.__n_legs + [-1, -1, -1] * sum(self.__n_seg)
        ub = [t0[1].mjd2000] + [1, mass, fb_rel_vel, fb_rel_vel, fb_rel_vel, fb_rel_vel,
                                fb_rel_vel, fb_rel_vel] * self.__n_legs + [1, 1, 1] * sum(self.__n_seg)
        # 3a ... and account for the bounds on the vinfs......
        lb[3:6] = [-self.__vinf_dep] * 3
        ub[3:6] = [self.__vinf_dep] * 3
        lb[-sum(self.__n_seg) * 3 - 3:-sum(self.__n_seg)
           * 3] = [-self.__vinf_arr] * 3
        ub[-sum(self.__n_seg) * 3 - 3:-sum(self.__n_seg)
           * 3] = [self.__vinf_arr] * 3
        # 3b... and for the time of flight
        lb[1:1 + 8 * self.__n_legs:8] = [el[0] for el in tof]
        ub[1:1 + 8 * self.__n_legs:8] = [el[1] for el in tof]

        # 4) And we set the bounds
        self.set_bounds(lb, ub)
예제 #25
0
    def plot(self, x, ax=None):
        """
        ax = prob.plot(x, ax=None)

        - x: encoded trajectory
        - ax: matplotlib axis where to plot. If None figure and axis will be created
        - [out] ax: matplotlib axis where to plot

        Plots the trajectory represented by a decision vector x on the 3d axis ax

        Example::

          ax = prob.plot(x)
        """
        import matplotlib as mpl
        from mpl_toolkits.mplot3d import Axes3D
        import matplotlib.pyplot as plt
        from pykep import epoch, AU
        from pykep.sims_flanagan import sc_state
        from pykep.orbit_plots import plot_planet, plot_sf_leg

        # Creating the axis if necessary
        if ax is None:
            mpl.rcParams['legend.fontsize'] = 10
            fig = plt.figure()
            axis = fig.gca(projection='3d')
        else:
            axis = ax

        # Plotting the Sun ........
        axis.scatter([0], [0], [0], color='y')

        # Plotting the legs .......
        # 1 - We decode the chromosome extracting the time of flights
        T = list([0] * (self.__n_legs))
        for i in range(self.__n_legs):
            T[i] = x[1 + i * 8]

        # 2 - We compute the epochs and ephemerides of the planetary encounters
        t_P = list([None] * (self.__n_legs + 1))
        r_P = list([None] * (self.__n_legs + 1))
        v_P = list([None] * (self.__n_legs + 1))

        for i, planet in enumerate(self.seq):
            t_P[i] = epoch(x[0] + sum(T[0:i]))
            r_P[i], v_P[i] = self.seq[i].eph(t_P[i])

        # 3 - We iterate through legs to compute mismatches and throttles
        # constraints
        ceq = list()
        cineq = list()
        m0 = self.__sc.mass
        for i in range(self.__n_legs):
            # First Leg
            v = [a + b for a, b in zip(v_P[i], x[(3 + i * 8):(6 + i * 8)])]
            x0 = sc_state(r_P[i], v, m0)
            v = [a + b for a,
                 b in zip(v_P[i + 1], x[(6 + i * 8):(11 + i * 8)])]
            xe = sc_state(r_P[i + 1], v, x[2 + i * 8])
            throttles = x[(1 + 8 * self.__n_legs + 3 * sum(self.__n_seg[:i])):(
                1 + 8 * self.__n_legs + 3 * sum(self.__n_seg[:i]) + 3 * self.__n_seg[i])]
            self.__leg.set(t_P[i], x0, throttles, t_P[i + 1], xe)
            # update mass!
            m0 = x[2 + 8 * i]
            plot_sf_leg(self.__leg, units=AU, N=10, ax=axis)

        # Plotting planets
        for i, planet in enumerate(self.seq):
            plot_planet(planet, t_P[i], units=AU,
                        legend=True, color=(0.7, 0.7, 1), ax=axis)

        plt.show()
        return axis
예제 #26
0
    def _compute_constraints_impl(self, x):
        # 1 - We decode the chromosome extracting the time of flights
        T = list([0] * (self.__n_legs))
        for i in range(self.__n_legs):
            T[i] = x[1 + i * 8]

        # 2 - We compute the epochs and ephemerides of the planetary encounters
        t_P = list([None] * (self.__n_legs + 1))
        r_P = list([None] * (self.__n_legs + 1))
        v_P = list([None] * (self.__n_legs + 1))

        for i, planet in enumerate(self.seq):
            t_P[i] = epoch(x[0] + sum(T[0:i]))
            r_P[i], v_P[i] = self.seq[i].eph(t_P[i])

        # 3 - We iterate through legs to compute mismatches and throttles
        # constraints
        ceq = list()
        cineq = list()
        m0 = self.__sc.mass
        for i in range(self.__n_legs):
            # First Leg
            v = [a + b for a, b in zip(v_P[i], x[(3 + i * 8):(6 + i * 8)])]
            x0 = sc_state(r_P[i], v, m0)
            v = [a + b for a, b in zip(v_P[i + 1], x[(6 + i * 8):(9 + i * 8)])]
            xe = sc_state(r_P[i + 1], v, x[2 + i * 8])
            throttles = x[(1 + 8 * self.__n_legs + 3 * sum(self.__n_seg[:i])):(
                1 + 8 * self.__n_legs + 3 * sum(self.__n_seg[:i]) + 3 * self.__n_seg[i])]
            self.__leg.set(t_P[i], x0, throttles, t_P[i + 1], xe)
            # update mass!
            m0 = x[2 + 8 * i]
            ceq.extend(self.__leg.mismatch_constraints())
            cineq.extend(self.__leg.throttles_constraints())

        # Adding the boundary constraints
        # departure
        v_dep_con = (x[3] ** 2 + x[4] ** 2 + x[5] ** 2 -
                     self.__vinf_dep ** 2) / (EARTH_VELOCITY ** 2)
        # arrival
        v_arr_con = (x[6 + (self.__n_legs - 1) * 8] ** 2 + x[7 + (self.__n_legs - 1) * 8] **
                     2 + x[8 + (self.__n_legs - 1) * 8] ** 2 - self.__vinf_arr ** 2) / (EARTH_VELOCITY ** 2)
        cineq.append(v_dep_con * 100)
        cineq.append(v_arr_con * 100)

        # We add the fly-by constraints
        for i in range(self.__n_legs - 1):
            DV_eq, alpha_ineq = fb_con(
                x[6 + i * 8:9 + i * 8], x[11 + i * 8:14 + i * 8], self.seq[i + 1])
            ceq.append(DV_eq / (EARTH_VELOCITY ** 2))
            cineq.append(alpha_ineq)

        # Making the mismatches non dimensional
        for i in range(self.__n_legs):
            ceq[0 + i * 7] /= AU
            ceq[1 + i * 7] /= AU
            ceq[2 + i * 7] /= AU
            ceq[3 + i * 7] /= EARTH_VELOCITY
            ceq[4 + i * 7] /= EARTH_VELOCITY
            ceq[5 + i * 7] /= EARTH_VELOCITY
            ceq[6 + i * 7] /= self.__sc.mass

        # We assemble the constraint vector
        retval = list()
        retval.extend(ceq)
        retval.extend(cineq)

        return retval
예제 #27
0
    def __init__(self,
                 seq=[jpl_lp('earth'),
                      jpl_lp('venus'),
                      jpl_lp('earth')],
                 n_seg=[10] * 2,
                 t0=[epoch(0), epoch(1000)],
                 tof=[[200, 500], [200, 500]],
                 vinf_dep=2.5,
                 vinf_arr=2.0,
                 mass=4000.0,
                 Tmax=1.0,
                 Isp=2000.0,
                 fb_rel_vel=6,
                 multi_objective=False,
                 high_fidelity=False):
        """
        prob = mga_lt_nep(seq = [jpl_lp('earth'),jpl_lp('venus'),jpl_lp('earth')], n_seg = [10]*2,
        t0 = [epoch(0),epoch(1000)], tof = [[200,500],[200,500]], vinf_dep=2.5, vinf_arr=2.0, mass=4000.0, Tmax=1.0, Isp=2000.0,
        multi_objective = False, fb_rel_vel = 6, high_fidelity=False)

        - 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 pykep epochs defining the launch window
        - tof: minimum and maximum time of each leg (days)
        - vinf_dep: maximum launch hyperbolic velocity allowed (in km/sec)
        - vinf_arr: maximum arrival hyperbolic velocity allowed (in km/sec)
        - mass: spacecraft starting mass
        - Tmax: maximum thrust
        - Isp: engine specific impulse
        - fb_rel_vel = determines the bounds on the maximum allowed relative velocity at all fly-bys (in km/sec)
        - multi-objective: when True defines the problem as a multi-objective problem, returning total DV and time of flight
        - high_fidelity = makes the trajectory computations slower, but actually dynamically feasible.
        """

        # 1) We compute the problem dimensions .... and call the base problem
        # constructor
        self.__n_legs = len(seq) - 1
        n_fb = self.__n_legs - 1
        # 1a) The decision vector length
        dim = 1 + self.__n_legs * 8 + sum(n_seg) * 3
        # 1b) The total number of constraints (mismatch + fly-by + boundary +
        # throttles
        c_dim = self.__n_legs * 7 + n_fb * 2 + 2 + sum(n_seg)
        # 1c) The number of inequality constraints (boundary + fly-by angle +
        # throttles)
        c_ineq_dim = 2 + n_fb + sum(n_seg)
        # 1d) the number of objectives
        f_dim = multi_objective + 1
        # First we call the constructor for the base pygmo problem
        # As our problem is n dimensional, box-bounded (may be multi-objective), we write
        # (dim, integer dim, number of obj, number of con, number of inequality con, tolerance on con violation)
        super(mga_lt_nep, self).__init__(dim, 0, f_dim, c_dim, c_ineq_dim,
                                         1e-4)

        # 2) We then define some class data members
        # public:
        self.seq = seq
        # private:
        self.__n_seg = n_seg
        self.__vinf_dep = vinf_dep * 1000
        self.__vinf_arr = vinf_arr * 1000
        self.__sc = spacecraft(mass, Tmax, Isp)
        self.__leg = leg()
        self.__leg.set_mu(MU_SUN)
        self.__leg.set_spacecraft(self.__sc)
        self.__leg.high_fidelity = high_fidelity
        fb_rel_vel *= 1000
        # 3) We compute the bounds
        lb = [t0[0].mjd2000] + [
            0, mass / 2, -fb_rel_vel, -fb_rel_vel, -fb_rel_vel, -fb_rel_vel,
            -fb_rel_vel, -fb_rel_vel
        ] * self.__n_legs + [-1, -1, -1] * sum(self.__n_seg)
        ub = [t0[1].mjd2000] + [
            1, mass, fb_rel_vel, fb_rel_vel, fb_rel_vel, fb_rel_vel,
            fb_rel_vel, fb_rel_vel
        ] * self.__n_legs + [1, 1, 1] * sum(self.__n_seg)
        # 3a ... and account for the bounds on the vinfs......
        lb[3:6] = [-self.__vinf_dep] * 3
        ub[3:6] = [self.__vinf_dep] * 3
        lb[-sum(self.__n_seg) * 3 - 3:-sum(self.__n_seg) *
           3] = [-self.__vinf_arr] * 3
        ub[-sum(self.__n_seg) * 3 - 3:-sum(self.__n_seg) *
           3] = [self.__vinf_arr] * 3
        # 3b... and for the time of flight
        lb[1:1 + 8 * self.__n_legs:8] = [el[0] for el in tof]
        ub[1:1 + 8 * self.__n_legs:8] = [el[1] for el in tof]

        # 4) And we set the bounds
        self.set_bounds(lb, ub)
예제 #28
0
    def plot(self, x, ax=None):
        """
        ax = prob.plot(x, ax=None)

        - x: encoded trajectory
        - ax: matplotlib axis where to plot. If None figure and axis will be created
        - [out] ax: matplotlib axis where to plot

        Plots the trajectory represented by a decision vector x on the 3d axis ax

        Example::

          ax = prob.plot(x)
        """
        import matplotlib as mpl
        from mpl_toolkits.mplot3d import Axes3D
        import matplotlib.pyplot as plt
        from pykep.orbit_plots import plot_planet, plot_lambert, plot_kepler

        if ax is None:
            mpl.rcParams['legend.fontsize'] = 10
            fig = plt.figure()
            axis = fig.gca(projection='3d')
        else:
            axis = ax

        axis.scatter(0, 0, 0, color='y')

        # 1 -  we 'decode' the chromosome recording the various times of flight
        # (days) in the list T and the cartesian components of vinf
        T, Vinfx, Vinfy, Vinfz = self._decode_times_and_vinf(x)

        # 2 - We compute the epochs and ephemerides of the planetary encounters
        t_P = list([None] * (self.n_legs + 1))
        r_P = list([None] * (self.n_legs + 1))
        v_P = list([None] * (self.n_legs + 1))
        DV = list([None] * (self.n_legs + 1))

        for i, planet in enumerate(self._seq):
            t_P[i] = epoch(x[0] + sum(T[0:i]))
            r_P[i], v_P[i] = planet.eph(t_P[i])
            plot_planet(planet,
                        t0=t_P[i],
                        color=(0.8, 0.6, 0.8),
                        legend=True,
                        units=AU,
                        axes=axis,
                        N=150)

        # 3 - We start with the first leg
        v0 = [a + b for a, b in zip(v_P[0], [Vinfx, Vinfy, Vinfz])]
        r, v = propagate_lagrangian(r_P[0], v0, x[4] * T[0] * DAY2SEC,
                                    self.common_mu)

        plot_kepler(r_P[0],
                    v0,
                    x[4] * T[0] * DAY2SEC,
                    self.common_mu,
                    N=100,
                    color='b',
                    legend=False,
                    units=AU,
                    axes=axis)

        # Lambert arc to reach seq[1]
        dt = (1 - x[4]) * T[0] * DAY2SEC
        l = lambert_problem(r, r_P[1], dt, self.common_mu, False, False)
        plot_lambert(l, sol=0, color='r', legend=False, units=AU, axes=axis)
        v_end_l = l.get_v2()[0]
        v_beg_l = l.get_v1()[0]

        # First DSM occuring at time nu1*T1
        DV[0] = norm([a - b for a, b in zip(v_beg_l, v)])

        # 4 - And we proceed with each successive leg
        for i in range(1, self.n_legs):
            # Fly-by
            v_out = fb_prop(v_end_l, v_P[i],
                            x[7 + (i - 1) * 4] * self._seq[i].radius,
                            x[6 + (i - 1) * 4], self._seq[i].mu_self)
            # s/c propagation before the DSM
            r, v = propagate_lagrangian(r_P[i], v_out,
                                        x[8 + (i - 1) * 4] * T[i] * DAY2SEC,
                                        self.common_mu)
            plot_kepler(r_P[i],
                        v_out,
                        x[8 + (i - 1) * 4] * T[i] * DAY2SEC,
                        self.common_mu,
                        N=100,
                        color='b',
                        legend=False,
                        units=AU,
                        axes=axis)
            # Lambert arc to reach Earth during (1-nu2)*T2 (second segment)
            dt = (1 - x[8 + (i - 1) * 4]) * T[i] * DAY2SEC

            l = lambert_problem(r, r_P[i + 1], dt, self.common_mu, False,
                                False)
            plot_lambert(l,
                         sol=0,
                         color='r',
                         legend=False,
                         units=AU,
                         N=1000,
                         axes=axis)

            v_end_l = l.get_v2()[0]
            v_beg_l = l.get_v1()[0]
            # DSM occuring at time nu2*T2
            DV[i] = norm([a - b for a, b in zip(v_beg_l, v)])
        plt.show()
        return axis
예제 #29
0
    def pretty(self, x):
        """
        prob.plot(x)

        - x: encoded trajectory

        Prints human readable information on the trajectory represented by the decision vector x

        Example::

          print(prob.pretty(x))
        """
        # 1 -  we 'decode' the chromosome recording the various times of flight
        # (days) in the list T and the cartesian components of vinf
        T, Vinfx, Vinfy, Vinfz = self._decode_times_and_vinf(x)

        # 2 - We compute the epochs and ephemerides of the planetary encounters
        t_P = list([None] * (self.n_legs + 1))
        r_P = list([None] * (self.n_legs + 1))
        v_P = list([None] * (self.n_legs + 1))
        DV = list([0.0] * (self.n_legs + 1))
        for i in range(len(self._seq)):
            t_P[i] = epoch(x[0] + sum(T[0:i]))
            r_P[i], v_P[i] = self._seq[i].eph(t_P[i])

        # 3 - We start with the first leg
        print("First Leg: " + self._seq[0].name + " to " + self._seq[1].name)
        print("Departure: " + str(t_P[0]) + " (" + str(t_P[0].mjd2000) +
              " mjd2000) ")
        print("Duration: " + str(T[0]) + "days")
        print("VINF: " + str(x[3] / 1000) + " km/sec")

        v0 = [a + b for a, b in zip(v_P[0], [Vinfx, Vinfy, Vinfz])]
        r, v = propagate_lagrangian(r_P[0], v0, x[4] * T[0] * DAY2SEC,
                                    self.common_mu)

        print("DSM after " + str(x[4] * T[0]) + " days")

        # Lambert arc to reach seq[1]
        dt = (1 - x[4]) * T[0] * DAY2SEC
        l = lambert_problem(r,
                            r_P[1],
                            dt,
                            self.common_mu,
                            cw=False,
                            max_revs=0)
        v_end_l = l.get_v2()[0]
        v_beg_l = l.get_v1()[0]

        # First DSM occuring at time nu1*T1
        DV[0] = norm([a - b for a, b in zip(v_beg_l, v)])
        print("DSM magnitude: " + str(DV[0]) + "m/s")

        # 4 - And we proceed with each successive leg
        for i in range(1, self.n_legs):
            print("\nleg no. " + str(i + 1) + ": " + self._seq[i].name +
                  " to " + self._seq[i + 1].name)
            print("Duration: " + str(T[i]) + "days")
            # Fly-by
            v_out = fb_prop(v_end_l, v_P[i],
                            x[7 + (i - 1) * 4] * self._seq[i].radius,
                            x[6 + (i - 1) * 4], self._seq[i].mu_self)
            print("Fly-by epoch: " + str(t_P[i]) + " (" + str(t_P[i].mjd2000) +
                  " mjd2000) ")
            print("Fly-by radius: " + str(x[7 + (i - 1) * 4]) +
                  " planetary radii")
            # s/c propagation before the DSM
            r, v = propagate_lagrangian(r_P[i], v_out,
                                        x[8 + (i - 1) * 4] * T[i] * DAY2SEC,
                                        self.common_mu)
            print("DSM after " + str(x[8 + (i - 1) * 4] * T[i]) + " days")
            # Lambert arc to reach Earth during (1-nu2)*T2 (second segment)
            dt = (1 - x[8 + (i - 1) * 4]) * T[i] * DAY2SEC
            l = lambert_problem(r,
                                r_P[i + 1],
                                dt,
                                self.common_mu,
                                cw=False,
                                max_revs=0)
            v_end_l = l.get_v2()[0]
            v_beg_l = l.get_v1()[0]
            # DSM occuring at time nu2*T2
            DV[i] = norm([a - b for a, b in zip(v_beg_l, v)])
            print("DSM magnitude: " + str(DV[i]) + "m/s")

        # Last Delta-v
        print("\nArrival at " + self._seq[-1].name)
        DV[-1] = norm([a - b for a, b in zip(v_end_l, v_P[-1])])
        print("Arrival epoch: " + str(t_P[-1]) + " (" + str(t_P[-1].mjd2000) +
              " mjd2000) ")
        print("Arrival Vinf: " + str(DV[-1]) + "m/s")
        if self._orbit_insertion:
            # In this case we compute the insertion DV as a single pericenter
            # burn
            DVper = np.sqrt(DV[-1] * DV[-1] +
                            2 * self._seq[-1].mu_self / self._rp_target)
            DVper2 = np.sqrt(2 * self._seq[-1].mu_self / self._rp_target -
                             self._seq[-1].mu_self / self._rp_target *
                             (1. - self._e_target))
            DVinsertion = np.abs(DVper - DVper2)
            print("Insertion DV: " + str(DVinsertion) + "m/s")

        print("Total mission time: " + str(sum(T) / 365.25) + " years (" +
              str(sum(T)) + " days)")
예제 #30
0
    def ic_from_mga_1dsm(self, x):
        """
        x_lt = prob.ic_from_mga_1dsm(x_mga)

        - x_mga: compatible trajectory as encoded by an mga_1dsm problem

        Returns an initial guess for the low-thrust trajectory, converting the mga_1dsm solution x_dsm. The user
        is responsible that x_mga makes sense (i.e. it is a viable mga_1dsm representation). The conversion is done by importing in the
        low-thrust encoding a) the launch date b) all the legs durations, c) the in and out relative velocities at each planet.
        All throttles are put to zero.

        Example::

          x_lt= prob.ic_from_mga_1dsm(x_mga)
        """
        from math import pi, cos, sin, acos
        from scipy.linalg import norm
        from pykep import propagate_lagrangian, lambert_problem, DAY2SEC, fb_prop

        retval = list([0.0] * self.dimension)
        # 1 -  we 'decode' the chromosome recording the various times of flight
        # (days) in the list T
        T = list([0] * (self.__n_legs))

        for i in range(len(T)):
            T[i] = log(x[2 + 4 * i])
        total = sum(T)
        T = [x[1] * time / total for time in T]

        retval[0] = x[0]
        for i in range(self.__n_legs):
            retval[1 + 8 * i] = T[i]
            retval[2 + 8 * i] = self.__sc.mass

        # 2 - We compute the epochs and ephemerides of the planetary encounters
        t_P = list([None] * (self.__n_legs + 1))
        r_P = list([None] * (self.__n_legs + 1))
        v_P = list([None] * (self.__n_legs + 1))
        DV = list([None] * (self.__n_legs + 1))

        for i, planet in enumerate(self.seq):
            t_P[i] = epoch(x[0] + sum(T[0:i]))
            r_P[i], v_P[i] = self.seq[i].eph(t_P[i])

        # 3 - We start with the first leg
        theta = 2 * pi * x[1]
        phi = acos(2 * x[2] - 1) - pi / 2

        Vinfx = x[3] * cos(phi) * cos(theta)
        Vinfy = x[3] * cos(phi) * sin(theta)
        Vinfz = x[3] * sin(phi)

        retval[3:6] = [Vinfx, Vinfy, Vinfz]

        v0 = [a + b for a, b in zip(v_P[0], [Vinfx, Vinfy, Vinfz])]
        r, v = propagate_lagrangian(r_P[0], v0, x[4] * T[0] * DAY2SEC, MU_SUN)

        # Lambert arc to reach seq[1]
        dt = (1 - x[4]) * T[0] * DAY2SEC
        l = lambert_problem(r, r_P[1], dt, MU_SUN)
        v_end_l = l.get_v2()[0]
        v_beg_l = l.get_v1()[0]

        retval[6:9] = [a - b for a, b in zip(v_end_l, v_P[1])]

        # 4 - And we proceed with each successive leg
        for i in range(1, self.__n_legs):
            # Fly-by
            v_out = fb_prop(v_end_l, v_P[i],
                            x[7 + (i - 1) * 4] * self.seq[i].radius,
                            x[6 + (i - 1) * 4], self.seq[i].mu_self)
            retval[3 + i * 8:6 +
                   i * 8] = [a - b for a, b in zip(v_out, v_P[i])]
            # s/c propagation before the DSM
            r, v = propagate_lagrangian(r_P[i], v_out,
                                        x[8 + (i - 1) * 4] * T[i] * DAY2SEC,
                                        MU_SUN)
            # Lambert arc to reach Earth during (1-nu2)*T2 (second segment)
            dt = (1 - x[8 + (i - 1) * 4]) * T[i] * DAY2SEC
            l = lambert_problem(r, r_P[i + 1], dt, MU_SUN)
            v_end_l = l.get_v2()[0]
            v_beg_l = l.get_v1()[0]
            # DSM occuring at time nu2*T2
            DV[i] = norm([a - b for a, b in zip(v_beg_l, v)])
            retval[6 + i * 8:9 +
                   i * 8] = [a - b for a, b in zip(v_end_l, v_P[i + 1])]
        return retval
예제 #31
0
    def __init__(self,
                 seq=[jpl_lp('earth'),
                      jpl_lp('venus'),
                      jpl_lp('earth')],
                 t0=[epoch(0), epoch(1000)],
                 tof=[[10, 300], [10, 300]],
                 vinf=[0.5, 2.5],
                 add_vinf_dep=False,
                 add_vinf_arr=True,
                 tof_encoding='direct',
                 multi_objective=False,
                 orbit_insertion=False,
                 e_target=None,
                 rp_target=None,
                 eta_lb=0.1,
                 eta_ub=0.9,
                 rp_ub=30):
        """
        pykep.trajopt.mga_1dsm(seq = [jpl_lp('earth'), jpl_lp('venus'), jpl_lp('earth')], t0 = [epoch(0),epoch(1000)], tof = [1.0,5.0], vinf = [0.5, 2.5], multi_objective = False, add_vinf_dep = False, add_vinf_arr=True)

        - seq (``list`` of ``pykep.planet``): the encounter sequence (including the starting launch)
        - t0 (``list`` of ``pykep.epoch`` or ``floats``): the launch window (in mjd2000 if floats)
        - tof (``list`` or ``float``): bounds on the time of flight (days). If *tof_encoding* is 'direct', this contains a list
            of 2D lists defining the upper and lower bounds on each leg. If *tof_encoding* is 'alpha',
            this contains a list of two floats containing the lower and upper bounds on the time-of-flight. If *tof_encoding*
            is 'eta' tof is a float defining the upper bound on the time-of-flight
        - vinf (``list``): the minimum and maximum allowed initial hyperbolic velocity (at launch), in km/sec
        - add_vinf_dep (``bool``): when True the computed Dv includes the initial hyperbolic velocity (at launch)
        - add_vinf_arr (``bool``): when True the computed Dv includes the final hyperbolic velocity (at the last planet)
        - tof_encoding (``str``): one of 'direct', 'alpha' or 'eta'. Selects the encoding for the time of flights
        - multi_objective (``bool``): when True constructs a multiobjective problem (dv, T)
        - orbit_insertion (``bool``): when True the arrival dv is computed as that required to acquire a target orbit defined by e_target and rp_target
        - e_target (``float``): if orbit_insertion is True this defines the target orbit eccentricity around the final planet
        - rp_target (``float``): if orbit_insertion is True this defines the target orbit pericenter around the final planet (in m)
        """

        # Sanity checks
        # 1 - Planets need to have the same mu_central_body
        if ([r.mu_central_body
             for r in seq].count(seq[0].mu_central_body) != len(seq)):
            raise ValueError(
                'All planets in the sequence need to have identical mu_central_body'
            )
        # 2 - tof encoding needs to be one of 'alpha', 'eta', 'direct'
        if tof_encoding not in ['alpha', 'eta', 'direct']:
            raise TypeError(
                'tof encoding must be one of \'alpha\', \'eta\', \'direct\'')
        # 3 - tof is expected to have different content depending on the tof_encoding
        if tof_encoding == 'direct':
            if np.shape(np.array(tof)) != (len(seq) - 1, 2):
                raise TypeError(
                    'tof_encoding is ' + tof_encoding +
                    ' and tof must be a list of two dimensional lists and with length equal to the number of legs'
                )
        if tof_encoding == 'alpha':
            if np.shape(np.array(tof)) != (2, ):
                raise TypeError('tof_encoding is ' + tof_encoding +
                                ' and tof must be a list of two floats')
        if tof_encoding == 'eta':
            if np.shape(np.array(tof)) != ():
                raise TypeError('tof_encoding is ' + tof_encoding +
                                ' and tof must be a float')
        # 4 - Check launch window t0. If defined in terms of floats transform into epochs
        if len(t0) != 2:
            raise TypeError('t0 is ' + t0 +
                            ' while should be a list of two floats or epochs')
        if type(t0[0]) is not epoch:
            t0[0] = epoch(t0[0])
        if type(t0[1]) is not epoch:
            t0[1] = epoch(t0[1])
        # 5 - Check that if orbit insertion is selected e_target and r_p are
        # defined
        if orbit_insertion:
            if rp_target is None:
                raise ValueError(
                    'The rp_target needs to be specified when orbit insertion is selected'
                )
            if e_target is None:
                raise ValueError(
                    'The e_target needs to be specified when orbit insertion is selected'
                )
            if add_vinf_arr is False:
                raise ValueError(
                    'When orbit insertion is selected, the add_vinf_arr must be True'
                )

        self._seq = seq
        self._t0 = t0
        self._tof = tof
        self._vinf = vinf
        self._add_vinf_dep = add_vinf_dep
        self._add_vinf_arr = add_vinf_arr
        self._tof_encoding = tof_encoding
        self._multi_objective = multi_objective
        self._orbit_insertion = orbit_insertion
        self._e_target = e_target
        self._rp_target = rp_target
        self._eta_lb = eta_lb
        self._eta_ub = eta_ub
        self._rp_ub = rp_ub

        self.n_legs = len(seq) - 1
        self.common_mu = seq[0].mu_central_body
예제 #32
0
    def __init__(self,
                 seq=[jpl_lp('earth'),
                      jpl_lp('venus'),
                      jpl_lp('earth')],
                 t0=[0, 1000],
                 tof=[[30, 200], [200, 300]],
                 vinf=2.5,
                 multi_objective=False,
                 tof_encoding='direct',
                 orbit_insertion=False,
                 e_target=None,
                 rp_target=None,
                 max_revs=0):
        """mga(seq=[pk.planet.jpl_lp('earth'), pk.planet.jpl_lp('venus'), pk.planet.jpl_lp('earth')], t0=[0, 1000], tof=[100, 500], vinf=2.5, multi_objective=False, alpha_encoding=False, orbit_insertion=False, e_target=None, rp_target=None)

        Args:
            - seq (``list of pk.planet``): sequence of body encounters including the starting object
            - t0 (``list of pk.epoch``): the launch window
            - tof (``list`` or ``float``): bounds on the time of flight. If *tof_encoding* is 'direct', this contains a list
              of 2D lists defining the upper and lower bounds on each leg. If *tof_encoding* is 'alpha',
              this contains a 2D list with the lower and upper bounds on the time-of-flight. If *tof_encoding*
              is 'eta' tof is a float defining the upper bound on the time-of-flight
            - vinf (``float``): the vinf provided at launch for free
            - multi_objective (``bool``): when True constructs a multiobjective problem (dv, T). In this case, 'alpha' or `eta` encodings are recommended
            - tof_encoding (``str``): one of 'direct', 'alpha' or 'eta'. Selects the encoding for the time of flights
            - orbit_insertion (``bool``): when True the arrival dv is computed as that required to acquire a target orbit defined by e_target and rp_target
            - e_target (``float``): if orbit_insertion is True this defines the target orbit eccentricity around the final planet
            - rp_target (``float``): if orbit_insertion is True this defines the target orbit pericenter around the final planet (in m)
            - max_revs (``int``): maximal number of revolutions for lambert transfer

        Raises:
            - ValueError: if *planets* do not share the same central body (checked on the mu_central_body attribute)
            - ValueError: if *t0* does not contain objects able to construct a epoch (e.g. pk. epoch or floats)
            - ValueError: if *tof* is badly defined
            - ValueError: it the target orbit is not defined and *orbit_insertion* is True
        """

        # Sanity checks
        # 1 - All planets need to have the same mu_central_body
        if ([r.mu_central_body
             for r in seq].count(seq[0].mu_central_body) != len(seq)):
            raise ValueError(
                'All planets in the sequence need to have exactly the same mu_central_body'
            )
        # 2 - We try to build epochs out of the t0 list (mjd2000 by default)
        for i in range(len(t0)):
            if (type(t0[i]) != type(epoch(0))):
                t0[i] = epoch(t0[i])
        # 3 - Check the tof bounds
        if tof_encoding == 'alpha':
            if len(tof) != 2:
                raise ValueError(
                    r'When the tof_encoding is \'alpha\', tof is expected to be something like [lb, ub]'
                )
        elif tof_encoding == 'direct':
            if len(tof) != (len(seq) - 1):
                raise ValueError(
                    'When tof_encoding is direct, the tof must be a float (upper bound on the time of flight)'
                    + str(len(seq) - 1))
        elif tof_encoding == 'eta':
            try:
                float(tof)
            except TypeError:
                raise ValueError('The tof needs to be have len equal to  ' +
                                 str(len(seq) - 1))
        if not tof_encoding in ['alpha', 'eta', 'direct']:
            raise ValueError(
                "tof_encoding must be one of 'alpha', 'eta', 'direct'")

        # 4 - Check that if orbit insertion is selected e_target and r_p are
        # defined
        if orbit_insertion:
            if rp_target is None:
                raise ValueError(
                    'The rp_target needs to be specified when orbit insertion is selected'
                )
            if e_target is None:
                raise ValueError(
                    'The e_target needs to be specified when orbit insertion is selected'
                )

        # Public data members
        self.seq = seq
        self.t0 = t0
        self.tof = tof
        self.vinf = vinf * 1000
        self.multi_objective = multi_objective
        self.tof_encoding = tof_encoding
        self.orbit_insertion = orbit_insertion
        self.e_target = e_target
        self.rp_target = rp_target

        # Private data members
        self._n_legs = len(seq) - 1
        self._common_mu = seq[0].mu_central_body
        self.max_revs = max_revs
예제 #33
0
    def pretty(self, x):
        """
        prob.plot(x)

        - x: encoded trajectory

        Prints human readable information on the trajectory represented by the decision vector x

        Example::

          print(prob.pretty(x))
        """
        # 1 -  we 'decode' the chromosome recording the various times of flight
        # (days) in the list T and the cartesian components of vinf
        T, Vinfx, Vinfy, Vinfz = self._decode_times_and_vinf(x)

        # 2 - We compute the epochs and ephemerides of the planetary encounters
        t_P = list([None] * (self.__n_legs + 1))
        r_P = list([None] * (self.__n_legs + 1))
        v_P = list([None] * (self.__n_legs + 1))
        DV = list([None] * (self.__n_legs + 1))

        for i, planet in enumerate(self.seq):
            t_P[i] = epoch(x[0] + sum(T[0:i]))
            r_P[i], v_P[i] = self.seq[i].eph(t_P[i])

        # 3 - We start with the first leg
        print("First Leg: " + self.seq[0].name + " to " + self.seq[1].name)
        print("Departure: " + str(t_P[0]) +
              " (" + str(t_P[0].mjd2000) + " mjd2000) ")
        print("Duration: " + str(T[0]) + "days")
        print("VINF: " + str(x[4] / 1000) + " km/sec")

        v0 = [a + b for a, b in zip(v_P[0], [Vinfx, Vinfy, Vinfz])]
        r, v = propagate_lagrangian(
            r_P[0], v0, x[5] * T[0] * DAY2SEC, self.common_mu)

        print("DSM after " + str(x[5] * T[0]) + " days")

        # Lambert arc to reach seq[1]
        dt = (1 - x[5]) * T[0] * DAY2SEC
        l = lambert_problem(r, r_P[1], dt, self.common_mu, False, False)
        v_end_l = l.get_v2()[0]
        v_beg_l = l.get_v1()[0]

        # First DSM occuring at time nu1*T1
        DV[0] = norm([a - b for a, b in zip(v_beg_l, v)])
        print("DSM magnitude: " + str(DV[0]) + "m/s")

        # 4 - And we proceed with each successive leg
        for i in range(1, self.__n_legs):
            print("\nleg no. " + str(i + 1) + ": " +
                  self.seq[i].name + " to " + self.seq[i + 1].name)
            print("Duration: " + str(T[i]) + "days")
            # Fly-by
            v_out = fb_prop(v_end_l, v_P[i], x[
                            8 + (i - 1) * 4] * self.seq[i].radius, x[7 + (i - 1) * 4], self.seq[i].mu_self)
            print(
                "Fly-by epoch: " + str(t_P[i]) + " (" + str(t_P[i].mjd2000) + " mjd2000) ")
            print(
                "Fly-by radius: " + str(x[8 + (i - 1) * 4]) + " planetary radii")
            # s/c propagation before the DSM
            r, v = propagate_lagrangian(
                r_P[i], v_out, x[9 + (i - 1) * 4] * T[i] * DAY2SEC, self.common_mu)
            print("DSM after " + str(x[9 + (i - 1) * 4] * T[i]) + " days")
            # Lambert arc to reach Earth during (1-nu2)*T2 (second segment)
            dt = (1 - x[9 + (i - 1) * 4]) * T[i] * DAY2SEC
            l = lambert_problem(r, r_P[i + 1], dt,
                                self.common_mu, False, False)
            v_end_l = l.get_v2()[0]
            v_beg_l = l.get_v1()[0]
            # DSM occuring at time nu2*T2
            DV[i] = norm([a - b for a, b in zip(v_beg_l, v)])
            print("DSM magnitude: " + str(DV[i]) + "m/s")

        # Last Delta-v
        print("\nArrival at " + self.seq[-1].name)
        DV[-1] = norm([a - b for a, b in zip(v_end_l, v_P[-1])])
        print(
            "Arrival epoch: " + str(t_P[-1]) + " (" + str(t_P[-1].mjd2000) + " mjd2000) ")
        print("Arrival Vinf: " + str(DV[-1]) + "m/s")
        print("Total mission time: " + str(sum(T) / 365.25) + " years")
예제 #34
0
    def plot(self, x, ax=None):
        """
        ax = prob.plot(x, ax=None)

        - x: encoded trajectory
        - ax: matplotlib axis where to plot. If None figure and axis will be created
        - [out] ax: matplotlib axis where to plot

        Plots the trajectory represented by a decision vector x on the 3d axis ax

        Example::

          ax = prob.plot(x)
        """
        import matplotlib as mpl
        from mpl_toolkits.mplot3d import Axes3D
        import matplotlib.pyplot as plt
        from pykep.orbit_plots import plot_planet, plot_lambert, plot_kepler

        if ax is None:
            mpl.rcParams['legend.fontsize'] = 10
            fig = plt.figure()
            axis = fig.gca(projection='3d')
        else:
            axis = ax

        axis.scatter(0, 0, 0, color='y')

        # 1 -  we 'decode' the chromosome recording the various times of flight
        # (days) in the list T and the cartesian components of vinf
        T, Vinfx, Vinfy, Vinfz = self._decode_times_and_vinf(x)

        # 2 - We compute the epochs and ephemerides of the planetary encounters
        t_P = list([None] * (self.__n_legs + 1))
        r_P = list([None] * (self.__n_legs + 1))
        v_P = list([None] * (self.__n_legs + 1))
        DV = list([None] * (self.__n_legs + 1))

        for i, planet in enumerate(self.seq):
            t_P[i] = epoch(x[0] + sum(T[0:i]))
            r_P[i], v_P[i] = planet.eph(t_P[i])
            plot_planet(planet, t0=t_P[i], color=(
                0.8, 0.6, 0.8), legend=True, units=AU, ax=axis)

        # 3 - We start with the first leg
        v0 = [a + b for a, b in zip(v_P[0], [Vinfx, Vinfy, Vinfz])]
        r, v = propagate_lagrangian(
            r_P[0], v0, x[5] * T[0] * DAY2SEC, self.common_mu)

        plot_kepler(r_P[0], v0, x[5] * T[0] * DAY2SEC, self.common_mu,
                    N=100, color='b', legend=False, units=AU, ax=axis)

        # Lambert arc to reach seq[1]
        dt = (1 - x[5]) * T[0] * DAY2SEC
        l = lambert_problem(r, r_P[1], dt, self.common_mu, False, False)
        plot_lambert(l, sol=0, color='r', legend=False, units=AU, ax=axis)
        v_end_l = l.get_v2()[0]
        v_beg_l = l.get_v1()[0]

        # First DSM occuring at time nu1*T1
        DV[0] = norm([a - b for a, b in zip(v_beg_l, v)])

        # 4 - And we proceed with each successive leg
        for i in range(1, self.__n_legs):
            # Fly-by
            v_out = fb_prop(v_end_l, v_P[i], x[
                            8 + (i - 1) * 4] * self.seq[i].radius, x[7 + (i - 1) * 4], self.seq[i].mu_self)
            # s/c propagation before the DSM
            r, v = propagate_lagrangian(
                r_P[i], v_out, x[9 + (i - 1) * 4] * T[i] * DAY2SEC, self.common_mu)
            plot_kepler(r_P[i], v_out, x[9 + (i - 1) * 4] * T[i] * DAY2SEC,
                        self.common_mu, N=100, color='b', legend=False, units=AU, ax=axis)
            # Lambert arc to reach Earth during (1-nu2)*T2 (second segment)
            dt = (1 - x[9 + (i - 1) * 4]) * T[i] * DAY2SEC

            l = lambert_problem(r, r_P[i + 1], dt,
                                self.common_mu, False, False)
            plot_lambert(l, sol=0, color='r', legend=False,
                         units=AU, N=1000, ax=axis)

            v_end_l = l.get_v2()[0]
            v_beg_l = l.get_v1()[0]
            # DSM occuring at time nu2*T2
            DV[i] = norm([a - b for a, b in zip(v_beg_l, v)])
        plt.show()
        return axis
예제 #35
0
    def __init__(self,
                 start=jpl_lp('earth'),
                 target=jpl_lp('venus'),
                 N_max=3,
                 tof=[20., 400.],
                 vinf=[0., 4.],
                 phase_free=True,
                 multi_objective=False,
                 t0=None):
        """
        prob = pykep.trajopt.pl2pl_N_impulses(start=jpl_lp('earth'), target=jpl_lp('venus'), N_max=3, tof=[20., 400.], vinf=[0., 4.], phase_free=True, multi_objective=False, t0=None)

        Args: 
            - start (``pykep.planet``): the starting planet
            - target (``pykep.planet``): the target planet
            - N_max (``int``): maximum number of impulses
            - tof (``list``): the box bounds [lower,upper] for the time of flight (days)
            - vinf (``list``): the box bounds [lower,upper] for each DV magnitude (km/sec)
            - phase_free (``bool``): when True, no randezvous condition are enforced and start and arrival anomalies will be free
            - multi_objective (``bool``):  when True, a multi-objective problem is constructed with DV and time of flight as objectives
            - t0 (``list``):  the box bounds on the launch window containing two pykep.epoch. This is not needed if phase_free is True.
        """

        # Sanity checks
        # 1) all planets need to have the same mu_central_body
        if (start.mu_central_body != target.mu_central_body):
            raise ValueError(
                'Starting and ending pykep.planet must have the same mu_central_body'
            )
        # 2) Number of impulses must be at least 2
        if N_max < 2:
            raise ValueError('Number of impulses N is less than 2')
        # 3) If phase_free is True, t0 does not make sense
        if (t0 is None and not phase_free):
            t0 = [epoch(0), epoch(1000)]
        if (t0 is not None and phase_free):
            raise ValueError('When phase_free is True no t0 can be specified')
        if (type(t0[0]) != type(epoch(0))):
            t0[0] = epoch(t0[0])
        if (type(t0[1]) != type(epoch(0))):
            t0[1] = epoch(t0[1])

        self.obj_dim = multi_objective + 1
        # We then define all class data members
        self.start = start
        self.target = target
        self.N_max = N_max
        self.phase_free = phase_free
        self.multi_objective = multi_objective
        self.vinf = [s * 1000 for s in vinf]

        self.__common_mu = start.mu_central_body

        # And we compute the bounds
        if phase_free:
            self._lb = [
                0, tof[0]
            ] + [1e-3, 0.0, 0.0, vinf[0] * 1000] * (N_max - 2) + [1e-3] + [0]
            self._ub = [
                2 * start.compute_period(epoch(0)) * SEC2DAY, tof[1]
            ] + [1.0 - 1e-3, 1.0, 1.0, vinf[1] * 1000] * (N_max - 2) + [
                1.0 - 1e-3
            ] + [2 * target.compute_period(epoch(0)) * SEC2DAY]
        else:
            self._lb = [t0[0].mjd2000, tof[0]] + \
                [1e-3, 0.0, 0.0, vinf[0] * 1000] * (N_max - 2) + [1e-3]
            self._ub = [t0[1].mjd2000, tof[1]] + \
                [1.0-1e-3, 1.0, 1.0, vinf[1] * 1000] * (N_max - 2) + [1.0-1e-3]
예제 #36
0
    def _compute_constraints_impl(self, x):
        # 1 - We decode the chromosome extracting the time of flights
        T = list([0] * (self.__n_legs))
        for i in range(self.__n_legs):
            T[i] = x[1 + i * 8]

        # 2 - We compute the epochs and ephemerides of the planetary encounters
        t_P = list([None] * (self.__n_legs + 1))
        r_P = list([None] * (self.__n_legs + 1))
        v_P = list([None] * (self.__n_legs + 1))

        for i, planet in enumerate(self.seq):
            t_P[i] = epoch(x[0] + sum(T[0:i]))
            r_P[i], v_P[i] = self.seq[i].eph(t_P[i])

        # 3 - We iterate through legs to compute mismatches and throttles
        # constraints
        ceq = list()
        cineq = list()
        m0 = self.__sc.mass
        for i in range(self.__n_legs):
            # First Leg
            v = [a + b for a, b in zip(v_P[i], x[(3 + i * 8):(6 + i * 8)])]
            x0 = sc_state(r_P[i], v, m0)
            v = [a + b for a, b in zip(v_P[i + 1], x[(6 + i * 8):(9 + i * 8)])]
            xe = sc_state(r_P[i + 1], v, x[2 + i * 8])
            throttles = x[(1 + 8 * self.__n_legs + 3 * sum(self.__n_seg[:i])):(
                1 + 8 * self.__n_legs + 3 * sum(self.__n_seg[:i]) +
                3 * self.__n_seg[i])]
            self.__leg.set(t_P[i], x0, throttles, t_P[i + 1], xe)
            # update mass!
            m0 = x[2 + 8 * i]
            ceq.extend(self.__leg.mismatch_constraints())
            cineq.extend(self.__leg.throttles_constraints())

        # Adding the boundary constraints
        # departure
        v_dep_con = (x[3]**2 + x[4]**2 + x[5]**2 -
                     self.__vinf_dep**2) / (EARTH_VELOCITY**2)
        # arrival
        v_arr_con = (x[6 +
                       (self.__n_legs - 1) * 8]**2 + x[7 +
                                                       (self.__n_legs - 1) * 8]
                     **2 + x[8 + (self.__n_legs - 1) * 8]**2 -
                     self.__vinf_arr**2) / (EARTH_VELOCITY**2)
        cineq.append(v_dep_con * 100)
        cineq.append(v_arr_con * 100)

        # We add the fly-by constraints
        for i in range(self.__n_legs - 1):
            DV_eq, alpha_ineq = fb_con(x[6 + i * 8:9 + i * 8],
                                       x[11 + i * 8:14 + i * 8],
                                       self.seq[i + 1])
            ceq.append(DV_eq / (EARTH_VELOCITY**2))
            cineq.append(alpha_ineq)

        # Making the mismatches non dimensional
        for i in range(self.__n_legs):
            ceq[0 + i * 7] /= AU
            ceq[1 + i * 7] /= AU
            ceq[2 + i * 7] /= AU
            ceq[3 + i * 7] /= EARTH_VELOCITY
            ceq[4 + i * 7] /= EARTH_VELOCITY
            ceq[5 + i * 7] /= EARTH_VELOCITY
            ceq[6 + i * 7] /= self.__sc.mass

        # We assemble the constraint vector
        retval = list()
        retval.extend(ceq)
        retval.extend(cineq)

        return retval