示例#1
0
文件: frame.py 项目: rev0nat/SMS
def itrs_gcrs_single(itrs):
  """ Transformation ITRS to GCRS.
  """

  utc = TimeScalesFactory.getUTC()
  date = itrs.index[0]
  X = float(itrs['x[m]'][0])
  Y = float(itrs['y[m]'][0])
  Z = float(itrs['z[m]'][0])
  Vx = float(itrs['vx[m/s]'][0])
  Vy = float(itrs['vy[m/s]'][0])
  Vz = float(itrs['vz[m/s]'][0])
  ok_date = AbsoluteDate(date.year, date.month, date.day, date.hour, date.minute,
                         date.second + float(date.microsecond) / 1000000., utc)
  PV_coordinates = PVCoordinates(Vector3D(X, Y, Z), Vector3D(Vx, Vy, Vz))
  start_state = TimeStampedPVCoordinates(ok_date, PV_coordinates)
  state_itrf = AbsolutePVCoordinates(itrf, start_state)
  state_gcrf = AbsolutePVCoordinates(gcrf, state_itrf.getPVCoordinates(gcrf))
  pos = state_gcrf.position
  vel = state_gcrf.velocity
  X = pos.getX()
  Y = pos.getY()
  Z = pos.getZ()
  Vx = vel.getX()
  Vy = vel.getY()
  Vz = vel.getZ()
  dframe = pd.DataFrame({'x[m]': [X], 'y[m]': [Y], 'z[m]': [Z], 'vx[m/s]': [Vx], 'vy[m/s]': [Vy], 'vz[m/s]': [Vz]}, index=itrs.index)

  return dframe
示例#2
0
def orekit_state(x0):
    if type(x0) == np.ndarray:
        x0 = [xi.item() for xi in x0]

    r = Vector3D(*(x0[0:3]))
    v = Vector3D(*(x0[3:6]))
    return PVCoordinates(r, v)
示例#3
0
def validate_elliptic_propagation():
    # Orbit initial state vectors and time of flight
    rx_0, ry_0, rz_0 = 1131.340e3, -2282.343e3, 6672.423e3
    vx_0, vy_0, vz_0 = -5.64305e3, 4.30333e3, 2.42879e3
    tof = 1.5 * 3600

    # Build the initial Orekit orbit
    k = C.IAU_2015_NOMINAL_EARTH_GM
    r0_vec = Vector3D(rx_0, ry_0, rz_0)
    v0_vec = Vector3D(vx_0, vy_0, vz_0)
    rv_0 = PVCoordinates(r0_vec, v0_vec)
    epoch_00 = AbsoluteDate.J2000_EPOCH
    gcrf_frame = FramesFactory.getGCRF()
    ss0_orekit = KeplerianOrbit(rv_0, gcrf_frame, epoch_00, k)
    orekit_propagator = KeplerianPropagator(ss0_orekit)
    ssf_orekit = orekit_propagator.propagate(
        epoch_00.shiftedBy(tof)).getOrbit()

    # Build poliastro orbit
    r0_vec = [rx_0, ry_0, rz_0] * u.m
    v0_vec = [vx_0, vy_0, vz_0] * u.m / u.s
    ss0_poliastro = Orbit.from_vectors(Earth, r0_vec, v0_vec)
    ssf_poliastro = ss0_poliastro.propagate(tof * u.s)

    # Retrieve Orekit final state vectors
    r_orekit = ssf_orekit.getPVCoordinates().position.toArray() * u.m
    v_orekit = ssf_orekit.getPVCoordinates().velocity.toArray() * u.m / u.s

    # Retrieve poliastro final state vectors
    r_poliastro, v_poliastro = ssf_poliastro.rv()

    # Assert final state vectors
    assert_quantity_allclose(r_poliastro, r_orekit, atol=10 * u.m)
    assert_quantity_allclose(v_poliastro, v_orekit, rtol=1e-5)
示例#4
0
    def setup_spacecraft(self, spacecraft=None, oneshot=False):
        """Create Spacecraft and respective blender object."""

        sc_state = None
        sc_rot_state = None
        if spacecraft is None:
            sssb_state = self.sssb.get_state(self.encounter_date)
            sc_state = sc.Spacecraft.calc_encounter_state(sssb_state,
                                                       self.minimum_distance,
                                                       self.relative_velocity,
                                                       self.with_terminator,
                                                       self.with_sunnyside)
        else:
            if 'r' in spacecraft:
                sc_state = PVCoordinates(Vector3D(spacecraft['r']), 
                                         Vector3D(spacecraft.get('v', [0.0, 0.0, 0.0])))
            if 'angleaxis' in spacecraft:
                sc_pxpz_rot = Rotation(Vector3D(spacecraft['angleaxis'][1:4]),
                                       spacecraft['angleaxis'][0],
                                       RotationConvention.FRAME_TRANSFORM)

                # transform camera where +x is forward and +z is up into -z is forward and +y is up
                mzpy_rot = self.pxpz_to_mzpy(sc_pxpz_rot)
                sc_rot_state = AngularCoordinates(mzpy_rot, Vector3D(0., 0., 0.))

        self.spacecraft = sc.Spacecraft("CI",
                                     self.mu_sun,
                                     sc_state,
                                     self.encounter_date,
                                     rot_state=sc_rot_state,
                                     oneshot=oneshot)
