Exemple #1
0
    def __init__(self, gm, r, alt, rp, t, sc):
        """Initializes `TwoDimLLO2HEOGuess` class. """

        dep = TwoDimOrb(gm, a=(r + alt), e=0)
        arr = TwoDimOrb(gm, T=t, rp=rp)

        TwoDimHEOGuess.__init__(self, gm, r, dep, arr, sc)

        self.pow = PowConstRadius(gm, dep.a, dep.vp, self.ht.transfer.vp,
                                  sc.m0, sc.T_max, sc.Isp)
        self.pow.compute_final_time_states()

        self.tf = self.pow.tf + self.ht.tof

        self.insertion_burn = None
Exemple #2
0
    def __init__(self, gm, dep, arr):
        """Initializes `HohmannTransfer` class. """

        self.GM = gm
        self.depOrb = dep
        self.arrOrb = arr

        if self.depOrb.a < self.arrOrb.a:  # ascent
            self.ra = self.arrOrb.ra
            self.rp = self.depOrb.rp
        else:  # descent
            self.ra = self.depOrb.ra
            self.rp = self.arrOrb.rp

        self.transfer = TwoDimOrb(self.GM, ra=self.ra, rp=self.rp)
        self.tof = self.transfer.T / 2

        if self.depOrb.a < self.arrOrb.a:  # ascent
            self.dvp = self.transfer.vp - self.depOrb.vp
            self.dva = self.arrOrb.va - self.transfer.va
        else:  # descent
            self.dva = self.depOrb.va - self.transfer.va
            self.dvp = self.transfer.vp - self.arrOrb.vp

        self.r = self.theta = self.u = self.v = None
        self.states = self.controls = None
Exemple #3
0
    def compute_energy_mprop(self, r, u, v, m_coast):
        """Computes the specific energy of the spacecraft on the ballistic arc and the total propellant mass including
        the final insertion burn.

        Parameters
        ----------
        r : float
            Radius at the end of the first powered phase [m]
        u : float
            Radial velocity at the end of the first powered phase [m/s]
        v : float
            Tangential velocity at the end of the first powered phase [m/s]
        m_coast : float
            Spacecraft mass on the ballistic arc [kg]

        Returns
        -------
        en : float
            Specific energy of the spacecraft on the ballistic arc [m/s]
        m_prop : float
            Total propellant mass including the final insertion burn [kg]

        """

        en = TwoDimOrb.polar2energy(
            self.body.GM, r, u,
            v)  # specific energy on ballistic arc [m^2/s^2]
        va = (2 * (en + self.body.GM / self.nlp.guess.ht.arrOrb.ra)
              )**0.5  # ballistic arc apoapsis velocity [m/s]
        dva = self.guess.ht.arrOrb.va - va  # apoapsis dv [m/s]
        m_prop = self.sc.m0 - ImpulsiveBurn.tsiolkovsky_mf(
            m_coast, dva, self.sc.Isp)  # total propellant mass [kg]

        return en, m_prop
Exemple #4
0
    def __init__(self, body, db, case_id='final', db_exp=None, scaled=False):

        Reader.__init__(self, db, case_id=case_id, db_exp=db_exp)

        self.body = body

        if scaled:
            self.gm_res = 1.0
            self.rm_res = 1.0
            self.states_scalers = None
        else:
            self.gm_res = body.GM
            self.rm_res = body.R
            self.states_scalers = np.array(
                [body.R, 1.0, body.vc, body.vc, 1.0])

        self.phase_name = []

        for s in ['dep', 'coast', 'arr']:
            ph_name = '.'.join(['traj', s, 'timeseries'])
            self.phase_name.append(ph_name)

        self.tof, self.time, self.states, self.controls = self.get_time_series(
            self.case)

        if db_exp is not None:
            self.tof_exp, self.time_exp, self.states_exp, self.controls_exp = self.get_time_series(
                self.case_exp)
        else:
            self.tof_exp = self.time_exp = self.states_exp = self.controls_exp = None

        self.coe_inj = TwoDimOrb.polar2coe(self.gm_res, self.states[-1][-1, 0],
                                           self.states[-1][-1, 2],
                                           self.states[-1][-1, 3])
