Skip to content

Commit 4a403e5

Browse files
Now using ground station elevation event arcs to build measurements
This is both realistic and very fast.
1 parent 631000a commit 4a403e5

File tree

6 files changed

+99
-91
lines changed

6 files changed

+99
-91
lines changed

src/md/events/edge.rs renamed to src/md/events/details.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,3 +165,29 @@ where
165165
)
166166
}
167167
}
168+
169+
#[derive(Clone, Debug, PartialEq)]
170+
pub struct EventArc<S: Interpolatable>
171+
where
172+
DefaultAllocator:
173+
Allocator<f64, S::VecLength> + Allocator<f64, S::Size> + Allocator<f64, S::Size, S::Size>,
174+
{
175+
pub rise: EventDetails<S>,
176+
pub fall: EventDetails<S>,
177+
}
178+
179+
impl<S: Interpolatable> fmt::Display for EventArc<S>
180+
where
181+
DefaultAllocator:
182+
Allocator<f64, S::VecLength> + Allocator<f64, S::Size> + Allocator<f64, S::Size, S::Size>,
183+
{
184+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
185+
write!(
186+
f,
187+
"{} until {} (lasts {})",
188+
self.rise,
189+
self.fall.state.epoch(),
190+
self.fall.state.epoch() - self.rise.state.epoch()
191+
)
192+
}
193+
}

src/md/events/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
along with this program. If not, see <https://www.gnu.org/licenses/>.
1717
*/
1818

19-
pub mod edge;
19+
pub mod details;
2020
pub mod evaluators;
2121
pub mod search;
2222
use super::StateParameter;

src/md/events/search.rs

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
along with this program. If not, see <https://www.gnu.org/licenses/>.
1717
*/
1818

19-
use super::edge::{EventDetails, EventEdge};
19+
use super::details::{EventArc, EventDetails, EventEdge};
2020
use crate::errors::NyxError;
2121
use crate::linalg::allocator::Allocator;
2222
use crate::linalg::DefaultAllocator;
@@ -283,11 +283,11 @@ where
283283
states.dedup();
284284