示例#5
0
    def change_initial_conditions(self, new_state, new_epoch, new_mass):
        """Change the initial conditions given to the propagator without initializing it again.

        Args:
            initial_state (Cartesian): New initial state of the satellite in cartesian coordinates.
            epoch (datetime.datetime): New starting date of the propagator.
            mass (float64): New satellite mass.

        """
        # Create position and velocity vectors as Vector3D
        p = Vector3D(
            1e3,  # convert to [m]
            Vector3D(float(new_state.R[0]), float(new_state.R[1]),
                     float(new_state.R[2])))
        v = Vector3D(
            1e3,  # convert to [m/s]
            Vector3D(float(new_state.V[0]), float(new_state.V[1]),
                     float(new_state.V[2])))

        # Extract frame from initial/pre-propagated state
        orbit_frame = self._propagator._propagator_num.getInitialState(
        ).getFrame()

        orekit_date = to_orekit_date(new_epoch)

        # Evaluate new initial orbit
        initialOrbit = CartesianOrbit(PVCoordinates(p, v), orbit_frame,
                                      orekit_date, Cst.WGS84_EARTH_MU)

        # Create new spacecraft state
        newSpacecraftState = SpacecraftState(initialOrbit, new_mass)

        # Rewrite propagator initial conditions
        self._propagator._propagator_num.setInitialState(newSpacecraftState)
示例#6
0
    def __init__(self, name, mu, trj, att, model_file=None):
        """Currently hard implemented for Didymos."""
        super().__init__(name, model_file=model_file)

        date = trj["date"]
        trj_date = AbsoluteDate(int(date["year"]), int(date["month"]),
                                int(date["day"]), int(date["hour"]),
                                int(date["minutes"]), float(date["seconds"]),
                                self.timescale)

        # rotation axis
        self.axis_ra = math.radians(att["RA"]) if "RA" in att else 0.
        self.axis_dec = math.radians(
            att["Dec"]) if "Dec" in att else math.pi / 2

        # rotation offset, zero longitude right ascension at epoch
        self.rotation_zlra = math.radians(att["ZLRA"]) if "ZLRA" in att else 0.

        # rotation angular velocity [rad/s]
        if "rotation_rate" in att:
            self.rotation_rate = att["rotation_rate"] * 2.0 * math.pi / 180.0
        else:
            self.rotation_rate = 2. * math.pi / (2.2593 * 3600
                                                 )  # didymain by default

        # Define initial rotation, set rotation convention
        #  - For me, FRAME_TRANSFORM order makes more sense, the rotations are applied from left to right
        #    so that the following rotations apply on previously rotated axes  +Olli
        self.rot_conv = RotationConvention.FRAME_TRANSFORM
        init_rot = Rotation(RotationOrder.ZYZ, self.rot_conv, self.axis_ra,
                            math.pi / 2 - self.axis_dec, self.rotation_zlra)

        if "r" in trj:
            self.date_history = [trj_date]
            self.pos_history = [Vector3D(*trj["r"])]
            self.vel_history = [
                Vector3D(*(trj["v"] if "v" in trj else [0., 0., 0.]))
            ]
            self.rot_history = [init_rot]
            return

        # Define trajectory/orbit
        self.trajectory = KeplerianOrbit(
            trj["a"] * ok_utils.Constants.IAU_2012_ASTRONOMICAL_UNIT, trj["e"],
            math.radians(trj["i"]), math.radians(trj["omega"]),
            math.radians(trj["Omega"]), math.radians(trj["M"]),
            PositionAngle.MEAN, self.ref_frame, trj_date, mu)

        rotation = ok_utils.AngularCoordinates(
            init_rot, Vector3D(0., 0., self.rotation_rate))
        attitude = Attitude(trj_date, self.ref_frame, rotation)
        att_provider = FixedRate(attitude)

        # Create propagator
        self.propagator = KeplerianPropagator(self.trajectory, att_provider)

        # Loaded coma object, currently only used with OpenGL based rendering
        self.coma = None
示例#7
0
def _pose_absolute_keplerian(ns_spacecraft, init_coords, init_epoch):
    pos = init_coords["init_coord"]
    init_state = Cartesian()

    init_pose_oe = KepOrbElem()
    init_pose_oe.a = float(pos["a"])
    init_pose_oe.e = float(pos["e"])
    init_pose_oe.i = float(radians(pos["i"]))
    init_pose_oe.O = float(radians(pos["O"]))
    init_pose_oe.w = float(radians(pos["w"]))
    try:
        init_pose_oe.v = float(radians(pos["v"]))
    except KeyError:
        try:
            init_pose_oe.m = float(radians(pos["m"]))
        except KeyError:
            raise ValueError("No Anomaly for initialization of spacecraft: " +
                             ns_spacecraft)

    # Coordinates given in J2000 Frame
    # ----------------------------------------------------------------------------------------
    if init_coords["coord_frame"] == "J2000":
        init_state.from_keporb(init_pose_oe)
    # ----------------------------------------------------------------------------------------

    if init_coords["coord_frame"] == "TEME":
        teme_state = CartesianTEME()
        teme_state.from_keporb(init_pose_oe)

        init_frame = FramesFactory.getTEME()
        inertialFrame = FramesFactory.getEME2000()

        TEME2EME = init_frame.getTransformTo(inertialFrame,
                                             to_orekit_date(init_epoch))
        p = Vector3D(
            float(1e3),  # convert to [m]
            Vector3D(float(teme_state.R[0]), float(teme_state.R[1]),
                     float(teme_state.R[2])))
        v = Vector3D(
            float(1e3),  # convert to [m/s]
            Vector3D(float(teme_state.V[0]), float(teme_state.V[1]),
                     float(teme_state.V[2])))

        pv_EME = TEME2EME.transformPVCoordinates(PVCoordinates(p, v))

        init_state.R = np.array([
            pv_EME.position.x, pv_EME.position.y, pv_EME.position.z
        ]) / 1e3  # convert to [km]
        init_state.V = np.array([
            pv_EME.velocity.x, pv_EME.velocity.y, pv_EME.velocity.z
        ]) / 1e3  # convert to [km/s]

    # ----------------------------------------------------------------------------------------

    return init_state