Exemple #5
0
    def __init__(self, gm, r, alt, rp, t, sc):
        """Initializes `TwoDimHEO2LLOGuess` class. """

        arr = TwoDimOrb(gm, a=(r + alt), e=0)
        dep = TwoDimOrb(gm, T=t, rp=rp)

        TwoDimGuess.__init__(self, gm, r, dep, arr, sc)

        self.deorbit_burn = ImpulsiveBurn(sc, self.ht.dva)
        self.pow = PowConstRadius(gm,
                                  arr.a,
                                  self.ht.transfer.vp,
                                  arr.vp,
                                  self.deorbit_burn.mf,
                                  sc.T_max,
                                  sc.Isp,
                                  t0=self.ht.tof)
        self.pow.compute_final_time_states()

        self.tf = self.pow.tf
Exemple #6
0
    def compute_solution(self, nb=200):
        """Retrieves the optimization results and computes the spacecraft states along the ballistic arc as well as the
        final insertion burn.

        Parameters
        ----------
        nb : int, optional
            Number of points in which the spacecraft states along the ballistic arc are computed. Default is ``200``

        """

        # states and COEs at the end of the departure burn
        states_end = self.states[-1]
        a, e, h, ta = TwoDimOrb.polar2coe(self.gm_res, states_end[0],
                                          states_end[2], states_end[3])

        # coasting orbit in dimensional units
        if np.isclose(self.gm_res, 1.0):
            self.transfer = TwoDimOrb(self.body.GM, a=a * self.body.R, e=e)
        else:
            self.transfer = TwoDimOrb(self.body.GM, a=a, e=e)

        # finite dV at departure [m/s]
        self.dv_dep = ImpulsiveBurn.tsiolkovsky_dv(self.sc.m0, states_end[-1],
                                                   self.sc.Isp)

        # impulsive dV at arrival [m/s]
        sc = deepcopy(self.sc)
        sc.m0 = states_end[-1]
        self.insertion_burn = ImpulsiveBurn(
            sc, self.guess.ht.arrOrb.va - self.transfer.va)

        # time and states along transfer orbit
        t, states = TwoDimOrb.propagate(self.gm_res, a, e, ta, np.pi, nb)

        # adjust time
        t_pow_end = self.time[-1, -1]
        t_coast_start = t[0, 0]
        t_coast_end = t[-1, 0]
        tof_coast = t_coast_end - t_coast_start

        self.tof = [self.tof, tof_coast]
        self.time = [self.time, (t - t_coast_start) + t_pow_end]

        # add mass
        m = np.vstack((states_end[-1] * np.ones(
            (len(t) - 1, 1)), [self.insertion_burn.mf]))
        states = np.hstack((states, m))

        # stack states and controls
        self.states = [self.states, states]
        self.controls = [self.controls, np.zeros((len(t), 2))]
        self.controls[-1][-1, 0] = self.controls[0][0, 0]

        # adjust theta
        dtheta = ta - self.states[0][-1, 1]
        self.states[0][:, 1] = self.states[0][:, 1] + dtheta
        if self.states_exp is not None:
            self.states_exp[:, 1] = self.states_exp[:, 1] + dtheta
Exemple #7
0
    def __init__(self, gm, r, alt, sc):
        """Initializes `TwoDimAscGuess` class. """

        dep = TwoDimOrb(gm, a=r, e=0)
        arr = TwoDimOrb(gm, a=(r + alt), e=0)

        TwoDimGuess.__init__(self, gm, r, dep, arr, sc)

        self.pow1 = PowConstRadius(gm, r, 0.0, self.ht.transfer.vp, sc.m0,
                                   sc.T_max, sc.Isp)
        self.pow1.compute_final_time_states()

        self.pow2 = PowConstRadius(gm, (r + alt),
                                   self.ht.transfer.va,
                                   self.ht.arrOrb.va,
                                   self.pow1.mf,
                                   sc.T_max,
                                   sc.Isp,
                                   t0=(self.pow1.tf + self.ht.tof),
                                   theta0=(self.pow1.thetaf + np.pi))
        self.pow2.compute_final_time_states()

        self.tf = self.pow2.tf
