Skip to content

Commit bda8ba3

Browse files
Implement maneuver representation enum
1 parent d9f661c commit bda8ba3

File tree

9 files changed

+281
-143
lines changed

9 files changed

+281
-143
lines changed

src/dynamics/guidance/mnvr.rs

+114-70
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,8 @@ pub struct Maneuver {
4444
/// Thrust level, if 1.0 use all thruster available at full power
4545
/// TODO: Convert this to a common polynomial as well to optimize throttle, throttle rate (and accel?)
4646
pub thrust_prct: f64,
47-
/// The interpolation polynomial for the azimuth (in-plane) angle
48-
pub alpha_inplane_radians: CommonPolynomial,
49-
/// The interpolation polynomial for the elevation (out-of-plane) angle
50-
pub delta_outofplane_radians: CommonPolynomial,
47+
/// The representation of this maneuver.
48+
pub representation: MnvrRepr,
5149
/// The frame in which the maneuvers are defined.
5250
pub frame: LocalFrame,
5351
}
@@ -67,11 +65,7 @@ impl fmt::Display for Maneuver {
6765
self.end - self.start,
6866
self.end,
6967
)?;
70-
write!(
71-
f,
72-
"\n\tin-plane angle α: {}\n\tout-of-plane angle β: {}",
73-
self.alpha_inplane_radians, self.delta_outofplane_radians
74-
)?;
68+
write!(f, "\n{}", self.representation)?;
7569
write!(
7670
f,
7771
"\n\tinitial dir: [{:.6}, {:.6}, {:.6}]\n\tfinal dir : [{:.6}, {:.6}, {:.6}]",
@@ -80,13 +74,40 @@ impl fmt::Display for Maneuver {
8074
} else {
8175
write!(
8276
f,
83-
"Impulsive maneuver @ {}\n\tin-plane angle α: {}\n\tout-of-plane angle β: {}",
84-
self.start, self.alpha_inplane_radians, self.delta_outofplane_radians
77+
"Impulsive maneuver @ {}\n{}",
78+
self.start, self.representation
8579
)
8680
}
8781
}
8882
}
8983