示例#8
0
def _pose_absolute_cartesian(ns_spacecraft, init_coords, init_epoch):
    pos = init_coords["init_coord"]
    init_state = Cartesian()

    # Coordinates given in J2000 Frame
    # ----------------------------------------------------------------------------------------
    if init_coords["coord_frame"] == "J2000":
        init_state.R = np.array(
            [float(pos["x"]),
             float(pos["y"]),
             float(pos["z"])])

        init_state.V = np.array(
            [float(pos["v_x"]),
             float(pos["v_y"]),
             float(pos["v_z"])])
    # ----------------------------------------------------------------------------------------

    # Coordinates given in ITRF Frame
    # ----------------------------------------------------------------------------------------
    elif init_coords["coord_frame"] == "ITRF":
        inertialFrame = FramesFactory.getEME2000()
        init_frame = FramesFactory.getITRF(
            IERS.IERS_2010, False)  # False -> don't ignore tidal effects
        p = Vector3D(
            float(1e3),  # convert to [m]
            Vector3D(float(pos["x"]), float(pos["y"]), float(pos["z"])))
        v = Vector3D(
            float(1e3),  # convert to [m/s]
            Vector3D(float(pos["v_x"]), float(pos["v_y"]), float(pos["v_z"])))

        ITRF2EME = init_frame.getTransformTo(inertialFrame,
                                             to_orekit_date(init_epoch))
        pv_EME = ITRF2EME.transformPVCoordinates(PVCoordinates(p, v))

        init_state.R = np.array([
            pv_EME.position.x, pv_EME.position.y, pv_EME.position.z
        ]) / 1e3  # convert to [km]
        init_state.V = np.array([
            pv_EME.velocity.x, pv_EME.velocity.y, pv_EME.velocity.z
        ]) / 1e3  # convert to [km/s]

    else:
        raise ValueError(
            "[" + ns_spacecraft + " ]: " +
            "Conversion from coordinate frame " + init_coords["coord_frame"] +
            " not implemented. Please provided coordinates in a different reference frame."
        )
    # ----------------------------------------------------------------------------------------

    return init_state
示例#9
0
def validate_rv2coe():
    # Orbit initial state vectors
    rx_0, ry_0, rz_0 = -6045.0e3, -3490.0e3, 2500.0e3
    vx_0, vy_0, vz_0 = -3.457e3, 6.618e3, 2.533e3

    # Build the initial Orekit orbit
    k = C.IAU_2015_NOMINAL_EARTH_GM
    r0_vec = Vector3D(rx_0, ry_0, rz_0)
    v0_vec = Vector3D(vx_0, vy_0, vz_0)
    rv_0 = PVCoordinates(r0_vec, v0_vec)
    epoch_00 = AbsoluteDate.J2000_EPOCH
    gcrf_frame = FramesFactory.getGCRF()
    ss0_orekit = KeplerianOrbit(rv_0, gcrf_frame, epoch_00, k)

    # Build poliastro orbit
    r0_vec = [rx_0, ry_0, rz_0] * u.m
    v0_vec = [vx_0, vy_0, vz_0] * u.m / u.s
    ss0_poliastro = Orbit.from_vectors(Earth, r0_vec, v0_vec)

    # Orekit bounds COE angular magnitudes between [-pi, +pi]. Let us define a
    # converter function to map values between [0, +2pi]
    def unbound_angle(angle):
        """ Bound angle between [0, +2pi] """
        if -np.pi <= angle <= 0.0:
            angle += 2 * np.pi

        return angle

    # Map angles
    orekit_raan = unbound_angle(ss0_orekit.getRightAscensionOfAscendingNode())
    orekit_argp = unbound_angle(ss0_orekit.getPerigeeArgument())
    orekit_nu = unbound_angle(ss0_orekit.getTrueAnomaly())

    # Assert classical orbital elements
    assert_quantity_allclose(ss0_poliastro.a,
                             ss0_orekit.getA() * u.m,
                             rtol=1e-6)
    assert_quantity_allclose(ss0_poliastro.ecc,
                             ss0_orekit.getE() * u.one,
                             rtol=1e-6)
    assert_quantity_allclose(ss0_poliastro.inc,
                             ss0_orekit.getI() * u.rad,
                             rtol=1e-6)
    assert_quantity_allclose(ss0_poliastro.raan,
                             orekit_raan * u.rad,
                             rtol=1e-6)
    assert_quantity_allclose(ss0_poliastro.argp,
                             orekit_argp * u.rad,
                             rtol=1e-6)
    assert_quantity_allclose(ss0_poliastro.nu, orekit_nu * u.rad, rtol=1e-6)
示例#10
0
def validate_GCRF_to_ITRF(r_vec, v_vec):

    # Compute for the norm of position and velocity vectors
    r_norm, v_norm = [norm(vec) for vec in [r_vec, v_vec]]
    R = Earth_poliastro.R.to(u.m).value

    # Correction factor to normalize position and velocity vectors
    k_r = R / r_norm if r_norm != 0 else 1.00
    k_v = 1 / v_norm if v_norm != 0 else 1.00

    # Make a position vector who's norm is equal to the body's radius. Make a
    # unitary velocity vector. Units are in [m] and [m / s].
    rx, ry, rz = [float(k_r * r_i) for r_i in r_vec]
    vx, vy, vz = [float(k_v * v_i) for v_i in v_vec]

    # orekit: build r_vec and v_vec wrt inertial body frame
    xyz_orekit = Vector3D(rx, ry, rz)
    uvw_orekit = Vector3D(vx, vy, vz)
    coords_GCRF_orekit = TimeStampedPVCoordinates(J2000_OREKIT, xyz_orekit,
                                                  uvw_orekit)

    # orekit: build conversion between GCRF and ITRF
    GCRF_TO_ITRF_OREKIT = GCRF_FRAME_OREKIT.getTransformTo(
        ITRF_FRAME_OREKIT,
        J2000_OREKIT,
    )

    # orekit: convert from GCRF to ITRF using previous built conversion
    coords_ITRF_orekit = (GCRF_TO_ITRF_OREKIT.transformPVCoordinates(
        coords_GCRF_orekit).getPosition().toArray())
    coords_ITRF_orekit = np.asarray(coords_ITRF_orekit) * u.m

    # poliastro: build r_vec and v_vec wrt GCRF
    xyz_poliastro = CartesianRepresentation(rx * u.m, ry * u.m, rz * u.m)
    coords_GCRS_poliastro = GCRS_poliastro(xyz_poliastro)

    # poliastro: convert from inertial to fixed frame at given epoch
    coords_ITRS_poliastro = (coords_GCRS_poliastro.transform_to(
        ITRS_poliastro(
            obstime=J2000_POLIASTRO)).represent_as(CartesianRepresentation).xyz
                             )

    # Check position conversion
    assert_quantity_allclose(
        coords_ITRS_poliastro,
        coords_ITRF_orekit,
        atol=1e-3 * u.m,
        rtol=1e-2,
    )