Exemple #8
0
    def __init__(self, gm, r, alt, rp, t, sc):

        dep = TwoDimOrb(gm, a=(r + alt), e=0)
        arr = TwoDimOrb(gm, T=t, rp=rp)

        TwoDimGuess.__init__(self, gm, r, dep, arr, sc)

        self.pow1 = PowConstRadius(gm, (r + alt), dep.vp, self.ht.transfer.vp,
                                   sc.m0, sc.T_max, sc.Isp)
        self.pow1.compute_final_time_states()

        self.pow2 = PowConstRadius(gm,
                                   arr.ra,
                                   self.ht.transfer.va,
                                   arr.va,
                                   self.pow1.mf,
                                   sc.T_max,
                                   sc.Isp,
                                   t0=(self.pow1.tf + self.ht.tof),
                                   theta0=(self.pow1.thetaf + np.pi))
        self.pow2.compute_final_time_states()

        self.tf = self.pow2.tf
Exemple #9
0
    def get_solutions(self, explicit=True, scaled=False):
        """Access the simulation solution.

        Parameters
        ----------
        explicit : bool
            Computes also the explicit simulation. Default is ``True``
        scaled : bool
            Scales the simulation results. Default is ``False``

        """

        TwoDimAnalyzer.get_solutions(self, explicit=explicit, scaled=scaled)

        coe = TwoDimOrb.polar2coe(self.gm_res, self.states[0][-1, 0],
                                  self.states[0][-1, 2], self.states[0][-1, 3])

        self.transfer = TwoDimOrb(self.body.GM,
                                  a=coe[0] * self.body.R / self.rm_res,
                                  e=coe[1])
        for i in [0, 2]:
            self.dv.append(
                self.sc.Isp * g0 *
                np.log(self.states[i][0, -1] / self.states[i][-1, -1]))
Exemple #10
0
    def plot(self):
        """Plots the states and controls resulting from the simulation and the ones from the explicit computation in
            time. The semi-major axis and the eccentricity of the HEO are also displayed.
        """

        coe_inj = TwoDimOrb.polar2coe(self.gm_res, self.states[-1][-1, 0],
                                      self.states[-1][-1, 2],
                                      self.states[-1][-1, 3])

        dtheta = coe_inj[-1] - self.states[-1][-1, 1]

        sol_plot = TwoDimMultiPhaseSolPlot(self.rm_res,
                                           self.time,
                                           self.states,
                                           self.controls,
                                           self.time_exp,
                                           self.states_exp,
                                           a=self.nlp.guess.ht.arrOrb.a *
                                           (self.rm_res / self.body.R),
                                           e=self.nlp.guess.ht.arrOrb.e,
                                           dtheta=dtheta)
        sol_plot.plot()
