rinex/observation/
snr.rs

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