示例#11
0
    def _compute_gravity_torque(self, curr_date):
        """Compute gravity gradient torque if gravity model provided.

        This method computes the Newtonian attraction and the perturbing part
        of the gravity gradient for every cuboid defined in dictionary
        inCub at time curr_date (= time of current satellite position).
        The gravity torque is computed in the inertial frame in which the
        spacecraft is defined. The perturbing part is calculated using Orekit's
        methods defined in the GravityModel object.

        The current position, rotation and mass of the satellite is obtained
        from the StateObserver object.

        Args:
            curr_date: Absolute date of current epoch

        Returns:
            Vector3D: gravity gradient torque at curr_date in satellite frame along principal axes
        """
        if self._to_add[0]:
            body2inertial = self.earth.getBodyFrame().getTransformTo(
                self.in_frame, curr_date)
            body2sat = self.inertial2Sat.applyTo(body2inertial.getRotation())
            sat2body = body2sat.revert()

            satM = self.state_observer.spacecraftState.getMass()
            mCub = self.inCub['mass_frac'] * satM

            self._gTorque = Vector3D.ZERO

            for CoM in self.inCub['CoM']:

                S_dmPos = self.satPos_s.add(CoM)

                r2 = S_dmPos.getNormSq()
                gNewton = Vector3D(-self.muGM / (sqrt(r2) * r2), S_dmPos)

                B_dmPos = sat2body.applyTo(S_dmPos)

                gDist = Vector3D(
                    self.GravityModel.gradient(curr_date, B_dmPos, self.muGM))

                g_Dist_s = body2sat.applyTo(gDist)

                dmForce = Vector3D(mCub, gNewton.add(g_Dist_s))
                self._gTorque = self._gTorque.add(self.V3_cross(CoM, dmForce))

        else:
            self._gTorque = Vector3D.ZERO
示例#12
0
    def compute_torques(self, rotation, omega, dt):
        """Compute disturbance torques acting on satellite.

        This method computes the disturbance torques, which are set to
        active in satellite's setting file.

        Args:
            rotation: Rotation object representing satellite's  current orientation
            omega: Satellite's current spin numpy array [rad/s]
            dt: passed time since last called 'update_satellite_state' method

        Returns:
            Vector3D: disturbance torque acting on satellite in satellite frame
        """
        # shift time @ which attitude integration currently is
        try:
            curr_date = self.in_date.shiftedBy(dt)

            self.inertial2Sat = rotation
            self.satPos_s = self.inertial2Sat.applyTo(self.satPos_i)
            omega = Vector3D(float(omega[0]), float(omega[1]), float(omega[2]))

            self._compute_gravity_torque(curr_date)
            self._compute_magnetic_torque(curr_date)
            self._compute_solar_torque(curr_date)
            self._compute_aero_torque(curr_date, omega)

            # external torque has to be set separately because it is received
            # through a ros subscriber
            return self._gTorque.add(
                self._mTorque.add(self._sTorque.add(self._aTorque)))
        except Exception:
            print traceback.print_exc()
            raise
    def calculate_external_torque(self):
        """Method which feeds external torques to attitude propagation provider.

        Method checks if torque has already been set by message from propulsion
        node (stored in self.torque), and then feeds them to the provider.
        """

        N_T_thrust = getattr(self, 'thrust_torque', None)
        N_T_actuator = getattr(self, 'actuator_torque', None)

        if N_T_thrust is not None and N_T_actuator is not None:
            N_T = N_T_thrust + N_T_actuator
        elif N_T_thrust is not None:
            N_T = N_T_thrust
        elif N_T_actuator is not None:
            N_T = N_T_actuator
        else:
            N_T = None

        if N_T is not None:
            N_T = Vector3D(float(N_T[0]),
                           float(N_T[1]),
                           float(N_T[2]))
            attProv = PAP.cast_(self._propagator_num.getAttitudeProvider())
            attProv.setExternalTorque(N_T)
    def calculate_thrust(self):
        """Method that updates parameter in Thrust Model.

        Method checks if first message from propulsion node received (stored in
         self.F_T), then computes the norm of the thrust vector and updates the
        parameters in the Thrust force model.

        If Thrust is zero, the contribution of the force model is not
        calculated.
        """

        # if simulation hasn't started attributes don't exist yet
        # set them to None in this case
        F_T = getattr(self, 'F_T', None)
        Isp = getattr(self, 'Isp', None)

        if F_T is not None and Isp is not None:
            F_T_norm = np.linalg.norm(F_T, 2)

            if F_T_norm > 2 * np.finfo(np.float32).eps:
                F_T_dir = F_T / F_T_norm
                F_T_dir = Vector3D(float(F_T_dir[0]),
                                   float(F_T_dir[1]),
                                   float(F_T_dir[2]))

                self.ThrustModel.direction = F_T_dir
                self.ThrustModel.thrust = float(F_T_norm)
                self.ThrustModel.isp = Isp
                self.ThrustModel.ChangeParameters(float(F_T_norm), Isp)
                self.ThrustModel.firing = True
            else:
                self.ThrustModel.firing = False