Exemple #11
0
class TwoDim3PhasesLLO2HEOAnalyzer(TwoDimMultiPhasesLLO2HEOAnalyzer):
    """Analyzer class defines the methods to analyze the results of a two dimensional 3 phases LLO to HEO simulation.

     It gives the results of an optimal trajectory from a Low Lunar Orbit of chosen altitude to an High Elliptical
     Orbit which can represent a transposition of an Halo orbit in 2D. The trajectory is modeled as the succession
     of three different phases: a first powered phase for departure, a coasting arch and a final powered phase for
     the injection.

    Parameters
    ----------
    body : Primary
        Instance of `Primary` class describing the central attracting body
    sc : Spacecraft
        Instance of `Spacecraft` class describing the spacecraft characteristics
        alt : float
    alt : float
        Value of the initial LLO altitude [m]
    rp : float
        Value for the target HEO periselene radius [m]
    t : float
        Value for the guessed trajectory time of flight [s]
    t_bounds : float
        Value for the time of flight bounds [-]
    method : str
        NLP transcription method
    nb_seg : int
        Number of segments for the transcription
    order : int
        Transcription order
    solver : str
        NLP solver
    snopt_opts : dict
        Sets some SNOPT's options. Default is ``None``
    rec_file : str
        Directory path for the solution recording file. Default is ``None``
    check_partials : bool
        Checking of partial derivatives. Default is ``False``

    Attributes
    ----------
    body : Primary
        Instance of `Primary` class describing the central attracting body
    sc : Spacecraft
        Instance of `Spacecraft` class describing the spacecraft characteristics
    phase_name : str
        Describes the phase name in case of multi-phase trajectories. Can be ``dep``, ``coast`` or ``arr``.
    nlp : NLP
        Instance of `NLP` object describing the type of Non Linear Problem solver used
    tof : float
        Value of the time of flight resulting by the simulation [s]
    tof_exp : float
        Value of the time of flight of the explicit simulation [s]
    err : float
        Value of the error between the optimized simulation results and the explicit simulation results
    rm_res : float
        Value of the central body radius [-] or [m]
    states_scalers : ndarray
        Reference values of the states with which perform the scaling
    controls_scalers : ndarray
        Reference values of the controls with which perform the scaling

    """
    def __init__(self,
                 body,
                 sc,
                 alt,
                 rp,
                 t,
                 t_bounds,
                 method,
                 nb_seg,
                 order,
                 solver,
                 snopt_opts=None,
                 rec_file=None,
                 check_partials=False):
        """Initializes the `TwoDim3PhasesLLO2HEOAnalyzer` class variables. """

        TwoDimMultiPhasesLLO2HEOAnalyzer.__init__(self, body, sc)

        self.phase_name = ('dep', 'coast', 'arr')

        self.nlp = TwoDim3PhasesLLO2HEONLP(body,
                                           sc,
                                           alt,
                                           rp,
                                           t, (-np.pi / 2, np.pi / 2),
                                           t_bounds,
                                           method,
                                           nb_seg,
                                           order,
                                           solver,
                                           self.phase_name,
                                           snopt_opts=snopt_opts,
                                           rec_file=rec_file,
                                           check_partials=check_partials)

    def get_time_series(self, p, scaled=False):
        """Access the time series of the problem.

        Parameters
        ----------
        p : Problem
            Instance of `Problem` class
        scaled : bool
            Scales the simulation results

        Returns
        -------
        tof : float
            Time of flight resulting from the optimized simulation phase [-] or [s]
        t : ndarray
            Time of flight time series for the optimized simulation phase [-] or [s]
        states : ndarray
            States time series for the optimized simulation phase
        controls : ndarray
            Controls time series for the optimized simulation phase

        """
        tof = []
        t = []
        states = []
        controls = []

        for i in range(3):
            tofi, ti, si, ci = self.get_time_series_phase(
                p, self.nlp.phase_name[i], scaled=scaled)

            tof.append(tofi)
            t.append(ti)
            states.append(si)
            controls.append(ci)

        return tof, t, states, controls

    def get_solutions(self, explicit=True, scaled=False):
        """Access the simulation solution.

        Parameters
        ----------
        explicit : bool
            Computes also the explicit simulation. Default is ``True``
        scaled : bool
            Scales the simulation results. Default is ``False``

        """

        TwoDimAnalyzer.get_solutions(self, explicit=explicit, scaled=scaled)

        coe = TwoDimOrb.polar2coe(self.gm_res, self.states[0][-1, 0],
                                  self.states[0][-1, 2], self.states[0][-1, 3])

        self.transfer = TwoDimOrb(self.body.GM,
                                  a=coe[0] * self.body.R / self.rm_res,
                                  e=coe[1])
        for i in [0, 2]:
            self.dv.append(
                self.sc.Isp * g0 *
                np.log(self.states[i][0, -1] / self.states[i][-1, -1]))

    def __str__(self):
        """Prints info on the `TwoDim3PhasesLLO2HEOAnalyzer`.

        Returns
        -------
        s : str
            Info on `TwoDim3PhasesLLO2HEOAnalyzer`

        """

        if np.isclose(self.gm_res, 1.0):
            time_scaler = self.body.tc
        else:
            time_scaler = 1.0

        lines = [
            '\n{:^50s}'.format('2D Transfer trajectory from LLO to HEO:'),
            self.nlp.guess.__str__(), '\n{:^50s}'.format('Coasting orbit:'),
            self.transfer.__str__(), '\n{:^50s}'.format('Optimal transfer:'),
            '\n{:<25s}{:>20.6f}{:>5s}'.format(
                'Propellant fraction:',
                1 - self.states[-1][-1, -1] / self.sc.m0,
                ''), '{:<25s}{:>20.6f}{:>5s}'.format(
                    'Time of flight:',
                    sum(self.tof) * time_scaler / 86400,
                    'days'), '\n{:^50s}'.format('Departure burn:'),
            '\n{:<25s}{:>20.6f}{:>5s}'.format('Impulsive dV:',
                                              self.nlp.guess.pow1.dv_inf,
                                              'm/s'),
            '{:<25s}{:>20.6f}{:>5s}'.format('Finite dV:', self.dv[0], 'm/s'),
            '{:<25s}{:>20.6f}{:>5s}'.format('Burn time:',
                                            self.tof[0] * time_scaler, 's'),
            '{:<25s}{:>20.6f}{:>5s}'.format(
                'Propellant fraction:',
                1 - self.states[0][-1, -1] / self.sc.m0,
                ''), '\n{:^50s}'.format('Injection burn:'),
            '\n{:<25s}{:>20.6f}{:>5s}'.format('Impulsive dV:',
                                              self.nlp.guess.pow2.dv_inf,
                                              'm/s'),
            '{:<25s}{:>20.6f}{:>5s}'.format('Finite dV:', self.dv[-1], 'm/s'),
            '{:<25s}{:>20.6f}{:>5s}'.format('Burn time:',
                                            self.tof[-1] * time_scaler, 's'),
            '{:<25s}{:>20.6f}{:>5s}'.format(
                'Propellant fraction:',
                1 - self.states[-1][-1, -1] / self.states[-1][0, -1], ''),
            TwoDimAnalyzer.__str__(self)
        ]

        s = '\n'.join(lines)

        return s
