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)
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)
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)
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)
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
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
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
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)
def calc_encounter_state(cls, sssb_state, min_dist, rel_vel, terminator=True, sunnyside=False): """Calculate the state of a Spacecraft at closest distance to SSSB.""" (sssb_pos, sssb_vel) = sssb_state sc_pos = cls.calc_encounter_pos(sssb_pos, min_dist, terminator, sunnyside) sc_vel = sssb_vel.scalarMultiply( (sssb_vel.getNorm() - rel_vel) / sssb_vel.getNorm()) #logger.info("Spacecraft relative velocity: %s", sc_vel) #logger.info("Spacecraft distance from sun: %s", # sc_pos.getNorm()/Constants.IAU_2012_ASTRONOMICAL_UNIT) return PVCoordinates(sc_pos, sc_vel)
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)
def frame_conversion(state, mjd, orekit_in_frame, orekit_out_frame): '''Convert Cartesian state between two frames. Currently options are: * EME * CIRF * ITRF * TIRF * ITRFEquinox * TEME # TODO: finish docstring ''' state_out = np.empty(state.shape, dtype=state.dtype) pos = org.hipparchus.geometry.euclidean.threed.Vector3D( float(state[0]), float(state[1]), float(state[2])) vel = org.hipparchus.geometry.euclidean.threed.Vector3D( float(state[3]), float(state[4]), float(state[5])) PV_state = PVCoordinates(pos, vel) transform = orekit_in_frame.getTransformTo(orekit_out_frame, mjd2absdate(mjd)) new_PV = transform.transformPVCoordinates(PV_state) x_tmp = new_PV.getPosition() v_tmp = new_PV.getVelocity() state_out[0] = x_tmp.getX() state_out[1] = x_tmp.getY() state_out[2] = x_tmp.getZ() state_out[3] = v_tmp.getX() state_out[4] = v_tmp.getY() state_out[5] = v_tmp.getZ() return state_out
def convert_cart_single_orekit(to_conv,ref_to_conv,target_ref): """ Coordinate frame transformation with Orekit modules. INPUTS ------ to_conv: dataframe Cartesian coordinates. ref_to_conv: string Initial reference frame ('itrf','gcrf','teme', 'eme2000') target_ref: string Final reference frame ('itrf','gcrf','teme', 'eme2000') RETURN ------ dframe: dataframe Cartesian coordinates. """ date = to_conv.index[0] X = float(to_conv['x[m]'][0]) Y = float(to_conv['y[m]'][0]) Z = float(to_conv['z[m]'][0]) Vx = float(to_conv['vx[m/s]'][0]) Vy = float(to_conv['vy[m/s]'][0]) Vz = float(to_conv['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) if ref_to_conv == 'itrf': frame_to_conv = itrf_f elif ref_to_conv == 'gcrf': frame_to_conv = gcrf_f elif ref_to_conv == 'teme': frame_to_conv = teme_f elif ref_to_conv == 'eme2000': frame_to_conv = eme2000_f else: print(f'Unknown reference frame: {ref_to_conv}') if target_ref == 'itrf': target_frame = itrf_f elif target_ref == 'gcrf': target_frame = gcrf_f elif target_ref == 'teme': target_frame = teme_f elif target_ref == 'eme2000': target_frame = eme2000_f else: print(f'Unknown reference frame: {target_ref}') state_to_conv = AbsolutePVCoordinates(frame_to_conv,start_state) target_state = AbsolutePVCoordinates(target_frame,state_to_conv.getPVCoordinates(target_frame)) pos = target_state.position vel = target_state.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=to_conv.index) return dframe
def propagate(self, t, state0, epoch, **kwargs): ''' **Implementation:** Units are in meters and degrees. Keyword arguments are: * float A: Area in m^2 * float C_D: Drag coefficient * float C_R: Radiation pressure coefficient * float m: Mass of object in kg *NOTE:* * If the eccentricity is below 1e-10 the eccentricity will be set to 1e-10 to prevent Keplerian Jacobian becoming singular. The implementation first checks if the input frame is Pseudo inertial, if this is true this is used as the propagation frame. If not it is automatically converted to EME (ECI-J2000). Since there are forces that are dependent on the space-craft parameters, if these parameter has been changed since the last iteration the numerical integrator is re-initialized at every call of this method. The forces that can be initialized without spacecraft parameters (e.g. Earth gravitational field) are done at propagator construction. See :func:`propagator_base.PropagatorBase.get_orbit`. ''' if self.profiler is not None: self.profiler.start('Orekit:propagate') if self.settings['in_frame'].startswith('Orekit-'): self.inputFrame = self._get_frame( self.settings['in_frame'].replace('Orekit-', '')) orekit_in_frame = True else: self.inputFrame = self._get_frame('GCRF') orekit_in_frame = False if self.settings['out_frame'].startswith('Orekit-'): self.outputFrame = self._get_frame( self.settings['out_frame'].replace('Orekit-', '')) orekit_out_frame = True else: self.outputFrame = self._get_frame('GCRF') orekit_out_frame = False if self.inputFrame.isPseudoInertial(): self.inertialFrame = self.inputFrame else: self.inertialFrame = FramesFactory.getEME2000() self.body = OneAxisEllipsoid(self.R_earth, self.f_earth, self.outputFrame) if isinstance(state0, pyorb.Orbit): state0_cart = np.squeeze(state0.cartesian) else: state0_cart = state0 if self.settings['radiation_pressure']: if 'C_R' not in kwargs: raise Exception( 'Radiation pressure force enabled but no coefficient "C_R" given' ) else: kwargs['C_R'] = 1.0 if self.settings['drag_force']: if 'C_D' not in kwargs: raise Exception( 'Drag force enabled but no drag coefficient "C_D" given') else: kwargs['C_D'] = 1.0 if 'm' not in kwargs: kwargs['m'] = 0.0 t, epoch = self.convert_time(t, epoch) times = epoch + t mjd0 = epoch.mjd t = t.value if not isinstance(t, np.ndarray): t = np.array([t]) if self.logger is not None: self.logger.debug(f'Orekit:propagate:len(t) = {len(t)}') if not orekit_in_frame: state0_cart = frames.convert( epoch, state0_cart, in_frame=self.settings['in_frame'], out_frame='GCRS', profiler=self.profiler, logger=self.logger, ) initialDate = mjd2absdate(mjd0, self.utc) pos = org.hipparchus.geometry.euclidean.threed.Vector3D( float(state0_cart[0]), float(state0_cart[1]), float(state0_cart[2])) vel = org.hipparchus.geometry.euclidean.threed.Vector3D( float(state0_cart[3]), float(state0_cart[4]), float(state0_cart[5])) PV_state = PVCoordinates(pos, vel) if not self.inputFrame.isPseudoInertial(): transform = self.inputFrame.getTransformTo(self.inertialFrame, initialDate) PV_state = transform.transformPVCoordinates(PV_state) initialOrbit = CartesianOrbit( PV_state, self.inertialFrame, initialDate, self.mu + float(scipy.constants.G * kwargs['m']), ) self._construct_propagator(initialOrbit) self._set_forces(kwargs['A'], kwargs['C_D'], kwargs['C_R']) initialState = SpacecraftState(initialOrbit) self.propagator.setInitialState(initialState) tb_inds = t < 0.0 t_back = t[tb_inds] tf_indst = t >= 0.0 t_forward = t[tf_indst] if len(t_forward) == 1: if np.any(t_forward == 0.0): t_back = t t_forward = [] tb_inds = t <= 0 state = np.empty((6, len(t)), dtype=np.float) step_handler = Orekit.OrekitVariableStep() if self.profiler is not None: self.profiler.start('Orekit:propagate:steps') if self.settings['heartbeat']: __heartbeat = self.heartbeat else: __heartbeat = None if len(t_back) > 0: _t = t_back _t_order = np.argsort(np.abs(_t)) _t_res = np.argsort(_t_order) _t = _t[_t_order] _state = np.empty((6, len(_t)), dtype=np.float) step_handler.set_params(_t, initialDate, _state, self.outputFrame, __heartbeat, profiler=self.profiler) self.propagator.setMasterMode(step_handler) self.propagator.propagate(initialDate.shiftedBy(float(_t[-1]))) #now _state is full and in the order of _t state[:, tb_inds] = _state[:, _t_res] if len(t_forward) > 0: _t = t_forward _t_order = np.argsort(np.abs(_t)) _t_res = np.argsort(_t_order) _t = _t[_t_order] _state = np.empty((6, len(_t)), dtype=np.float) step_handler.set_params(_t, initialDate, _state, self.outputFrame, __heartbeat, profiler=self.profiler) self.propagator.setMasterMode(step_handler) self.propagator.propagate(initialDate.shiftedBy(float(_t[-1]))) #now _state is full and in the order of _t state[:, tf_indst] = _state[:, _t_res] if not orekit_out_frame: state = frames.convert( times, state, in_frame='GCRS', out_frame=self.settings['out_frame'], profiler=self.profiler, logger=self.logger, ) if self.profiler is not None: self.profiler.stop('Orekit:propagate:steps') self.profiler.stop('Orekit:propagate') if self.logger is not None: self.logger.debug(f'Orekit:propagate:completed') return state
def get_orbit(self, t, a, e, inc, raan, aop, mu0, mjd0, **kwargs): ''' **Implementation:** Units are in meters and degrees. Keyword arguments are: * float A: Area in m^2 * float C_D: Drag coefficient * float C_R: Radiation pressure coefficient * float m: Mass of object in kg *NOTE:* * If the eccentricity is below 1e-10 the eccentricity will be set to 1e-10 to prevent Keplerian Jacobian becoming singular. The implementation first checks if the input frame is Pseudo inertial, if this is true this is used as the propagation frame. If not it is automatically converted to EME (ECI-J2000). Since there are forces that are dependent on the space-craft parameters, if these parameter has been changed since the last iteration the numerical integrator is re-initialized at every call of this method. The forces that can be initialized without spacecraft parameters (e.g. Earth gravitational field) are done at propagator construction. **Uses:** * :func:`propagator_base.PropagatorBase._make_numpy` * :func:`propagator_orekit.PropagatorOrekit._construct_propagator` * :func:`propagator_orekit.PropagatorOrekit._set_forces` * :func:`dpt_tools.kep2cart` * :func:`dpt_tools.cart2kep` * :func:`dpt_tools.true2mean` * :func:`dpt_tools.mean2true` See :func:`propagator_base.PropagatorBase.get_orbit`. ''' if self.logger_func is not None: self._logger_start('get_orbit') if self.radiation_pressure: if 'C_R' not in kwargs: raise Exception( 'Radiation pressure force enabled but no coefficient "C_R" given' ) else: kwargs['C_R'] = 1.0 if self.drag_force: if 'C_D' not in kwargs: raise Exception( 'Drag force enabled but no drag coefficient "C_D" given') else: kwargs['C_D'] = 1.0 t = self._make_numpy(t) initialDate = mjd2absdate(mjd0) if not self.inputFrame.isPseudoInertial(): orb = np.array( [a, e, inc, aop, raan, dpt.mean2true(mu0, e, radians=False)], dtype=np.float) cart = dpt.kep2cart( orb, m=kwargs['m'], M_cent=self.M_earth, radians=False, ) pos = org.hipparchus.geometry.euclidean.threed.Vector3D( float(cart[0]), float(cart[1]), float(cart[2])) vel = org.hipparchus.geometry.euclidean.threed.Vector3D( float(cart[3]), float(cart[4]), float(cart[5])) PV_state = PVCoordinates(pos, vel) transform = self.inputFrame.getTransformTo(self.inertialFrame, initialDate) new_PV = transform.transformPVCoordinates(PV_state) initialOrbit = CartesianOrbit( new_PV, self.inertialFrame, initialDate, self.mu + float(scipy.constants.G * kwargs['m']), ) else: #this is to prevent Keplerian Jacobian to become singular use_equinoctial = False if e < dpt.e_lim: use_equinoctial = True if inc < dpt.i_lim: use_equinoctial = True if use_equinoctial: ex = e * np.cos(np.radians(aop) + np.radians(raan)) ey = e * np.sin(np.radians(aop) + np.radians(raan)) hx = np.tan(np.radians(inc) * 0.5) * np.cos(np.radians(raan)) hy = np.tan(np.radians(inc) * 0.5) * np.sin(np.radians(raan)) lv = np.radians(mu0) + np.radians(aop) + np.radians(raan) initialOrbit = EquinoctialOrbit( float(a), float(ex), float(ey), float(hx), float(hy), float(lv), PositionAngle.MEAN, self.inertialFrame, initialDate, self.mu + float(scipy.constants.G * kwargs['m']), ) else: initialOrbit = KeplerianOrbit( float(a), float(e), float(np.radians(inc)), float(np.radians(aop)), float(np.radians(raan)), float(np.radians(mu0)), PositionAngle.MEAN, self.inertialFrame, initialDate, self.mu + float(scipy.constants.G * kwargs['m']), ) self._construct_propagator(initialOrbit) self._set_forces(kwargs['A'], kwargs['C_D'], kwargs['C_R']) initialState = SpacecraftState(initialOrbit) self.propagator.setInitialState(initialState) tb_inds = t < 0.0 t_back = t[tb_inds] tf_indst = t >= 0.0 t_forward = t[tf_indst] if len(t_forward) == 1: if np.any(t_forward == 0.0): t_back = t t_forward = [] tb_inds = t <= 0 state = np.empty((6, len(t)), dtype=np.float) step_handler = PropagatorOrekit.OrekitVariableStep() if self.logger_func is not None: self._logger_start('propagation') if len(t_back) > 0: _t = t_back _t_order = np.argsort(np.abs(_t)) _t_res = np.argsort(_t_order) _t = _t[_t_order] _state = np.empty((6, len(_t)), dtype=np.float) step_handler.set_params(_t, initialDate, _state, self.outputFrame) self.propagator.setMasterMode(step_handler) self.propagator.propagate(initialDate.shiftedBy(float(_t[-1]))) #now _state is full and in the order of _t state[:, tb_inds] = _state[:, _t_res] if len(t_forward) > 0: _t = t_forward _t_order = np.argsort(np.abs(_t)) _t_res = np.argsort(_t_order) _t = _t[_t_order] _state = np.empty((6, len(_t)), dtype=np.float) step_handler.set_params(_t, initialDate, _state, self.outputFrame) self.propagator.setMasterMode(step_handler) self.propagator.propagate(initialDate.shiftedBy(float(_t[-1]))) #now _state is full and in the order of _t state[:, tf_indst] = _state[:, _t_res] if self.logger_func is not None: self._logger_record('propagation') if self.logger_func is not None: self._logger_record('get_orbit') return state
def validate_3D_hohmann(): # Initial orbit state vectors, final radius and time of flight # This orbit has an inclination of 22.30 [deg] so the maneuver will not be # applied on an equatorial orbit. See associated GMAT script: # gmat_validate_hohmann3D.script rx_0, ry_0, rz_0 = 7200e3, -1000.0e3, 0.0 vx_0, vy_0, vz_0 = 0.0, 8.0e3, 3.25e3 rf_norm = 35781.35e3 tof = 19800.00 # 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() ss_0 = KeplerianOrbit(rv_0, gcrf_frame, epoch_00, k) # Final desired orbit radius and auxiliary variables a_0, ecc_0 = ss_0.getA(), ss_0.getE() rp_norm = a_0 * (1 - ecc_0) vp_norm = np.sqrt(2 * k / rp_norm - k / a_0) a_trans = (rp_norm + rf_norm) / 2 # Compute the magnitude of Hohmann's deltaV dv_a = np.sqrt(2 * k / rp_norm - k / a_trans) - vp_norm dv_b = np.sqrt(k / rf_norm) - np.sqrt(2 * k / rf_norm - k / a_trans) # Convert previous magnitudes into vectors within the TNW frame, which # is aligned with local velocity vector dVa_vec, dVb_vec = [ Vector3D(float(dV), float(0), float(0)) for dV in (dv_a, dv_b) ] # Local orbit frame: X-axis aligned with velocity, Z-axis towards momentum attitude_provider = LofOffset(gcrf_frame, LOFType.TNW) # Setup impulse triggers; default apside detector stops on increasing g # function (aka at perigee) at_apoapsis = ApsideDetector(ss_0).withHandler(StopOnDecreasing()) at_periapsis = ApsideDetector(ss_0) # Build the impulsive maneuvers; ISP is only related to fuel mass cost ISP = float(300) imp_A = ImpulseManeuver(at_periapsis, attitude_provider, dVa_vec, ISP) imp_B = ImpulseManeuver(at_apoapsis, attitude_provider, dVb_vec, ISP) # Generate the propagator and add the maneuvers propagator = KeplerianPropagator(ss_0, attitude_provider) propagator.addEventDetector(imp_A) propagator.addEventDetector(imp_B) # Apply the maneuver by propagating the orbit epoch_ff = epoch_00.shiftedBy(tof) rv_f = propagator.propagate(epoch_ff).getPVCoordinates(gcrf_frame) # Retrieve orekit final state vectors r_orekit, v_orekit = ( rv_f.getPosition().toArray() * u.m, rv_f.getVelocity().toArray() * u.m / u.s, ) # Build initial poliastro orbit and apply the maneuver 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) man_poliastro = Maneuver.hohmann(ss0_poliastro, rf_norm * u.m) # Retrieve propagation time after maneuver has been applied tof_prop = tof - man_poliastro.get_total_time().to(u.s).value ssf_poliastro = ss0_poliastro.apply_maneuver(man_poliastro).propagate( tof_prop * 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, rtol=1e-6) assert_quantity_allclose(v_poliastro, v_orekit, rtol=1e-6)