示例#15
0
    def _compute_solar_torque(self, curr_date):
        """Compute torque acting on satellite due to solar radiation pressure.

        This method uses the getLightingRatio() method defined in Orekit and
        copies parts of the acceleration() method of the SolarRadiationPressure
        and radiationPressureAcceleration() of the BoxAndSolarArraySpacecraft
        class to to calculate the solar radiation pressure on the discretized
        surface of the satellite. This is done, since the necessary Orekit
        methods cannot be accessed directly without creating an Spacecraft
        object.

        Args:
            curr_date: Absolute date of current epoch

        Returns:
            Vector3D: solar radiation pressure torque in satellite frame along principal axes
        """
        if self._to_add[2]:
            ratio = self.SolarModel.getLightingRatio(self.satPos_i,
                                                     self.in_frame, curr_date)

            sunPos = self.inertial2Sat.applyTo(
                self.sun.getPVCoordinates(curr_date,
                                          self.in_frame).getPosition())
            sunPos = np.array([sunPos.x, sunPos.y, sunPos.z], dtype='float64')

            CoM = self.meshDA['CoM_np']
            normal = self.meshDA['Normal_np']
            area = self.meshDA['Area_np']
            coefs = self.meshDA['Coefs_np']

            sunSatVector = self.satPos_s + CoM - sunPos
            r = np.linalg.norm(sunSatVector, axis=1)
            rawP = ratio * self.K_REF / (r**2)
            flux = (rawP / r)[:, None] * sunSatVector
            # eliminate arrays where zero flux
            fluxNorm = np.linalg.norm(flux, axis=1)
            Condflux = fluxNorm**2 > Precision.SAFE_MIN
            flux = flux[Condflux]
            normal = normal[Condflux]

            # dot product for multidimensional arrays:
            dot = np.einsum('ij,ij->i', flux, normal)
            dot[dot > 0] = dot[dot > 0] * (-1.0)
            if dot.size > 0:
                normal[dot > 0] = normal[dot > 0] * (-1.0)

                cN = 2 * area * dot * (coefs[:, 2] / 3 -
                                       coefs[:, 1] * dot / fluxNorm)
                cS = (area * dot / fluxNorm) * (coefs[:, 1] - 1)
                force = cN[:, None] * normal + cS[:, None] * flux

                sT = np.sum(np.cross(CoM, force), axis=0)

                self._sTorque = Vector3D(float(sT[0]), float(sT[1]),
                                         float(sT[2]))

        else:
            self._sTorque = Vector3D.ZERO
示例#16
0
    def _compute_aero_torque(self, curr_date, omega):
        """Compute torque acting on satellite due to drag.

        This method copies parts of the acceleration() method of the
        DragForce and dragAcceleration() of the BoxAndSolarArraySpacecraft
        class to to calculate the pressure on the discretized surface of the
        satellite. This is done, since the necessary Orekit methods cannot be
        accessed directly without creating an Spacecraft object.

        Args:
            curr_date: Absolute date of current epoch
            omega: numpy array of satellite's spin vector in satellite frame

        Returns:
            Vector3D: torque due to drag along principle axes in satellite frame
        """
        if self._to_add[3]:
            # assuming constant atmosphere condition over spacecraft
            # error is of order of 10^-17
            rho = self.AtmoModel.getDensity(curr_date, self.satPos_i,
                                            self.in_frame)
            vAtm_i = self.AtmoModel.getVelocity(curr_date, self.satPos_i,
                                                self.in_frame)

            satVel = self.inertial2Sat.applyTo(self.satVel_i)
            vAtm = self.inertial2Sat.applyTo(vAtm_i)

            self._aTorque = Vector3D.ZERO

            dragCoeff = self.meshDA['Cd']
            liftRatio = 0.0  # no lift considered

            iterator = itertools.izip(self.meshDA['CoM'],
                                      self.meshDA['Normal'],
                                      self.meshDA['Area'])

            for CoM, Normal, Area in iterator:
                CoMVelocity = satVel.add(self.V3_cross(omega, CoM))
                relativeVelocity = vAtm.subtract(CoMVelocity)

                vNorm2 = relativeVelocity.getNormSq()
                vNorm = sqrt(vNorm2)
                vDir = relativeVelocity.scalarMultiply(1.0 / vNorm)

                dot = self.V3_dot(Normal, vDir)
                if (dot < 0):
                    coeff = 0.5 * rho * dragCoeff * vNorm2
                    oMr = 1.0 - liftRatio
                    # dA intercepts the incoming flux
                    f = coeff * Area * dot
                    force = Vector3D(float(oMr * abs(f)), vDir,
                                     float(liftRatio * f * 2), Normal)
                    self._aTorque = self._aTorque.add(self.V3_cross(
                        CoM, force))

        else:
            self._aTorque = Vector3D.ZERO
示例#17
0
def get_elevation(sun_pos_sundial_frame):
    """
    Returns the elevation of the sun in the sundial frame.

    Parameters
    ----------
    sun_pos_sundial_frame : Vector3D
        Position vector of the Sun in the sundial frame.

    Returns
    -------
    float
        Elevation (in radians) of the Sun in the sundial frame.

    """
    proj_sun_pos_sundial_frame = Vector3D(sun_pos_sundial_frame.getX(),
                                          sun_pos_sundial_frame.getY(), 0.0)
    cos_elevation = Vector3D.dotProduct(sun_pos_sundial_frame, proj_sun_pos_sundial_frame)/ \
    (sun_pos_sundial_frame.getNorm()*proj_sun_pos_sundial_frame.getNorm())
    return acos(cos_elevation)