Exemple #12
0
class TwoDimLLO2ApoAnalyzer(TwoDimAscAnalyzer):
    """TwoDimLLO2HEOAnalyzer class defines the methods to analyze the results of a two dimensional simulation from a
    Low Lunar Orbit to an Highly Elliptical Orbit.

    The Highly Elliptical Orbit is chosen as first planar approximation of a three-dimensional Near Rectilinear Halo
    Orbit. The optimal control problem is solved for a single phase trajectory performed at constant thrust that
    injects the spacecraft from the Low Lunar Orbit to an intermediate transfer trajectory whose aposelene radius
    coincides with the one of the target Highly Elliptical Orbit. The final insertion manoeuvre is then modelled as
    an ideal impulsive burn due to its limited dV magnitude.

    Parameters
    ----------
    body : Primary
        Instance of `Primary` class describing the central attracting body
    sc : Spacecraft
        Instance of `Spacecraft` class describing the spacecraft characteristics
    alt : float
        Value of the final orbit altitude [m]
    rp : float
        Value for the target HEO periselene radius [m]
    t : float
        Value for the target HEO period [s]
    t_bounds : float
        Value for the time of flight bounds [-]
    method : str
        NLP transcription method
    nb_seg : int
        Number of segments for the transcription
    order : int
        Transcription order
    solver : str
        NLP solver
    snopt_opts : dict
        Sets some SNOPT's options. Default is ``None``
    rec_file : str
        Directory path for the solution recording file. Default is ``None``
    check_partials : bool
        Checking of partial derivatives. Default is ``False``

    Attributes
    ----------
    body : Primary
        Instance of `Primary` class describing the central attracting body
    sc : Spacecraft
        Instance of `Spacecraft` class describing the spacecraft characteristics
    phase_name : str
        Describes the phase name in case of multi-phase trajectories
    nlp : NLP
        Instance of `NLP` object describing the type of Non Linear Problem solver used
    tof : float
        Value of the time of flight resulting by the simulation [s]
    tof_exp : float
        Value of the time of flight of the explicit simulation [s]
    err : float
        Value of the error between the optimized simulation results and the explicit simulation results
    rm_res : float
        Value of the central body radius [- or m]
    states_scalers = ndarray
        Reference values of the states with which perform the scaling
    controls_scalers : ndarray
        Reference values of the controls with which perform the scaling
    alt : float
        Value of the final orbit altitude [m]
    phase_name : str
        Name assigned to the problem phase
    transfer : HohmannTransfer
        Instance of `HohmannTransfer` computing the keplerian parameters of the transfer orbit
    insertion_burn : ImpulsiveBurn
        Instance of `ImpulsiveBurn` defining the delta v required for an impulsive burn
    dv_dep : float
        Delta v required for a manoeuvre [m/s]

    """
    def __init__(self,
                 body,
                 sc,
                 alt,
                 rp,
                 t,
                 t_bounds,
                 method,
                 nb_seg,
                 order,
                 solver,
                 snopt_opts=None,
                 rec_file=None,
                 check_partials=False):
        """Initializes the `TwoDimLLO2ApoAnalyzer` class variables. """

        TwoDimAscAnalyzer.__init__(self, body, sc, alt)

        self.nlp = TwoDimLLO2ApoNLP(body,
                                    sc,
                                    alt,
                                    rp,
                                    t, (-np.pi / 2, np.pi / 2),
                                    t_bounds,
                                    method,
                                    nb_seg,
                                    order,
                                    solver,
                                    self.phase_name,
                                    snopt_opts=snopt_opts,
                                    rec_file=rec_file,
                                    check_partials=check_partials)

        self.transfer = self.insertion_burn = self.dv_dep = None
        self.guess = self.nlp.guess  # save the initial initial guess at analyzer level

    def compute_solution(self, nb=200):
        """Retrieves the optimization results and computes the spacecraft states along the ballistic arc as well as the
        final insertion burn.

        Parameters
        ----------
        nb : int, optional
            Number of points in which the spacecraft states along the ballistic arc are computed. Default is ``200``

        """

        # states and COEs at the end of the departure burn
        states_end = self.states[-1]
        a, e, h, ta = TwoDimOrb.polar2coe(self.gm_res, states_end[0],
                                          states_end[2], states_end[3])

        # coasting orbit in dimensional units
        if np.isclose(self.gm_res, 1.0):
            self.transfer = TwoDimOrb(self.body.GM, a=a * self.body.R, e=e)
        else:
            self.transfer = TwoDimOrb(self.body.GM, a=a, e=e)

        # finite dV at departure [m/s]
        self.dv_dep = ImpulsiveBurn.tsiolkovsky_dv(self.sc.m0, states_end[-1],
                                                   self.sc.Isp)

        # impulsive dV at arrival [m/s]
        sc = deepcopy(self.sc)
        sc.m0 = states_end[-1]
        self.insertion_burn = ImpulsiveBurn(
            sc, self.guess.ht.arrOrb.va - self.transfer.va)

        # time and states along transfer orbit
        t, states = TwoDimOrb.propagate(self.gm_res, a, e, ta, np.pi, nb)

        # adjust time
        t_pow_end = self.time[-1, -1]
        t_coast_start = t[0, 0]
        t_coast_end = t[-1, 0]
        tof_coast = t_coast_end - t_coast_start

        self.tof = [self.tof, tof_coast]
        self.time = [self.time, (t - t_coast_start) + t_pow_end]

        # add mass
        m = np.vstack((states_end[-1] * np.ones(
            (len(t) - 1, 1)), [self.insertion_burn.mf]))
        states = np.hstack((states, m))

        # stack states and controls
        self.states = [self.states, states]
        self.controls = [self.controls, np.zeros((len(t), 2))]
        self.controls[-1][-1, 0] = self.controls[0][0, 0]

        # adjust theta
        dtheta = ta - self.states[0][-1, 1]
        self.states[0][:, 1] = self.states[0][:, 1] + dtheta
        if self.states_exp is not None:
            self.states_exp[:, 1] = self.states_exp[:, 1] + dtheta

    def get_solutions(self, explicit=True, scaled=False, nb=200):
        """Access the simulation solution.

        Parameters
        ----------
        explicit : bool
            Computes also the explicit simulation. Default is ``True``
        scaled : bool
            Scales the simulation results. Default is ``False``
        nb : int
            Number of points where the coasting arch is computed

        """

        TwoDimAscAnalyzer.get_solutions(self, explicit=explicit, scaled=scaled)

        self.compute_solution(nb=nb)

    def plot(self):
        """Plots the states and controls resulting from the simulation and the ones from the explicit computation in
        time. The semi-major axis and the eccentricity of the HEO are also displayed.

        """

        states_plot = TwoDimStatesTimeSeries(self.rm_res, self.time[0],
                                             self.states[0], self.time_exp,
                                             self.states_exp)

        if np.isclose(self.rm_res, 1.0):
            controls_plot = TwoDimControlsTimeSeries(self.time[0],
                                                     self.controls[0],
                                                     units=('-', '-'),
                                                     threshold=None)
        else:
            controls_plot = TwoDimControlsTimeSeries(self.time[0],
                                                     self.controls[0],
                                                     threshold=None)

        sol_plot = TwoDimMultiPhaseSolPlot(self.rm_res,
                                           self.time,
                                           self.states,
                                           self.controls,
                                           self.time_exp,
                                           self.states_exp,
                                           a=self.guess.ht.arrOrb.a *
                                           (self.rm_res / self.body.R),
                                           e=self.guess.ht.arrOrb.e)

        states_plot.plot()
        controls_plot.plot()
        sol_plot.plot()

    def __str__(self):
        """Prints info on the `TwoDimLLO2ApoAnalyzer`.

        Returns
        -------
        s : str
            Info on `TwoDimLLO2ApoAnalyzer`

        """

        if np.isclose(self.gm_res, 1.0):
            time_scaler = self.body.tc
        else:
            time_scaler = 1.0

        lines = [
            '\n{:^50s}'.format('2D Transfer trajectory from LLO to HEO:'),
            self.guess.__str__(),
            '\n{:^50s}'.format('Optimal coasting phase:'),
            self.transfer.__str__(),
            '\n{:^50s}'.format('Optimal powered phases:'),
            '\n{:<25s}{:>20.6f}{:>5s}'.format(
                'Propellant fraction:',
                1 - self.insertion_burn.mf / self.sc.m0,
                ''), '{:<25s}{:>20.6f}{:>5s}'.format(
                    'Time of flight:',
                    sum(self.tof) * time_scaler / 86400,
                    'days'), '\n{:^50s}'.format('Departure burn:'),
            '\n{:<25s}{:>20.6f}{:>5s}'.format('Impulsive dV:',
                                              self.guess.pow.dv_inf, 'm/s'),
            '{:<25s}{:>20.6f}{:>5s}'.format('Finite dV:', self.dv_dep, 'm/s'),
            '{:<25s}{:>20.6f}{:>5s}'.format('Burn time:',
                                            self.tof[0] * time_scaler, 's'),
            '{:<25s}{:>20.6f}{:>5s}'.format(
                'Propellant fraction:',
                1 - self.states[0][-1, -1] / self.sc.m0,
                ''), '\n{:^50s}'.format('Injection burn:'),
            '\n{:<25s}{:>20.6f}{:>5s}'.format('Impulsive dV:',
                                              self.insertion_burn.dv, 'm/s'),
            '{:<25s}{:>20.6f}{:>5s}'.format(
                'Propellant fraction:', self.insertion_burn.dm / self.sc.m0,
                ''),
            TwoDimAnalyzer.__str__(self)
        ]

        s = '\n'.join(lines)

        return s