285285
match states.len() {
286-
0 => info!("{event} not found"),
287-
1 => info!("{event} found once on {}", states[0].state.epoch()),
286+
0 => info!("Event {event} not found"),
287+
1 => info!("Event {event} found once on {}", states[0].state.epoch()),
288288
_ => {
289289
info!(
290-
"{event} found {} times from {} until {}",
290+
"Event {event} found {} times from {} until {}",
291291
states.len(),
292292
states.first().unwrap().state.epoch(),
293293
states.last().unwrap().state.epoch()
@@ -346,7 +346,7 @@ where
346346
/// - `event`: A reference to an object implementing the `EventEvaluator<S>` trait, which is used to evaluate and classify events in the trajectory.
347347
///
348348
/// # Returns
349-
/// - `Result<Vec<(EventDetails<S>, EventDetails<S>)>, NyxError>`: On success, returns a vector of tuples, where each tuple contains a pair of `EventDetails` (one for the rising edge and one for the falling edge). Returns an error if any issues occur during the event evaluation process.
349+
/// - `Result<Vec<EventArc>, NyxError>`: On success, returns a vector of EventArc, where each struct contains a pair of `EventDetails` (one for the rising edge and one for the falling edge). Returns an error if any issues occur during the event evaluation process.
350350
///
351351
/// # Logic
352352
/// - Sorts the events by their epoch to ensure chronological processing.
@@ -356,10 +356,7 @@ where
356356
/// - Prints debug information for each event and arc.
357357
///
358358
359-
pub fn find_arcs<E>(
360-
&self,
361-
event: &E,
362-
) -> Result<Vec<(EventDetails<S>, EventDetails<S>)>, NyxError>
359+
pub fn find_arcs<E>(&self, event: &E) -> Result<Vec<EventArc<S>>, NyxError>
363360
where
364361
E: EventEvaluator<S>,
365362
{
@@ -389,26 +386,28 @@ where
389386
};
390387

391388
for event in events {
392-
println!("{event}");
393389
if event.edge == EventEdge::Rising {
394390
if prev_rise.is_none() && prev_fall.is_none() {
395391
// This is a new rising edge
396392
prev_rise = Some(event.clone());
397393
} else if prev_fall.is_some() {
398394
// We've found a transition from a fall to a rise, so we can close this arc out.
399395
if prev_rise.is_some() {
400-
arcs.push((prev_rise.clone().unwrap(), prev_fall.clone().unwrap()));
396+
let arc = EventArc {
397+
rise: prev_rise.clone().unwrap(),
398+
fall: prev_fall.clone().unwrap(),
399+
};
400+
arcs.push(arc);
401401
} else {
402-
arcs.push((event.clone(), prev_fall.clone().unwrap()));
402+
let arc = EventArc {
403+
rise: event.clone(),
404+
fall: prev_fall.clone().unwrap(),
405+
};
406+
arcs.push(arc);
403407
}
404408
prev_fall = None;
405409
// We have a new rising edge since this is how we ended up here.
406410
prev_rise = Some(event.clone());
407-
println!(
408-
"{} <-> {}",
409-
arcs.last().unwrap().0.state.epoch(),
410-
arcs.last().unwrap().1.state.epoch()
411-
);
412411
}
413412
} else if event.edge == EventEdge::Falling {
414413
prev_fall = Some(event.clone());
@@ -418,12 +417,20 @@ where
418417
// Add the final pass
419418
if prev_rise.is_some() {
420419
if prev_fall.is_some() {
421-
arcs.push((prev_rise.clone().unwrap(), prev_fall.clone().unwrap()));
420+
let arc = EventArc {
421+
rise: prev_rise.clone().unwrap(),
422+
fall: prev_fall.clone().unwrap(),
423+
};
424+
arcs.push(arc);
422425
} else {
423426
// Use the last trajectory as the end of the arc
424427
let value = event.eval(self.last());
425428
let fall = EventDetails::new(*self.last(), value, event, self)?;
426-
arcs.push((prev_rise.clone().unwrap(), fall));
429+
let arc = EventArc {
430+
rise: prev_rise.clone().unwrap(),
431+
fall,
432+
};
433+
arcs.push(arc);
427434
}
428435
}
429436

src/od/ground_station.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,6 @@ where
441441
// Source: Vallado, section 4.4.3
442442
// Only the sine is needed as per Vallado, and the formula is the same as the declination
443443
// because we're in the SEZ frame.
444-
// angled_value(rho_sez.declination_deg(), self.elevation_mask_deg)
445444
rho_sez.declination_deg() - self.elevation_mask_deg
446445
}
447446

src/od/simulator/arc.rs

Lines changed: 45 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -270,84 +270,60 @@ impl TrackingArcSim<Orbit, RangeDoppler, GroundStation> {
270270
) -> Result<HashMap<String, TrkConfig>, NyxError> {
271271
// Consider using find_all via the heuristic
272272
let mut built_cfg = self.configs.clone();
273-
'devices: for (name, device) in self.devices.iter() {
273+
for (name, device) in self.devices.iter() {
274274
let cfg = &self.configs[name];
275275
if let Some(scheduler) = cfg.scheduler {
276276
info!("Building schedule for {name}");
277277
built_cfg.get_mut(name).unwrap().scheduler = None;
278278
built_cfg.get_mut(name).unwrap().strands = Some(Vec::new());
279279
// Convert the trajectory into the ground station frame.
280280
let traj = self.trajectory.to_frame(device.frame, cosm.clone())?;
281-
let mut start_at = traj.first().epoch;
282-
let end_at = traj.last().epoch;
283-
284-
let elevation_events = traj.find_arcs(&device).unwrap();
285-
for (rise, fall) in elevation_events {
286-
println!(
287-
"{name} -> {:?} at {} -> {:?} {}",
288-
rise.edge,
289-
rise.state.epoch(),
290-
fall.edge,
291-
fall.state.epoch()
292-
);
281+
282+
let elevation_arcs = traj.find_arcs(&device).unwrap();
283+
for arc in elevation_arcs {
284+
info!("Working on {arc}");
285+
let strand_start = arc.rise.state.epoch();
286+
let strand_end = arc.fall.state.epoch();
287+
288+
let mut strand_range = EpochRanges {
289+
start: strand_start,
290+
end: strand_end,
291+
};
292+
293+
if let Cadence::Intermittent { on, off } = scheduler.cadence {
294+
// Check that the next start time is within the allocated time
295+
if let Some(prev_strand) = built_cfg[name].strands.as_ref().unwrap().last()
296+
{
297+
if prev_strand.end + off > strand_range.start {
298+
// We're turning on the tracking sooner than the schedule allows, so let's fix that.
299+
strand_range.start = prev_strand.end + off;
300+
// Check that we didn't eat into the whole tracking opportunity
301+
if strand_range.start > strand_end {
302+
// Lost this whole opportunity.
303+
info!("Discarding {name} opportunity from {} to {} due to cadence {:?}", strand_start, strand_end, scheduler.cadence);
304+
}
305+
}
306+
}
307+
// Check that we aren't tracking for longer than configured
308+
if strand_range.end - strand_range.start > on {
309+
strand_range.end = strand_range.start + on;
310+
}
311+
}
312+
313+
// We've found when the spacecraft is below the horizon, so this is a new strand.
314+
built_cfg
315+
.get_mut(name)
316+
.unwrap()
317+
.strands
318+
.as_mut()
319+
.unwrap()
320+
.push(strand_range);
293321
}
294322

295-
// while start_at < end_at {
296-
// if let Ok(visibility_event) = traj.find_bracketed(start_at, end_at, &device) {
297-
// // We've found when the spacecraft is visible
298-
// start_at = visibility_event.epoch;
299-
// // Search for when the spacecraft is no longer visible.
300-
// if let Ok(visibility_event) =
301-
// traj.find_bracketed(start_at + cfg.sampling, end_at, &device)
302-
// {
303-
// let strand_end = visibility_event.epoch;
304-
// let mut strand_range = EpochRanges {
305-
// start: start_at,
306-
// end: strand_end,
307-
// };
308-
309-
// if let Cadence::Intermittent { on, off } = scheduler.cadence {
310-
// // Check that the next start time is within the allocated time
311-
// if let Some(prev_strand) =
312-
// built_cfg[name].strands.as_ref().unwrap().last()
313-
// {
314-
// if prev_strand.end + off > strand_range.start {
315-
// // We're turning on the tracking sooner than the schedule allows, so let's fix that.
316-
// strand_range.start = prev_strand.end + off;
317-
// // Check that we didn't eat into the whole tracking opportunity
318-
// if strand_range.start > strand_end {
319-
// // Lost this whole opportunity.
320-
// info!("Discarding {name} opportunity from {} to {} due to cadence {:?}", start_at, strand_end, scheduler.cadence);
321-
// }
322-
// }
323-
// }
324-
// // Check that we aren't tracking for longer than configured
325-
// if strand_range.end - strand_range.start > on {
326-
// strand_range.end = strand_range.start + on;
327-
// }
328-
// }
329-
330-
// // We've found when the spacecraft is below the horizon, so this is a new strand.
331-
// built_cfg
332-
// .get_mut(name)
333-
// .unwrap()
334-
// .strands
335-
// .as_mut()
336-
// .unwrap()
337-
// .push(strand_range);
338-
// // Set the new start time and continue searching
339-
// start_at = strand_end;
340-
// } else {
341-
// continue 'devices;
342-
// }
343-
// } else {
344-
// info!(
345-
// "Built {} tracking strands for {name}",
346-
// built_cfg[name].strands.as_ref().unwrap().len()
347-
// );
348-
// continue 'devices;
349-
// }
350-
// }
323+
info!(
324+
"Built {} tracking strands for {name}",
325+
built_cfg[name].strands.as_ref().unwrap().len()
326+
);
351327
}
352328
}
353329
// todo!("remove overlaps")

tests/orbit_determination/simulator.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ fn continuous_tracking() {
115115

116116
println!("{arc_concrete}");
117117

118-
assert_eq!(arc.measurements.len(), 146);
118+
assert_eq!(arc.measurements.len(), 144);
119119
// Check that we've loaded all of the measurements
120120
assert_eq!(arc_concrete.measurements.len(), arc.measurements.len());
121121
// Check that we find the same device names too

0 commit comments

Comments
 (0)