示例#18
0
    def _compute_magnetic_torque(self, curr_date):
        """Compute magnetic torque if magnetic model provided.

        This method converts the satellite's position into Longitude, Latitude,
        Altitude representation to determine the geo. magnetic field at that
        position and then computes based on those values the magnetic torque.

        Args:
            curr_date: Absolute date of current epoch

        Returns:
            Vector3D: magnetic torque at satellite position in satellite frame along principal axes
        """
        if self._to_add[1]:
            gP = self.earth.transform(self.satPos_i, self.in_frame, curr_date)

            topoframe = TopocentricFrame(self.earth, gP, 'ENU')
            topo2inertial = topoframe.getTransformTo(self.in_frame, curr_date)

            lat = gP.getLatitude()
            lon = gP.getLongitude()
            alt = gP.getAltitude() / 1e3  # Mag. Field needs degrees and [km]

            # get B-field in geodetic system (X:East, Y:North, Z:Nadir)
            B_geo = FileDataHandler.mag_field_model.calculateField(
                degrees(lat), degrees(lon), alt).getFieldVector()

            # convert geodetic frame to inertial and from [nT] to [T]
            B_i = topo2inertial.transformVector(Vector3D(1e-9, B_geo))

            B_b = self.inertial2Sat.applyTo(B_i)
            B_b = np.array([B_b.x, B_b.y, B_b.z])

            dipoleVector = self.dipoleM.getDipoleVectors(B_b)

            torque = np.sum(np.cross(dipoleVector, B_b), axis=0)

            self._mTorque = Vector3D(float(torque[0]), float(torque[1]),
                                     float(torque[2]))
        else:
            self._mTorque = Vector3D.ZERO
    def change_initial_conditions(self, initial_state, date, mass):
        """
            Allows to change the initial conditions given to the propagator without initializing it again.

        Args:
            initial_state (Cartesian): New initial state of the satellite in cartesian coordinates.
            date (datetime): New starting date of the propagator.
            mass (float64): New satellite mass.
        """
        # Redefine the start date
        self.date = date

        # Create position and velocity vectors as Vector3D
        p = Vector3D(
            float(initial_state.R[0]) * 1e3,
            float(initial_state.R[1]) * 1e3,
            float(initial_state.R[2]) * 1e3)
        v = Vector3D(
            float(initial_state.V[0]) * 1e3,
            float(initial_state.V[1]) * 1e3,
            float(initial_state.V[2]) * 1e3)

        # Initialize orekit date
        seconds = float(date.second) + float(date.microsecond) / 1e6
        orekit_date = AbsoluteDate(date.year, date.month, date.day, date.hour,
                                   date.minute, seconds,
                                   TimeScalesFactory.getUTC())

        # Extract frame
        inertialFrame = FramesFactory.getEME2000()

        # Evaluate new initial orbit
        initialOrbit = CartesianOrbit(PVCoordinates(p, v), inertialFrame,
                                      orekit_date, Cst.WGS84_EARTH_MU)

        # Create new spacecraft state
        newSpacecraftState = SpacecraftState(initialOrbit, mass)

        # Rewrite propagator initial conditions
        self.orekit_prop._propagator_num.setInitialState(newSpacecraftState)
示例#20
0
    def __init__(self, name, mu, trj, att, model_file=None):
        """Currently hard implemented for Didymos."""
        super().__init__(name, model_file=model_file)

        date = trj["date"]
        trj_date = AbsoluteDate(int(date["year"]), int(date["month"]),
                                int(date["day"]), int(date["hour"]),
                                int(date["minutes"]), float(date["seconds"]),
                                self.timescale)

        if "a" and "e" and "i" and "omega" and "Omega" and "M" not in trj:
            a = 1.644641475071416E+00 * utils.Constants.IAU_2012_ASTRONOMICAL_UNIT
            P = 7.703805051391988E+02 * utils.Constants.JULIAN_DAY
            e = 3.838774437558215E-01
            i = math.radians(3.408231185574551E+00)
            omega = math.radians(3.192958853076784E+02)
            Omega = math.radians(7.320940216397703E+01)
            M = math.radians(1.967164895190036E+02)

        if "rotation_rate" not in att:
            rotation_rate = 2. * math.pi / (2.2593 * 3600)
        else:
            rotation_rate = att["rotation_rate"] * 2.0 * math.pi / 180.0

        if "RA" not in att:
            self.RA = 0.
        else:
            self.RA = math.radians(att["RA"])

        if "Dec" not in att:
            self.Dec = 0.
        else:
            self.Dec = math.radians(att["Dec"])

        # Define trajectory/orbit
        self.trajectory = KeplerianOrbit(
            trj["a"] * utils.Constants.IAU_2012_ASTRONOMICAL_UNIT, trj["e"],
            math.radians(trj["i"]), math.radians(trj["omega"]),
            math.radians(trj["Omega"]), math.radians(trj["M"]),
            PositionAngle.MEAN, self.ref_frame, trj_date, mu)

        # Define attitude
        self.rot_conv = RotationConvention.valueOf("VECTOR_OPERATOR")

        rotation = utils.AngularCoordinates(Rotation.IDENTITY,
                                            Vector3D(0., 0., rotation_rate))
        attitude = Attitude(trj_date, self.ref_frame, rotation)
        att_provider = FixedRate(attitude)

        # Create propagator
        self.propagator = KeplerianPropagator(self.trajectory, att_provider)