84+
/// Defines the available maneuver representations.
85+
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
86+
pub enum MnvrRepr {
87+
/// Represents the maneuver as a fixed vector in the local frame.
88+
Vector(Vector3<f64>),
89+
/// Represents the maneuver as a polynominal of azimuth (right ascension / in-plane) and elevation (declination / out of plane)
90+
Angles {
91+
azimuth: CommonPolynomial,
92+
elevation: CommonPolynomial,
93+
},
94+
}
95+
96+
impl fmt::Display for MnvrRepr {
97+
/// Prints the polynomial with the least significant coefficients first
98+
#[allow(clippy::identity_op)]
99+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
100+
match self {
101+
MnvrRepr::Vector(vector) => write!(f, "{vector}"),
102+
MnvrRepr::Angles { azimuth, elevation } => write!(
103+
f,
104+
"\tazimuth (in-plane) α: {}\n\televation (out-of-plane) β: {}",
105+
azimuth, elevation
106+
),
107+
}
108+
}
109+
}
110+
90111
impl Maneuver {
91112
/// Creates an impulsive maneuver whose vector is the deltaV.
92113
/// TODO: This should use William's algorithm
@@ -102,24 +123,26 @@ impl Maneuver {
102123
vector: Vector3<f64>,
103124
frame: LocalFrame,
104125
) -> Self {
105-
// Convert to angles
106-
let (alpha, delta) = ra_dec_from_unit_vector(vector);
107126
Self {
108127
start,
109128
end,
110129
thrust_prct: thrust_lvl,
111-
alpha_inplane_radians: CommonPolynomial::Constant(alpha),
112-
delta_outofplane_radians: CommonPolynomial::Constant(delta),
130+
representation: MnvrRepr::Vector(vector),
113131
frame,
114132
}
115133
}
116134

117135
/// Return the thrust vector computed at the provided epoch
118136
pub fn vector(&self, epoch: Epoch) -> Vector3<f64> {
119-
let t = (epoch - self.start).to_seconds();
120-
let alpha = self.alpha_inplane_radians.eval(t);
121-
let delta = self.delta_outofplane_radians.eval(t);
122-
unit_vector_from_ra_dec(alpha, delta)
137+
match self.representation {
138+
MnvrRepr::Vector(vector) => vector,
139+
MnvrRepr::Angles { azimuth, elevation } => {
140+
let t = (epoch - self.start).to_seconds();
141+
let alpha = azimuth.eval(t);
142+
let delta = elevation.eval(t);
143+
unit_vector_from_ra_dec(alpha, delta)
144+
}
145+
}
123146
}
124147

125148
/// Return the duration of this maneuver
@@ -134,9 +157,14 @@ impl Maneuver {
134157

135158
/// Returns the direction of the burn at the start of the burn, useful for setting new angles
136159
pub fn direction(&self) -> Vector3<f64> {
137-
let alpha = self.alpha_inplane_radians.coeff_in_order(0).unwrap();
138-
let delta = self.delta_outofplane_radians.coeff_in_order(0).unwrap();
139-
unit_vector_from_ra_dec(alpha, delta)
160+
match self.representation {
161+
MnvrRepr::Vector(vector) => vector / vector.norm(),
162+
MnvrRepr::Angles { azimuth, elevation } => {
163+
let alpha = azimuth.coeff_in_order(0).unwrap();
164+
let delta = elevation.coeff_in_order(0).unwrap();
165+
unit_vector_from_ra_dec(alpha, delta)
166+
}
167+
}
140168
}
141169

142170
/// Set the time-invariant direction for this finite burn while keeping the other components as they are
@@ -146,12 +174,15 @@ impl Maneuver {
146174

147175
/// Returns the rate of direction of the burn at the start of the burn, useful for setting new angles
148176
pub fn rate(&self) -> Vector3<f64> {
149-
match self.alpha_inplane_radians.coeff_in_order(1) {
150-
Ok(alpha) => {
151-
let delta = self.delta_outofplane_radians.coeff_in_order(1).unwrap();
152-
unit_vector_from_ra_dec(alpha, delta)
153-
}
154-
Err(_) => Vector3::zeros(),
177+
match self.representation {
178+
MnvrRepr::Vector(_) => Vector3::zeros(),
179+
MnvrRepr::Angles { azimuth, elevation } => match azimuth.coeff_in_order(1) {
180+
Ok(alpha) => {
181+
let delta = elevation.coeff_in_order(1).unwrap();
182+
unit_vector_from_ra_dec(alpha, delta)
183+
}
184+
Err(_) => Vector3::zeros(),
185+
},
155186
}
156187
}
157188

@@ -162,12 +193,15 @@ impl Maneuver {
162193

163194
/// Returns the acceleration of the burn at the start of the burn, useful for setting new angles
164195
pub fn accel(&self) -> Vector3<f64> {
165-
match self.alpha_inplane_radians.coeff_in_order(2) {
166-
Ok(alpha) => {
167-
let delta = self.delta_outofplane_radians.coeff_in_order(2).unwrap();
168-
unit_vector_from_ra_dec(alpha, delta)
169-
}
170-
Err(_) => Vector3::zeros(),
196+
match self.representation {
197+
MnvrRepr::Vector(_) => Vector3::zeros(),
198+
MnvrRepr::Angles { azimuth, elevation } => match azimuth.coeff_in_order(2) {
199+
Ok(alpha) => {
200+
let delta = elevation.coeff_in_order(2).unwrap();
201+
unit_vector_from_ra_dec(alpha, delta)
202+
}
203+
Err(_) => Vector3::zeros(),
204+
},
171205
}
172206
}
173207

@@ -183,48 +217,58 @@ impl Maneuver {
183217
rate: Vector3<f64>,
184218
accel: Vector3<f64>,
185219
) -> Result<(), GuidanceError> {
186-
let (alpha, delta) = ra_dec_from_unit_vector(dir);
187-
if alpha.is_nan() || delta.is_nan() {
188-
return Err(GuidanceError::InvalidDirection {
189-
x: dir[0],
190-
y: dir[1],
191-
z: dir[2],
192-
in_plane_deg: alpha.to_degrees(),
193-
out_of_plane_deg: delta.to_degrees(),
194-
});
195-
}
196-
if rate.norm() < 2e-16 && accel.norm() < 2e-16 {
197-
self.alpha_inplane_radians = CommonPolynomial::Constant(alpha);
198-
self.delta_outofplane_radians = CommonPolynomial::Constant(delta);
220+
if rate.norm() < f64::EPSILON && accel.norm() < f64::EPSILON {
221+
// Set as a vector
222+
self.representation = MnvrRepr::Vector(dir)
199223
} else {
200-
let (alpha_dt, delta_dt) = ra_dec_from_unit_vector(rate);
201-
if alpha_dt.is_nan() || delta_dt.is_nan() {
202-
return Err(GuidanceError::InvalidRate {
203-
x: rate[0],
204-
y: rate[1],
205-
z: rate[2],
206-
in_plane_deg_s: alpha_dt.to_degrees(),
207-
out_of_plane_deg_s: delta_dt.to_degrees(),
224+
let (alpha, delta) = ra_dec_from_unit_vector(dir);
225+
if alpha.is_nan() || delta.is_nan() {
226+
return Err(GuidanceError::InvalidDirection {
227+
x: dir[0],
228+
y: dir[1],
229+
z: dir[2],
230+
in_plane_deg: alpha.to_degrees(),
231+
out_of_plane_deg: delta.to_degrees(),
208232
});
209233
}
210-
if accel.norm() < 2e-16 {
211-
self.alpha_inplane_radians = CommonPolynomial::Linear(alpha_dt, alpha);
212-
self.delta_outofplane_radians = CommonPolynomial::Linear(delta_dt, delta);
234+
if rate.norm() < f64::EPSILON && accel.norm() < f64::EPSILON {
235+
self.representation = MnvrRepr::Angles {
236+
azimuth: CommonPolynomial::Constant(alpha),
237+
elevation: CommonPolynomial::Constant(delta),
238+
};
213239
} else {
214-
let (alpha_ddt, delta_ddt) = ra_dec_from_unit_vector(accel);
215-
if alpha_ddt.is_nan() || delta_ddt.is_nan() {
216-
return Err(GuidanceError::InvalidAcceleration {
217-
x: accel[0],
218-
y: accel[1],
219-
z: accel[2],
220-
in_plane_deg_s2: alpha_ddt.to_degrees(),
221-
out_of_plane_deg_s2: delta_ddt.to_degrees(),
240+
let (alpha_dt, delta_dt) = ra_dec_from_unit_vector(rate);
241+
if alpha_dt.is_nan() || delta_dt.is_nan() {
242+
return Err(GuidanceError::InvalidRate {
243+
x: rate[0],
244+
y: rate[1],
245+
z: rate[2],
246+
in_plane_deg_s: alpha_dt.to_degrees(),
247+
out_of_plane_deg_s: delta_dt.to_degrees(),
222248
});
223249
}
224-
self.alpha_inplane_radians =
225-
CommonPolynomial::Quadratic(alpha_ddt, alpha_dt, alpha);
226-
self.delta_outofplane_radians =
227-
CommonPolynomial::Quadratic(delta_ddt, delta_dt, delta);
250+
if accel.norm() < f64::EPSILON {
251+
self.representation = MnvrRepr::Angles {
252+
azimuth: CommonPolynomial::Linear(alpha_dt, alpha),
253+
elevation: CommonPolynomial::Linear(delta_dt, delta),
254+
};
255+
} else {
256+
let (alpha_ddt, delta_ddt) = ra_dec_from_unit_vector(accel);
257+
if alpha_ddt.is_nan() || delta_ddt.is_nan() {
258+
return Err(GuidanceError::InvalidAcceleration {
259+
x: accel[0],
260+
y: accel[1],
261+
z: accel[2],
262+
in_plane_deg_s2: alpha_ddt.to_degrees(),
263+
out_of_plane_deg_s2: delta_ddt.to_degrees(),
264+
});
265+
}
266+
267+
self.representation = MnvrRepr::Angles {
268+
azimuth: CommonPolynomial::Quadratic(alpha_ddt, alpha_dt, alpha),
269+
elevation: CommonPolynomial::Quadratic(delta_ddt, delta_dt, delta),
270+
};
271+
}
228272
}
229273
}
230274
Ok(())

src/dynamics/guidance/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ mod finiteburns;
2929
pub use finiteburns::FiniteBurns;
3030

3131
mod mnvr;
32-
pub use mnvr::Maneuver;
32+
pub use mnvr::{Maneuver, MnvrRepr};
3333

3434
mod ruggiero;
3535
pub use ruggiero::{Objective, Ruggiero, StateParameter};
@@ -182,8 +182,8 @@ fn ra_dec_from_vec() {
182182
loop {
183183
let unit_v = unit_vector_from_ra_dec(alpha, delta);
184184
let (alpha2, delta2) = ra_dec_from_unit_vector(unit_v);
185-
assert!((alpha - alpha2).abs() < 2e-16);
186-
assert!((delta - delta2).abs() < 2e-16);
185+
assert!((alpha - alpha2).abs() < f64::EPSILON);
186+
assert!((delta - delta2).abs() < f64::EPSILON);
187187
alpha += TAU * 0.1; // Increment right ascension by one tenth of a circle
188188
if alpha > PI {
189189
alpha = 0.0;

src/md/opti/multipleshooting/equidistant_heuristic.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ impl<'a> MultipleShooting<'a, Node, 3, 3> {
4141

4242
// Compute the direction of the objective
4343
let mut direction = xf.radius_km - x0.orbit.radius_km;
44-
if direction.norm() < 2e-16 {
44+
if direction.norm() < f64::EPSILON {
4545
return Err(TargetingError::TargetsTooClose);
4646
}
4747
let distance_increment = direction.norm() / (node_count as f64);

0 commit comments

Comments
 (0)