doris_rs/record/
snr.rs

1#[cfg(feature = "serde")]
2use serde::{Deserialize, Serialize};
3
4use crate::error::ParsingError;
5
6/// [SNR] (Signal to Noise Ratio) for all frequency dependent measurements.
7#[derive(Default, PartialOrd, Ord, PartialEq, Eq, Copy, Clone, Debug)]
8#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
9pub enum SNR {
10    /// SNR ~= 0 dB/Hz
11    DbHz0,
12
13    /// SNR < 12 dB/Hz
14    DbHz12,
15
16    /// 12 dB/Hz <= SNR < 17 dB/Hz
17    DbHz12_17,
18
19    /// 18 dB/Hz <= SNR < 23 dB/Hz
20    DbHz18_23,
21
22    /// 24 dB/Hz <= SNR < 29 dB/Hz
23    #[default]
24    DbHz24_29,
25
26    /// 30 dB/Hz <= SNR < 35 dB/Hz
27    DbHz30_35,
28
29    /// 36 dB/Hz <= SNR < 41 dB/Hz
30    DbHz36_41,
31
32    /// 42 dB/Hz <= SNR < 47 dB/Hz
33    DbHz42_47,
34
35    /// 48 dB/Hz <= SNR < 53 dB/Hz
36    DbHz48_53,
37
38    /// SNR >= 54 dB/Hz
39    DbHz54,
40}
41
42impl std::fmt::LowerHex for SNR {
43    /// Prints [SNR] as per DORIS-RINEX files
44    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
45        match self {
46            Self::DbHz0 => f.write_str("0"),
47            Self::DbHz12 => f.write_str("1"),
48            Self::DbHz12_17 => f.write_str("2"),
49            Self::DbHz18_23 => f.write_str("3"),
50            Self::DbHz24_29 => f.write_str("4"),
51            Self::DbHz30_35 => f.write_str("5"),
52            Self::DbHz36_41 => f.write_str("6"),
53            Self::DbHz42_47 => f.write_str("7"),
54            Self::DbHz48_53 => f.write_str("8"),
55            Self::DbHz54 => f.write_str("9"),
56        }
57    }
58}
59
60impl std::fmt::Display for SNR {
61    /// Prints [SNR] in verbose manner
62    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
63        match self {
64            Self::DbHz0 => f.write_str("<< 12 dB"),
65            Self::DbHz12 => f.write_str("< 12 dB"),
66            Self::DbHz12_17 => f.write_str("[12, 17[ dB"),
67            Self::DbHz18_23 => f.write_str("[18, 23[ dB"),
68            Self::DbHz24_29 => f.write_str("[24, 29[ dB"),
69            Self::DbHz30_35 => f.write_str("[30, 35[ dB"),
70            Self::DbHz36_41 => f.write_str("[36, 41[ dB"),
71            Self::DbHz42_47 => f.write_str("[42, 47[ dB"),
72            Self::DbHz48_53 => f.write_str("[48, 53[ dB"),
73            Self::DbHz54 => f.write_str("> 54 dB"),
74        }
75    }
76}
77
78impl std::str::FromStr for SNR {
79    type Err = ParsingError;
80
81    /// Parses [SNR] from standard DORIS-RINEX value.
82    fn from_str(code: &str) -> Result<Self, Self::Err> {
83        match code.trim() {
84            "0" => Ok(Self::DbHz0),
85            "1" => Ok(Self::DbHz12),
86            "2" => Ok(Self::DbHz12_17),
87            "3" => Ok(Self::DbHz18_23),
88            "4" => Ok(Self::DbHz24_29),
89            "5" => Ok(Self::DbHz30_35),
90            "6" => Ok(Self::DbHz36_41),
91            "7" => Ok(Self::DbHz42_47),
92            "8" => Ok(Self::DbHz48_53),
93            "9" => Ok(Self::DbHz54),
94            "bad" => Ok(Self::DbHz18_23),
95            "weak" => Ok(Self::DbHz24_29),
96            "strong" => Ok(Self::DbHz30_35),
97            "excellent" => Ok(Self::DbHz48_53),
98            _ => Err(ParsingError::SNR),
99        }
100    }
101}
102
103impl From<f64> for SNR {
104    fn from(f_db: f64) -> Self {
105        if f_db < 12.0 {
106            Self::DbHz12
107        } else if f_db <= 17.0 {
108            Self::DbHz12_17
109        } else if f_db <= 23.0 {
110            Self::DbHz18_23
111        } else if f_db <= 29.0 {
112            Self::DbHz24_29
113        } else if f_db <= 35.0 {
114            Self::DbHz30_35
115        } else if f_db <= 41.0 {
116            Self::DbHz36_41
117        } else if f_db <= 47.0 {
118            Self::DbHz42_47
119        } else if f_db <= 53.0 {
120            Self::DbHz48_53
121        } else {
122            Self::DbHz54
123        }
124    }
125}
126
127impl From<SNR> for f64 {
128    fn from(val: SNR) -> Self {
129        match val {
130            SNR::DbHz0 => 0.0_f64,
131            SNR::DbHz12 => 12.0_f64,
132            SNR::DbHz12_17 => 17.0_f64,
133            SNR::DbHz18_23 => 23.0_f64,
134            SNR::DbHz24_29 => 29.0_f64,
135            SNR::DbHz30_35 => 35.0_f64,
136            SNR::DbHz36_41 => 41.0_f64,
137            SNR::DbHz42_47 => 47.0_f64,
138            SNR::DbHz48_53 => 53.0_f64,
139            SNR::DbHz54 => 54.0_f64,
140        }
141    }
142}
143
144impl From<u8> for SNR {
145    fn from(u: u8) -> Self {
146        match u {
147            1 => Self::DbHz12,
148            2 => Self::DbHz12_17,
149            3 => Self::DbHz18_23,
150            4 => Self::DbHz24_29,
151            5 => Self::DbHz30_35,
152            6 => Self::DbHz36_41,
153            7 => Self::DbHz42_47,
154            8 => Self::DbHz48_53,
155            9 => Self::DbHz54,
156            _ => Self::DbHz0,
157        }
158    }
159}
160
161impl SNR {
162    /// Returns true if [SNR] is bad signal level.
163    pub fn bad(self) -> bool {
164        self <= Self::DbHz18_23
165    }
166
167    /// Returns true if [SNR] describes a weak signal level.
168    pub fn weak(self) -> bool {
169        self < Self::DbHz30_35
170    }
171
172    /// Returns true if [SNR] describes a strong signal level.
173    pub fn strong(self) -> bool {
174        self >= Self::DbHz30_35
175    }
176
177    /// Returns true if [SNR] describes an exellent signal level.
178    pub fn excellent(self) -> bool {
179        self > Self::DbHz42_47
180    }
181}
182
183#[cfg(test)]
184mod test {
185    use super::*;
186    use std::str::FromStr;
187
188    #[test]
189    fn snr_parsing() {
190        for (value, expected) in [("0", SNR::DbHz0), ("8", SNR::DbHz48_53), ("9", SNR::DbHz54)] {
191            let parsed = SNR::from_str(value).unwrap_or_else(|e| {
192                panic!("Failed to parse SNR from \"{}\"", value);
193            });
194
195            let formatted = format!("{:x}", parsed);
196
197            assert_eq!(formatted, value);
198        }
199
200        assert!(SNR::DbHz0.bad());
201        assert!(SNR::DbHz12.weak());
202        assert!(SNR::DbHz30_35.strong());
203        assert!(SNR::DbHz54.excellent());
204    }
205}