示例#21
0
    def _initialize_dipole_model(self, model):
        """Initializes dipole Model.

        This method uses the simplified dipole model implemented in DipoleModel.py
        Which needs to initialize the induced Magnetic density in the hysteresis
        rods.

        It also adds the hysteresis rods and bar magnets specified in the settings
        file to the satellite using the DipoleModel class.

        Args:
            model: dictionary holding information about hysteresis rods and bar magnets of the satellite
        """
        for key, hyst in model['Hysteresis'].items():
            direction = np.array([float(x) for x in hyst['dir'].split(" ")])
            self.dipoleM.addHysteresis(direction, hyst['vol'], hyst['Hc'],
                                       hyst['Bs'], hyst['Br'])

        # initialize values for Hysteresis (need B-field @ initial position)
        spacecraft_state = self.state_observer.spacecraftState
        self.inertial2Sat = spacecraft_state.getAttitude().getRotation()
        self.satPos_i = spacecraft_state.getPVCoordinates().getPosition()

        gP = self.earth.transform(self.satPos_i, self.in_frame, self.in_date)

        topoframe = TopocentricFrame(self.earth, gP, 'ENU')
        topo2inertial = topoframe.getTransformTo(self.in_frame, self.in_date)

        lat = gP.getLatitude()
        lon = gP.getLongitude()
        alt = gP.getAltitude() / 1e3  # Mag. Field needs degrees and [km]

        # get B-field in geodetic system (X:East, Y:North, Z:Nadir)
        B_geo = FileDataHandler.mag_field_model.calculateField(
            degrees(lat), degrees(lon), alt).getFieldVector()

        # convert geodetic frame to inertial and from [nT] to [T]
        B_i = topo2inertial.transformVector(Vector3D(1e-9, B_geo))

        B_b = self.inertial2Sat.applyTo(B_i)
        B_field = np.array([B_b.x, B_b.y, B_b.z])

        self.dipoleM.initializeHysteresisModel(B_field)

        # add bar magnets to satellite
        for key, bar in model['BarMagnet'].items():
            direction = np.array([float(x) for x in bar['dir'].split(" ")])
            self.dipoleM.addBarMagnet(direction, bar['m'])
示例#22
0
def find_sat_distance(prop1, prop2, time):
    """
	distance between two propagators at a given time
	Inputs: prop1/prop2 (Two orekit propagator objects), time (orekit absolute time object--utc)
	Output: Distance (meters)
	"""
    ITRF = FramesFactory.getITRF(IERSConventions.IERS_2010, True)
    earth = OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
                             Constants.WGS84_EARTH_FLATTENING, ITRF)

    pv_1 = prop1.getPVCoordinates(time, prop1.getFrame())
    pv_2 = prop2.getPVCoordinates(time, prop2.getFrame())

    p_1 = pv_1.getPosition()
    p_2 = pv_2.getPosition()

    return abs(Vector3D.distance(p_1, p_2))
def Get_LineOfSight_UnitVector(RA, DE):
    """
    Calculates the line of sight versor given the Declination and Right Ascension
    values for that observation  
    Returns a numpy array for each of these
    """

    # L = np.mat(np.array([[np.cos(DE) * np.cos(RA)],
    #                      [np.cos(DE) * np.sin(RA)],
    #                      [np.sin(DE)]]))

    # due to the Java Python interface the Vector3D class will create problems if
    # the float types are not explicitly cast
    L = Vector3D(float(np.cos(DE) * np.cos(RA)),
                 float(np.cos(DE) * np.sin(RA)), float(np.sin(DE)))

    return L
示例#24
0
    def acceleration(self, state, parameters):
        """
        Compute acceleration due to thrust.

        Args:
            state: spacecraft state
            parameters: parameters of Force Model (here: thrust and flow rate)

        Returns:
            Vector3D: acceleration vector based on thrust and mass of satellite
        """
        if self.firing:
            thrust = parameters[0]
            return Vector3D(
                thrust / state.getMass(),
                state.getAttitude().getRotation().applyInverseTo(
                    self.direction))
        else:
            return Vector3D.ZERO
示例#25
0
def get_azimuth(sun_pos_sundial_frame):
    """
    Returns the azimuth of the sun in the sundial frame.

    Parameters
    ----------
    sun_pos_sundial_frame : Vector3D
        Position vector of the Sun in the sundial frame.

    Returns
    -------
    float
        Azimuth (in radians) of the Sun in the sundial frame.

    """
    proj_sun_pos_sundial_frame = Vector3D(sun_pos_sundial_frame.getX(),
                                          sun_pos_sundial_frame.getY(), 0.0)
    cos_azimuth = proj_sun_pos_sundial_frame.getY(
    ) / proj_sun_pos_sundial_frame.getNorm()
    return acos(cos_azimuth)
示例#26
0
    def calc_encounter_pos(sssb_pos,
                           min_dist,
                           terminator=True,
                           sunnyside=False):
        """Calculate the pos of a Spacecraft at closest distance to SSSB."""
        sssb_direction = sssb_pos.normalize()

        if terminator:
            shift = sssb_direction.scalarMultiply(-0.15)
            shift = shift.add(Vector3D(0., 0., 1.))
            shift = shift.normalize()
            shift = shift.scalarMultiply(min_dist)
            sc_pos = sssb_pos.add(shift)
        else:
            if not sunnyside:
                min_dist *= -1

            sssb_direction = sssb_direction.scalarMultiply(min_dist)
            sc_pos = sssb_pos.subtract(sssb_direction)

        return sc_pos
    def _calculate_magnetic_field(self, oDate):
        """Calculate the magnetic field at position of the spacecraft (Internal Method)."""
        space_state = self._propagator_num.getInitialState()
        satPos = space_state.getPVCoordinates().getPosition()
        inertial2Sat = space_state.getAttitude().getRotation()
        frame = space_state.getFrame()

        gP = self._earth.transform(satPos, frame, oDate)

        topoframe = TopocentricFrame(self._earth, gP, 'ENU')
        topo2inertial = topoframe.getTransformTo(frame, oDate)

        lat = gP.getLatitude()
        lon = gP.getLongitude()
        alt = gP.getAltitude() / 1e3  # Mag. Field needs degrees and [km]

        # get B-field in geodetic system (X:East, Y:North, Z:Nadir)
        B_geo = FileDataHandler.mag_field_model.calculateField(
            degrees(lat), degrees(lon), alt).getFieldVector()

        # convert geodetic frame to inertial and from [nT] to [T]
        B_i = topo2inertial.transformVector(Vector3D(1e-9, B_geo))

        return inertial2Sat.applyTo(B_i)
