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}