pub struct Objective {
pub parameter: StateParameter,
pub desired_value: f64,
pub tolerance: f64,
pub multiplicative_factor: f64,
pub additive_factor: f64,
}Expand description
Defines a state parameter event finder
Fields§
§parameter: StateParameterThe state parameter to target
desired_value: f64The desired self.desired_value, must be in the same units as the state parameter
tolerance: f64The precision on the desired value
multiplicative_factor: f64A multiplicative factor this parameter’s error in the targeting (defaults to 1.0)
additive_factor: f64An additive factor to this parameters’s error in the targeting (defaults to 0.0)
Implementations§
Source§impl Objective
impl Objective
Sourcepub fn new(parameter: StateParameter, desired_value: f64) -> Self
pub fn new(parameter: StateParameter, desired_value: f64) -> Self
Match a specific value for the parameter. By default, the tolerance on the parameter is 0.1 times whatever unit is the default for that parameter. For example, a radius event will seek the requested value at the decimeter level, and an angle event will seek it at the tenth of a degree.
Sourcepub fn within_tolerance(
parameter: StateParameter,
desired_value: f64,
tolerance: f64,
) -> Self
pub fn within_tolerance( parameter: StateParameter, desired_value: f64, tolerance: f64, ) -> Self
Match a specific value for the parameter to hit the specified value with the provided tolerance on the value
Examples found in repository?
28fn main() -> Result<(), Box<dyn Error>> {
29 pel::init();
30 // Set up the dynamics like in the orbit raise.
31 let almanac = Arc::new(MetaAlmanac::latest().map_err(Box::new)?);
32 let epoch = Epoch::from_gregorian_utc_hms(2024, 2, 29, 12, 13, 14);
33
34 // Define the GEO orbit, and we're just going to maintain it very tightly.
35 let earth_j2000 = almanac.frame_info(EARTH_J2000)?;
36 let orbit = Orbit::try_keplerian(42164.0, 1e-5, 0., 163.0, 75.0, 0.0, epoch, earth_j2000)?;
37 println!("{orbit:x}");
38
39 let sc = Spacecraft::builder()
40 .orbit(orbit)
41 .mass(Mass::from_dry_and_prop_masses(1000.0, 1000.0)) // 1000 kg of dry mass and prop, totalling 2.0 tons
42 .srp(SRPData::from_area(3.0 * 6.0)) // Assuming 1 kW/m^2 or 18 kW, giving a margin of 4.35 kW for on-propulsion consumption
43 .thruster(Thruster {
44 // "NEXT-STEP" row in Table 2
45 isp_s: 4435.0,
46 thrust_N: 0.472,
47 })
48 .mode(GuidanceMode::Thrust) // Start thrusting immediately.
49 .build();
50
51 // Set up the spacecraft dynamics like in the orbit raise example.
52
53 let prop_time = 30.0 * Unit::Day;
54
55 // Define the guidance law -- we're just using a Ruggiero controller as demonstrated in AAS-2004-5089.
56 let objectives = &[
57 Objective::within_tolerance(
58 StateParameter::Element(OrbitalElement::SemiMajorAxis),
59 42_165.0,
60 20.0,
61 ),
62 Objective::within_tolerance(
63 StateParameter::Element(OrbitalElement::Eccentricity),
64 0.001,
65 5e-5,
66 ),
67 Objective::within_tolerance(
68 StateParameter::Element(OrbitalElement::Inclination),
69 0.05,
70 1e-2,
71 ),
72 ];
73
74 let ruggiero_ctrl = Ruggiero::from_max_eclipse(objectives, sc, 0.2)?;
75 println!("{ruggiero_ctrl}");
76
77 let mut orbital_dyn = OrbitalDynamics::point_masses(vec![MOON, SUN]);
78
79 let mut jgm3_meta = MetaFile {
80 uri: "http://public-data.nyxspace.com/nyx/models/JGM3.cof.gz".to_string(),
81 crc32: Some(0xF446F027), // Specifying the CRC32 avoids redownloading it if it's cached.
82 };
83 jgm3_meta.process(true)?;
84
85 let harmonics = GravityField::new(GravityFieldData::from_cof(
86 &jgm3_meta.uri,
87 8,
88 8,
89 true,
90 almanac.frame_info(IAU_EARTH_FRAME)?,
91 )?);
92 orbital_dyn.accel_models.push(harmonics);
93
94 let srp_dyn = SolarPressure::default_flux(EARTH_J2000, &almanac)?;
95 let sc_dynamics = SpacecraftDynamics::from_model(orbital_dyn, srp_dyn)
96 .with_guidance_law(ruggiero_ctrl.clone());
97
98 println!("{sc_dynamics}");
99
100 // Finally, let's use the Monte Carlo framework built into Nyx to propagate spacecraft.
101
102 // Let's start by defining the dispersion.
103 // The MultivariateNormal structure allows us to define the dispersions in any of the orbital parameters, but these are applied directly in the Cartesian state space.
104 // Note that additional validation on the MVN is in progress -- https://github.com/nyx-space/nyx/issues/339.
105 let mc_rv = MvnSpacecraft::new(
106 sc,
107 vec![StateDispersion::zero_mean(
108 StateParameter::Element(OrbitalElement::SemiMajorAxis),
109 3.0,
110 )],
111 )?;
112
113 let my_mc = MonteCarlo::new(
114 sc, // Nominal state
115 mc_rv,
116 "03_geo_sk".to_string(), // Scenario name
117 None, // No specific seed specified, so one will be drawn from the computer's entropy.
118 );
119
120 // Build the propagator setup.
121 let setup = Propagator::rk89(
122 sc_dynamics.clone(),
123 IntegratorOptions::builder()
124 .min_step(10.0_f64.seconds())
125 .error_ctrl(ErrorControl::RSSCartesianStep)
126 .build(),
127 );
128
129 let num_runs = 25;
130 let rslts = my_mc.run_until_epoch(setup, almanac.clone(), sc.epoch() + prop_time, num_runs);
131
132 assert_eq!(rslts.runs.len(), num_runs);
133
134 rslts.to_parquet("03_geo_sk.parquet", ExportCfg::default())?;
135
136 Ok(())
137}More examples
27fn main() -> Result<(), Box<dyn Error>> {
28 pel::init();
29
30 // Dynamics models require planetary constants and ephemerides to be defined.
31 // Let's start by grabbing those by using ANISE's latest MetaAlmanac.
32 // This will automatically download the DE440s planetary ephemeris,
33 // the daily-updated Earth Orientation Parameters, the high fidelity Moon orientation
34 // parameters (for the Moon Mean Earth and Moon Principal Axes frames), and the PCK11
35 // planetary constants kernels.
36 // For details, refer to https://github.com/nyx-space/anise/blob/master/data/latest.dhall.
37 // Note that we place the Almanac into an Arc so we can clone it cheaply and provide read-only
38 // references to many functions.
39 let almanac = Arc::new(MetaAlmanac::latest().map_err(Box::new)?);
40 // Fetch the EME2000 frame from the Almabac
41 let eme2k = almanac.frame_info(EARTH_J2000).unwrap();
42 // Define the orbit epoch
43 let epoch = Epoch::from_gregorian_utc_hms(2024, 2, 29, 12, 13, 14);
44
45 // Build the spacecraft itself.
46 // Using slide 6 of https://aerospace.org/sites/default/files/2018-11/Davis-Mayberry_HPSEP_11212018.pdf
47 // for the "next gen" SEP characteristics.
48
49 // GTO start
50 let orbit = Orbit::keplerian(24505.9, 0.725, 7.05, 0.0, 0.0, 0.0, epoch, eme2k);
51
52 let sc = Spacecraft::builder()
53 .orbit(orbit)
54 .mass(Mass::from_dry_and_prop_masses(1000.0, 1000.0)) // 1000 kg of dry mass and prop, totalling 2.0 tons
55 .srp(SRPData::from_area(3.0 * 6.0)) // Assuming 1 kW/m^2 or 18 kW, giving a margin of 4.35 kW for on-propulsion consumption
56 .thruster(Thruster {
57 // "NEXT-STEP" row in Table 2
58 isp_s: 4435.0,
59 thrust_N: 0.472,
60 })
61 .mode(GuidanceMode::Thrust) // Start thrusting immediately.
62 .build();
63
64 let prop_time = 180.0 * Unit::Day;
65
66 // Define the guidance law -- we're just using a Ruggiero controller as demonstrated in AAS-2004-5089.
67 let objectives = &[
68 Objective::within_tolerance(
69 StateParameter::Element(OrbitalElement::SemiMajorAxis),
70 42_165.0,
71 20.0,
72 ),
73 Objective::within_tolerance(
74 StateParameter::Element(OrbitalElement::Eccentricity),
75 0.001,
76 5e-5,
77 ),
78 Objective::within_tolerance(
79 StateParameter::Element(OrbitalElement::Inclination),
80 0.05,
81 1e-2,
82 ),
83 ];
84
85 // Ensure that we only thrust if we have more than 20% illumination.
86 let ruggiero_ctrl = Ruggiero::from_max_eclipse(objectives, sc, 0.2).unwrap();
87 println!("{ruggiero_ctrl}");
88
89 // Define the high fidelity dynamics
90
91 // Set up the spacecraft dynamics.
92
93 // Specify that the orbital dynamics must account for the graviational pull of the Moon and the Sun.
94 // The gravity of the Earth will also be accounted for since the spaceraft in an Earth orbit.
95 let mut orbital_dyn = OrbitalDynamics::point_masses(vec![MOON, SUN]);
96
97 // We want to include the spherical harmonics, so let's download the gravitational data from the Nyx Cloud.
98 // We're using the JGM3 model here, which is the default in GMAT.
99 let mut jgm3_meta = MetaFile {
100 uri: "http://public-data.nyxspace.com/nyx/models/JGM3.cof.gz".to_string(),
101 crc32: Some(0xF446F027), // Specifying the CRC32 avoids redownloading it if it's cached.
102 };
103 // And let's download it if we don't have it yet.
104 jgm3_meta.process(true)?;
105
106 // Build the spherical harmonics.
107 // The harmonics must be computed in the body fixed frame.
108 // We're using the long term prediction of the Earth centered Earth fixed frame, IAU Earth.
109 let harmonics = GravityField::new(
110 GravityFieldData::from_cof(
111 &jgm3_meta.uri,
112 8,
113 8,
114 true,
115 almanac.frame_info(IAU_EARTH_FRAME)?,
116 )
117 .unwrap(),
118 );
119
120 // Include the spherical harmonics into the orbital dynamics.
121 orbital_dyn.accel_models.push(harmonics);
122
123 // We define the solar radiation pressure, using the default solar flux and accounting only
124 // for the eclipsing caused by the Earth.
125 let srp_dyn = SolarPressure::default_flux(EARTH_J2000, &almanac)?;
126
127 // Finalize setting up the dynamics, specifying the force models (orbital_dyn) separately from the
128 // acceleration models (SRP in this case). Use `from_models` to specify multiple accel models.
129 let sc_dynamics = SpacecraftDynamics::from_model(orbital_dyn, srp_dyn)
130 .with_guidance_law(ruggiero_ctrl.clone());
131
132 println!("{orbit:x}");
133
134 // We specify a minimum step in the propagator because the Ruggiero control would otherwise drive this step very low.
135 let (final_state, traj) = Propagator::rk89(
136 sc_dynamics.clone(),
137 IntegratorOptions::builder()
138 .min_step(10.0_f64.seconds())
139 .error_ctrl(ErrorControl::RSSCartesianStep)
140 .build(),
141 )
142 .with(sc, almanac.clone())
143 .for_duration_with_traj(prop_time)?;
144
145 let prop_usage = sc.mass.prop_mass_kg - final_state.mass.prop_mass_kg;
146 println!("{:x}", final_state.orbit);
147 println!("prop usage: {prop_usage:.3} kg");
148
149 // Finally, export the results for analysis, including the penumbra percentage throughout the orbit raise.
150 traj.to_parquet("./03_geo_raise.parquet", ExportCfg::default())?;
151
152 for status_line in ruggiero_ctrl.status(&final_state) {
153 println!("{status_line}");
154 }
155
156 ruggiero_ctrl
157 .achieved(&final_state)
158 .expect("objective not achieved");
159
160 Ok(())
161}Sourcepub fn assess(&self, achieved: &Spacecraft) -> Result<(bool, f64), StateError>
pub fn assess(&self, achieved: &Spacecraft) -> Result<(bool, f64), StateError>
Returns whether this objective has been achieved, and the associated parameter error.
Sourcepub fn assess_value(&self, achieved: f64) -> (bool, f64)
pub fn assess_value(&self, achieved: f64) -> (bool, f64)
Returns whether this objective has been achieved, and the associated parameter error.
Warning: the parameter achieved must be in the same unit as the objective.
Trait Implementations§
impl Copy for Objective
Source§impl<'de> Deserialize<'de> for Objective
impl<'de> Deserialize<'de> for Objective
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Source§impl StaticType for Objective
impl StaticType for Objective
Source§fn static_type() -> SimpleType
fn static_type() -> SimpleType
Auto Trait Implementations§
impl Freeze for Objective
impl RefUnwindSafe for Objective
impl Send for Objective
impl Sync for Objective
impl Unpin for Objective
impl UnsafeUnpin for Objective
impl UnwindSafe for Objective
Blanket Implementations§
impl<T> Allocation for T
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<T> FromDhall for Twhere
T: DeserializeOwned,
impl<T> FromDhall for Twhere
T: DeserializeOwned,
fn from_dhall(v: &Value) -> Result<T, Error>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more§impl<T> Pointable for T
impl<T> Pointable for T
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
self from the equivalent element of its
superset. Read more§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
self is actually part of its subset T (and can be converted to it).§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
self.to_subset but without any property checks. Always succeeds.§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
self to the equivalent element of its superset.§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
self from the equivalent element of its
superset. Read more§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
self is actually part of its subset T (and can be converted to it).§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
self.to_subset but without any property checks. Always succeeds.§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
self to the equivalent element of its superset.