示例#28
0
    def __init__(self, Thrust=None, Isp=None):
        BaseForceModel.__init__(self, "ThrustModel")

        # direction has to be normalized!
        self.direction = Vector3D(float(1), float(0), float(0))
        self.firing = False

        self._mDot = tuple([0., 0.])  # tuple for attitude propagation

        if Thrust is None:
            thrust = float(0.0)
        else:
            thrust = float(Thrust)

        if Isp is None:
            isp = 0
        else:
            isp = Isp

        if isp == 0:
            flowRate = 0.0
            thrust = 0.0
        else:
            flowRate = -thrust / (Constants.G0_STANDARD_GRAVITY * isp)

        # defined as in ConstantManeuverClass by Orekit:
        FLOW_RATE_SCALE = 1.0 * (2**-12)
        THRUST_RATE_SCALE = 1.0 * (2**-5)

        self.thrustDriver = ParameterDriver('thrust', thrust,
                                            float(FLOW_RATE_SCALE), float(0.0),
                                            float(100.0))

        self.flowRateDriver = ParameterDriver('flowRate', float(flowRate),
                                              float(THRUST_RATE_SCALE),
                                              float(-100.0), float(0.0))
示例#29
0
    return TLE(tle_line1.strip(), tle_line2.strip())


if __name__ == "__main__":
    spot5_1 = " 1 27421U 02021A   02124.48976499 -.00021470  00000-0 -89879-2 0    20"
    spot5_2 = " 2 27421  98.7490 199.5121 0001333 133.9522 226.1918 14.26113993    62"

    maneuvers = [(datetime(2002,
                           month=5,
                           day=5,
                           hour=12,
                           minute=0,
                           second=0,
                           microsecond=0,
                           tzinfo=timezone.utc), FramesFactory.getEME2000(),
                  Vector3D(100., 0., 0.), 300.),
                 (datetime(2002,
                           month=5,
                           day=6,
                           hour=12,
                           minute=0,
                           second=0,
                           microsecond=0,
                           tzinfo=timezone.utc), FramesFactory.getEME2000(),
                  Vector3D(0., 100., 0.), 300.),
                 (datetime(2002,
                           month=5,
                           day=7,
                           hour=12,
                           minute=0,
                           second=0,
示例#30
0
def validate_from_body_intertial_to_body_fixed(body_name, r_vec, v_vec):

    # poliastro: collect body information
    (
        BODY_POLIASTRO,
        BODY_ICRF_FRAME_POLIASTRO,
        BODY_FIXED_FRAME_POLIASTRO,
    ) = POLIASTRO_BODIES_AND_FRAMES[body_name]

    # Compute for the norm of position and velocity vectors
    r_norm, v_norm = [norm(vec) for vec in [r_vec, v_vec]]
    R = BODY_POLIASTRO.R.to(u.m).value

    # Make a position vector who's norm is equal to the body's radius. Make a
    # unitary velocity vector. Units are in [m] and [m / s].
    rx, ry, rz = [float(r_i * R / r_norm) for r_i in r_vec]
    vx, vy, vz = [float(v_i / v_norm) for v_i in v_vec]

    # poliastro: build r_vec and v_vec wrt inertial body frame
    xyz_poliastro = CartesianRepresentation(rx * u.m, ry * u.m, rz * u.m)
    coords_wrt_bodyICRS_poliastro = BODY_ICRF_FRAME_POLIASTRO(xyz_poliastro)

    # poliastro: convert from inertial to fixed frame at given epoch
    coords_wrt_bodyFIXED_poliastro = (
        coords_wrt_bodyICRS_poliastro.transform_to(
            BODY_FIXED_FRAME_POLIASTRO(obstime=J2000_POLIASTRO)).represent_as(
                CartesianRepresentation).xyz)

    # orekit: collect body information
    (
        BODY_OREKIT,
        BODY_FIXED_FRAME_OREKIT,
    ) = OREKIT_BODIES_AND_FRAMES[body_name]

    # orekit: build r_vec and v_vec wrt inertial body frame
    xyz_orekit = Vector3D(rx, ry, rz)
    uvw_orekit = Vector3D(vx, vy, vz)
    coords_wrt_bodyICRS_orekit = TimeStampedPVCoordinates(
        J2000_OREKIT, xyz_orekit, uvw_orekit)

    # orekit: create bodyICRS frame as pure translation of ICRF one
    coords_body_wrt_ICRF_orekit = PVCoordinatesProvider.cast_(
        BODY_OREKIT).getPVCoordinates(J2000_OREKIT, ICRF_FRAME_OREKIT)
    BODY_ICRF_FRAME_OREKIT = Frame(
        ICRF_FRAME_OREKIT,
        Transform(J2000_OREKIT, coords_body_wrt_ICRF_orekit.negate()),
        body_name.capitalize() + "ICRF",
    )

    # orekit: build conversion between BodyICRF and BodyFixed frames
    bodyICRF_to_bodyFIXED_orekit = BODY_ICRF_FRAME_OREKIT.getTransformTo(
        BODY_FIXED_FRAME_OREKIT,
        J2000_OREKIT,
    )

    # orekit: convert from inertial coordinates to non-inertial ones
    coords_orekit_fixed_raw = (
        bodyICRF_to_bodyFIXED_orekit.transformPVCoordinates(
            coords_wrt_bodyICRS_orekit).getPosition().toArray())
    coords_wrt_bodyFIXED_orekit = np.asarray(coords_orekit_fixed_raw) * u.m

    # Check position conversion
    assert_quantity_allclose(
        coords_wrt_bodyFIXED_poliastro,
        coords_wrt_bodyFIXED_orekit,
        atol=1e-5 * u.m,
        rtol=1e-7,
    )