Exemple #13
0
    def sampling(self,
                 body,
                 isp_lim,
                 twr_lim,
                 alt,
                 alt_p,
                 alt_switch,
                 theta,
                 tof,
                 t_bounds,
                 method,
                 nb_seg,
                 order,
                 solver,
                 nb_samp,
                 samp_method='lhs',
                 criterion='m',
                 snopt_opts=None):
        """Compute a new set of training data starting from a given sampling grid.

        Parameters
        ----------
        body : Primary
            Central attracting body
        isp_lim : iterable
            Specific impulse lower and upper limits [s]
        twr_lim : iterable
            Thrust/weight ratio lower and upper limits [-]
        alt : float
            Orbit altitude [m]
        alt_p : float
            Periapsis altitude where the final powered descent is initiated [m]
        alt_switch : float
            Altitude at which the final vertical descent is triggered [m]
        theta : float
            Guessed spawn angle [rad]
        tof : iterable
            Guessed time of flight for the two phases [s]
        t_bounds : iterable
            Time of flight lower and upper bounds expressed as fraction of `tof`
        method : str
            Transcription method used to discretize the continuous time trajectory into a finite set of nodes,
            allowed ``gauss-lobatto``, ``radau-ps`` and ``runge-kutta``
        nb_seg : int or iterable
            Number of segments in which each phase is discretized
        order : int or iterable
            Transcription order within each phase, must be odd
        solver : str
            NLP solver, must be supported by OpenMDAO
        nb_samp : iterable
            Total number of sampling points
        samp_method : str, optional
            Sampling scheme, ``lhs`` for Latin Hypercube Sampling or ``full`` for Full-Factorial Sampling.
            Default is ``lhs``
        criterion : str, optional
            Criterion used to construct the LHS design among ``center``, ``maximin``, ``centermaximin``,
            ``correlation``, ``c``, ``m``, ``cm``, ``corr``, ``ese``. ``c``, ``m``, ``cm`` and ``corr`` are
            abbreviations of ``center``, ``maximin``, ``centermaximin`` and ``correlation``, ``respectively``.
            Default is ``m``
        snopt_opts : dict or None, optional
            SNOPT optional settings expressed as key-value pairs. Default is None

        """

        self.compute_grid(isp_lim,
                          twr_lim,
                          nb_samp,
                          samp_method=samp_method,
                          criterion=criterion)

        ht = HohmannTransfer(body.GM,
                             TwoDimOrb(body.GM, a=(body.R + alt), e=0.0),
                             TwoDimOrb(body.GM, a=(body.R + alt_p), e=0.0))

        for i in range(nb_samp):

            sc = Spacecraft(self.x_samp[i, 0], self.x_samp[i, 1], g=body.g)
            deorbit_burn = ImpulsiveBurn(sc, ht.dva)
            nlp = TwoDimDescTwoPhasesNLP(body,
                                         deorbit_burn.sc,
                                         alt,
                                         alt_switch,
                                         ht.transfer.vp,
                                         theta, (0.0, np.pi),
                                         tof,
                                         t_bounds,
                                         method,
                                         nb_seg,
                                         order,
                                         solver, ('free', 'vertical'),
                                         snopt_opts=snopt_opts)

            self.m_prop[i, 0], self.failures[i, 0] = self.solve(nlp, i)
