melvin_ob/objective/beacon_objective.rs
1use crate::STATIC_ORBIT_VEL;
2use crate::util::{Vec2D, logger::JsonDump};
3use super::BayesianSet;
4use chrono::{DateTime, TimeDelta, Utc};
5use fixed::types::I32F32;
6use std::cmp::Ordering;
7
8/// Represents a beacon measurement with associated properties.
9#[derive(Debug, Clone, serde::Serialize)]
10pub struct BeaconMeas {
11 /// Unique identifier of the beacon.
12 id: usize,
13 /// Position of MELVIN when the beacon measurement was received.
14 pos: Vec2D<I32F32>,
15 /// Received Signal Strength Indicator (RSSI) or `d_noisy` of the beacon.
16 rssi: f64,
17 /// Time delay associated with the beacon measurement and the observed position.
18 delay: TimeDelta,
19}
20
21impl BeaconMeas {
22 /// Creates a new [`BeaconMeas`] instance.
23 ///
24 /// # Arguments
25 /// * `id` - Unique identifier of the beacon.
26 /// * `pos` - Position of MELVIN as a 2D vector.
27 /// * `rssi` - RSSI (`d_noisy`) value of the beacon.
28 /// * `delay` - Time delay for the beacon.
29 pub fn new(id: usize, pos: Vec2D<I32F32>, rssi: f64, delay: TimeDelta) -> Self {
30 Self { id, pos, rssi, delay }
31 }
32
33 /// Returns the unique identifier of the beacon.
34 pub fn id(&self) -> usize { self.id }
35 /// Returns a reference to the position of the beacon.
36 pub fn pos(&self) -> &Vec2D<I32F32> { &self.pos }
37 /// Returns the RSSI of the beacon.
38 pub fn rssi(&self) -> f64 { self.rssi }
39
40 /// Computes and returns the corrected position of MELVIN.
41 ///
42 /// This considers the delay and adjusts the position accordingly using
43 /// `STATIC_ORBIT_VEL`.
44 pub fn corr_pos(&self) -> Vec2D<I32F32> {
45 let delay_s_fixed =
46 I32F32::from_num(self.delay.num_milliseconds()) / I32F32::from_num(1000);
47 (self.pos - Vec2D::from(STATIC_ORBIT_VEL) * delay_s_fixed).wrap_around_map().round()
48 }
49
50 /// Returns the time delay associated with the beacon measurement.
51 pub fn delay(&self) -> TimeDelta { self.delay }
52}
53
54/// Represents a beacon objective with associated metadata and measurements.
55#[derive(Debug, Clone, serde::Serialize)]
56pub struct BeaconObjective {
57 /// Unique identifier of the beacon objective.
58 id: usize,
59 /// Name of the beacon objective.
60 name: String,
61 /// Start time of the beacon objective.
62 start: DateTime<Utc>,
63 /// End time of the beacon objective.
64 end: DateTime<Utc>,
65 /// Optional set of measurements associated with the beacon objective.
66 measurements: Option<BayesianSet>,
67}
68
69impl JsonDump for BeaconObjective {
70 /// Returns the file name for the JSON dump of the beacon objective.
71 fn file_name(&self) -> String { format!("bo_{}.json", self.id) }
72
73 /// Returns the directory name for the beacon objective JSON files.
74 fn dir_name(&self) -> &'static str { "beacon_objectives" }
75}
76
77impl BeaconObjective {
78 /// Creates a new [`BeaconObjective`] instance.
79 ///
80 /// # Arguments
81 /// * `id` - Unique identifier of the beacon objective.
82 /// * `name` - Name of the beacon objective.
83 /// * `start` - Start time of the beacon objective.
84 /// * `end` - End time of the beacon objective.
85 pub fn new(id: usize, name: String, start: DateTime<Utc>, end: DateTime<Utc>) -> Self {
86 Self { id, name, start, end, measurements: None }
87 }
88
89 /// Returns the unique identifier of the beacon objective.
90 pub fn id(&self) -> usize { self.id }
91 /// Returns the name of the beacon objective.
92 pub fn name(&self) -> &str { &self.name }
93 /// Returns the start time of the beacon objective.
94 pub fn start(&self) -> DateTime<Utc> { self.start }
95 /// Returns the end time of the beacon objective.
96 pub fn end(&self) -> DateTime<Utc> { self.end }
97 /// Returns an optional reference to the set of beacon measurements.
98 pub fn measurements(&self) -> Option<&BayesianSet> { self.measurements.as_ref() }
99
100 /// Appends a beacon measurement to the objective's measurement set.
101 ///
102 /// If the measurement set does not exist, it creates a new one.
103 ///
104 /// # Arguments
105 /// * `meas` - The `BeaconMeas` to be added.
106 pub fn append_measurement(&mut self, meas: BeaconMeas) {
107 if let Some(meas_set) = &mut self.measurements {
108 meas_set.update(&meas);
109 } else {
110 self.measurements = Some(BayesianSet::new(meas));
111 }
112 }
113}
114
115impl Eq for BeaconObjective {}
116
117impl PartialEq<Self> for BeaconObjective {
118 /// Compares equality based on the end time of the objectives.
119 fn eq(&self, other: &Self) -> bool { self.end == other.end }
120}
121
122impl PartialOrd<Self> for BeaconObjective {
123 /// Provides partial ordering based on the end time of the objectives.
124 fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
125}
126
127impl Ord for BeaconObjective {
128 /// Orders the objectives based on their end time.
129 fn cmp(&self, other: &Self) -> Ordering { self.end.cmp(&other.end) }
130}
131
132impl From<crate::http_handler::BeaconObjective> for BeaconObjective {
133 /// Converts an external `BeaconObjective` into the internal representation.
134 ///
135 /// # Arguments
136 /// * `obj` - The external `BeaconObjective` to be converted.
137 fn from(obj: crate::http_handler::BeaconObjective) -> Self {
138 Self {
139 id: obj.id(),
140 name: String::from(obj.name()),
141 start: obj.start(),
142 end: obj.end(),
143 measurements: None,
144 }
145 }
146}