Exemple #14
0
    def solve(body, sc, alt, t_bounds, method, nb_seg, order, solver, snopt_opts=None, u_bound=None, **kwargs):
        """Solve the NLP for the i-th `twr` and k-th `Isp` values.

        Parameters
        ----------
        body : Primary
            Central attracting body
        sc : Spacecraft
            Spacecraft object characterized by the i-th `twr` and k-th `Isp` values
        alt : float
            Orbit altitude [m]
        t_bounds : iterable
            Time of flight lower and upper bounds expressed as fraction of `tof`
        method : str
            Transcription method used to discretize the continuous time trajectory into a finite set of nodes,
            allowed ``gauss-lobatto``, ``radau-ps`` and ``runge-kutta``
        nb_seg : int
            Number of segments in which the phase is discretized
        order : int
            Transcription order within the phase, must be odd
        solver : str
            NLP solver, must be supported by OpenMDAO
        snopt_opts : dict or None, optional
            SNOPT optional settings expressed as key-value pairs. Default is None
        u_bound : str, optional
            Specify the bounds on the radial velocity along the transfer as ``lower``, ``upper`` or ``None``.
            Default is ``None``

        Other Parameters
        ----------------
        alt_p : float
            Periapsis altitude where the final powered descent is initiated [m]
        theta : float
            Guessed spawn angle [rad]
        tof : float
            Guessed time of flight [s]

        Returns
        -------
        m_prop : float
            Propellant fraction [-]
        f : bool
            Failure status

        """

        if 'alt_p' in kwargs:
            alt_p = kwargs['alt_p']
        else:
            alt_p = alt

        dep = TwoDimOrb(body.GM, a=(body.R + alt), e=0.0)
        arr = TwoDimOrb(body.GM, a=(body.R + alt_p), e=0.0)

        ht = HohmannTransfer(body.GM, dep, arr)
        deorbit_burn = ImpulsiveBurn(sc, ht.dva)

        nlp = TwoDimDescConstNLP(body, deorbit_burn.sc, alt_p, ht.transfer.vp, kwargs['theta'], (0.0, 1.5 * np.pi),
                                 kwargs['tof'], t_bounds, method, nb_seg, order, solver, 'powered',
                                 snopt_opts=snopt_opts, u_bound=u_bound)

        f = nlp.p.run_driver()
        nlp.cleanup()
        m_prop = 1. - nlp.p.get_val(nlp.phase_name + '.timeseries.states:m')[-1, -1]

        return m_prop, f