Skip to main content

rfham_core/
frequency.rs

1//!
2//! Provides ..., a one-line description
3//!
4//! More detailed description
5//!
6//! # Examples
7//!
8//! ```rust
9//! ```
10//!
11
12use crate::error::CoreError;
13use serde::{Deserialize, Serialize};
14use std::{fmt::Display, ops::Range, str::FromStr};
15use uom::{
16    fmt::DisplayStyle,
17    si::{
18        f64::{Frequency as BaseFrequency, Length as BaseLength},
19        frequency as frequency_unit, length as length_unit,
20    },
21};
22
23// ------------------------------------------------------------------------------------------------
24// Public Macros
25// ------------------------------------------------------------------------------------------------
26
27// ------------------------------------------------------------------------------------------------
28// Public Types
29// ------------------------------------------------------------------------------------------------
30
31#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd, Deserialize, Serialize)]
32pub struct Frequency(BaseFrequency);
33
34#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd, Deserialize, Serialize)]
35pub struct Wavelength(BaseLength);
36
37pub const SPEED_OF_LIGHT: f64 = 299792458.0; // m/s
38
39#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
40pub struct FrequencyRange(Range<Frequency>);
41
42// ------------------------------------------------------------------------------------------------
43// Public Functions
44// ------------------------------------------------------------------------------------------------
45
46pub fn gigahertz(value: f64) -> Frequency {
47    Frequency(BaseFrequency::new::<frequency_unit::gigahertz>(value))
48}
49pub fn megahertz(value: f64) -> Frequency {
50    Frequency(BaseFrequency::new::<frequency_unit::megahertz>(value))
51}
52pub fn kilohertz(value: f64) -> Frequency {
53    Frequency(BaseFrequency::new::<frequency_unit::kilohertz>(value))
54}
55pub fn hertz(value: f64) -> Frequency {
56    Frequency(BaseFrequency::new::<frequency_unit::hertz>(value))
57}
58
59pub fn millimeters(value: f64) -> Wavelength {
60    Wavelength(BaseLength::new::<length_unit::millimeter>(value))
61}
62
63pub fn centimeters(value: f64) -> Wavelength {
64    Wavelength(BaseLength::new::<length_unit::centimeter>(value))
65}
66
67pub fn meters(value: f64) -> Wavelength {
68    Wavelength(BaseLength::new::<length_unit::meter>(value))
69}
70
71pub fn kilometers(value: f64) -> Wavelength {
72    Wavelength(BaseLength::new::<length_unit::kilometer>(value))
73}
74
75// ------------------------------------------------------------------------------------------------
76// Private Macros
77// ------------------------------------------------------------------------------------------------
78
79// ------------------------------------------------------------------------------------------------
80// Private Types
81// ------------------------------------------------------------------------------------------------
82
83// ------------------------------------------------------------------------------------------------
84// Implementations ❯ Frequency
85// ------------------------------------------------------------------------------------------------
86
87impl Display for Frequency {
88    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
89        if f.alternate() {
90            match self.value() {
91                0.0..1_000.0 => self
92                    .0
93                    .into_format_args(frequency_unit::hertz, DisplayStyle::Description)
94                    .fmt(f),
95                1_000.0..1_000_000.0 => self
96                    .0
97                    .into_format_args(frequency_unit::kilohertz, DisplayStyle::Description)
98                    .fmt(f),
99                1_000_000.0..1_000_000_000.0 => self
100                    .0
101                    .into_format_args(frequency_unit::megahertz, DisplayStyle::Description)
102                    .fmt(f),
103                1_000_000_000.0..1_000_000_000_000.0 => self
104                    .0
105                    .into_format_args(frequency_unit::gigahertz, DisplayStyle::Description)
106                    .fmt(f),
107                _ => self
108                    .0
109                    .into_format_args(frequency_unit::terahertz, DisplayStyle::Description)
110                    .fmt(f),
111            }
112        } else {
113            self.0
114                .into_format_args(frequency_unit::megahertz, DisplayStyle::Abbreviation)
115                .fmt(f)
116        }
117    }
118}
119
120impl FromStr for Frequency {
121    type Err = CoreError;
122
123    fn from_str(s: &str) -> Result<Self, Self::Err> {
124        BaseFrequency::from_str(s)
125            .map(Self)
126            .map_err(|_| CoreError::InvalidValueFromStr(s.to_string(), "Frequency"))
127    }
128}
129
130impl From<BaseFrequency> for Frequency {
131    fn from(value: BaseFrequency) -> Self {
132        Self(value)
133    }
134}
135
136impl From<f64> for Frequency {
137    fn from(value: f64) -> Self {
138        megahertz(value)
139    }
140}
141
142impl From<Frequency> for BaseFrequency {
143    fn from(value: Frequency) -> Self {
144        value.0
145    }
146}
147
148impl From<Frequency> for f64 {
149    fn from(value: Frequency) -> Self {
150        value.0.value
151    }
152}
153
154impl AsRef<BaseFrequency> for Frequency {
155    fn as_ref(&self) -> &BaseFrequency {
156        &self.0
157    }
158}
159
160impl Frequency {
161    pub fn value(&self) -> f64 {
162        self.0.value
163    }
164
165    pub fn to_wavelength(&self) -> Wavelength {
166        meters(SPEED_OF_LIGHT / self.value())
167    }
168}
169
170// ------------------------------------------------------------------------------------------------
171// Implementations ❯ FrequencyRange
172// ------------------------------------------------------------------------------------------------
173
174impl Display for FrequencyRange {
175    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
176        self.0.start.fmt(f)?;
177        write!(f, " {} ", if f.alternate() { "to" } else { "-" },)?;
178        self.0.end.fmt(f)
179    }
180}
181
182impl From<Range<Frequency>> for FrequencyRange {
183    fn from(range: Range<Frequency>) -> Self {
184        Self(range)
185    }
186}
187
188impl From<Range<f64>> for FrequencyRange {
189    fn from(range: Range<f64>) -> Self {
190        Self::new(megahertz(range.start), megahertz(range.end))
191    }
192}
193
194impl From<(Frequency, Frequency)> for FrequencyRange {
195    fn from(range: (Frequency, Frequency)) -> Self {
196        Self::new(range.0, range.1)
197    }
198}
199
200impl From<(f64, f64)> for FrequencyRange {
201    fn from(range: (f64, f64)) -> Self {
202        Self::new(megahertz(range.0), megahertz(range.1))
203    }
204}
205
206impl From<FrequencyRange> for Range<Frequency> {
207    fn from(range: FrequencyRange) -> Self {
208        range.0
209    }
210}
211
212impl From<FrequencyRange> for Range<f64> {
213    fn from(range: FrequencyRange) -> Self {
214        Range {
215            start: range.0.start.value(),
216            end: range.0.end.value(),
217        }
218    }
219}
220
221impl FrequencyRange {
222    pub fn new(start: Frequency, end: Frequency) -> Self {
223        assert!(start <= end);
224        Self(Range { start, end })
225    }
226    pub fn new_mhz(start: f64, end: f64) -> Self {
227        Self::new(megahertz(start), megahertz(end))
228    }
229
230    pub const fn start(&self) -> Frequency {
231        self.0.start
232    }
233
234    pub const fn end(&self) -> Frequency {
235        self.0.end
236    }
237
238    pub fn mid_band(&self) -> Frequency {
239        hertz(self.0.start.value() + ((self.0.end.value() - self.0.start.value()) / 2.0))
240    }
241
242    pub fn contains(&self, frequency: Frequency) -> bool {
243        self.0.contains(&frequency)
244    }
245
246    pub fn contains_mhz(&self, frequency: f64) -> bool {
247        self.0.contains(&megahertz(frequency))
248    }
249
250    pub fn is_empty(&self) -> bool {
251        self.0.is_empty()
252    }
253
254    pub fn starts_before(&self, other: &Self) -> bool {
255        self.start() < other.start()
256    }
257
258    pub fn starts_with(&self, other: &Self) -> bool {
259        self.start() == other.start() && self.contains(other.end())
260    }
261
262    pub fn ends_before(&self, other: &Self) -> bool {
263        self.end() < other.end()
264    }
265
266    pub fn ends_with(&self, other: &Self) -> bool {
267        self.contains(other.start()) && self.end() == other.end()
268    }
269
270    pub fn is_subrange(&self, other: &Self) -> bool {
271        self.start() <= other.start() && self.end() >= other.end()
272    }
273
274    pub fn is_overlapping(&self, other: &Self) -> bool {
275        self.contains(other.start()) || self.contains(other.end())
276    }
277}
278
279// ------------------------------------------------------------------------------------------------
280// Implementations ❯ Wavelength
281// ------------------------------------------------------------------------------------------------
282
283impl Display for Wavelength {
284    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
285        if f.alternate() {
286            match self.value() {
287                0.001..0.01 => self
288                    .0
289                    .into_format_args(length_unit::millimeter, DisplayStyle::Description)
290                    .fmt(f),
291                0.01..1.0 => self
292                    .0
293                    .into_format_args(length_unit::centimeter, DisplayStyle::Description)
294                    .fmt(f),
295                1_000.0.. => self
296                    .0
297                    .into_format_args(length_unit::kilometer, DisplayStyle::Description)
298                    .fmt(f),
299                _ => self
300                    .0
301                    .into_format_args(length_unit::meter, DisplayStyle::Description)
302                    .fmt(f),
303            }
304        } else {
305            self.0
306                .into_format_args(length_unit::meter, DisplayStyle::Abbreviation)
307                .fmt(f)
308        }
309    }
310}
311
312impl FromStr for Wavelength {
313    type Err = CoreError;
314
315    fn from_str(s: &str) -> Result<Self, Self::Err> {
316        BaseLength::from_str(s)
317            .map(Self)
318            .map_err(|_| CoreError::InvalidValueFromStr(s.to_string(), "Wavelength"))
319    }
320}
321
322impl From<BaseLength> for Wavelength {
323    fn from(value: BaseLength) -> Self {
324        Self(value)
325    }
326}
327
328impl From<f64> for Wavelength {
329    fn from(value: f64) -> Self {
330        meters(value)
331    }
332}
333
334impl From<Wavelength> for BaseLength {
335    fn from(value: Wavelength) -> Self {
336        value.0
337    }
338}
339
340impl From<Wavelength> for f64 {
341    fn from(value: Wavelength) -> Self {
342        value.0.value
343    }
344}
345
346impl AsRef<BaseLength> for Wavelength {
347    fn as_ref(&self) -> &BaseLength {
348        &self.0
349    }
350}
351
352impl Wavelength {
353    pub fn value(&self) -> f64 {
354        self.0.value
355    }
356
357    pub fn to_frequency(&self) -> Frequency {
358        megahertz(SPEED_OF_LIGHT / self.value())
359    }
360}
361
362// ------------------------------------------------------------------------------------------------
363// Private Functions
364// ------------------------------------------------------------------------------------------------
365
366// ------------------------------------------------------------------------------------------------
367// Sub-Modules
368// ------------------------------------------------------------------------------------------------
369
370// ------------------------------------------------------------------------------------------------
371// Unit Tests
372// ------------------------------------------------------------------------------------------------
373
374#[cfg(test)]
375mod tests {
376    use super::FrequencyRange;
377    use pretty_assertions::assert_eq;
378
379    #[test]
380    fn test_default_fmt_frequency() {
381        assert_eq!("0.000001 MHz", &super::hertz(1.0).to_string());
382        assert_eq!("0.001 MHz", &super::kilohertz(1.0).to_string());
383        assert_eq!("1 MHz", &super::megahertz(1.0).to_string());
384        assert_eq!("1000 MHz", &super::gigahertz(1.0).to_string());
385    }
386
387    #[test]
388    fn test_default_fmt_frequency_precision() {
389        assert_eq!("0.000001 MHz", &format!("{:.6}", super::hertz(1.0)));
390        assert_eq!("0.001000 MHz", &format!("{:.6}", super::kilohertz(1.0)));
391        assert_eq!("1.000000 MHz", &format!("{:.6}", super::megahertz(1.0)));
392        assert_eq!("1000.000000 MHz", &format!("{:.6}", super::gigahertz(1.0)));
393    }
394
395    #[test]
396    fn test_default_fmt_frequency_width_and_precision() {
397        assert_eq!(
398            "      0.000001 MHz",
399            &format!("{:>14.6}", super::hertz(1.0))
400        );
401        assert_eq!(
402            "      0.001000 MHz",
403            &format!("{:>14.6}", super::kilohertz(1.0))
404        );
405        assert_eq!(
406            "      1.000000 MHz",
407            &format!("{:>14.6}", super::megahertz(1.0))
408        );
409        assert_eq!(
410            "   1000.000000 MHz",
411            &format!("{:>14.6}", super::gigahertz(1.0))
412        );
413    }
414
415    #[test]
416    fn test_alternate_fmt_frequency() {
417        assert_eq!("1 hertz", &format!("{:#}", super::hertz(1.0)));
418        assert_eq!("1 kilohertz", &format!("{:#}", super::kilohertz(1.0)));
419        assert_eq!("1 megahertz", &format!("{:#}", super::megahertz(1.0)));
420        assert_eq!("1 gigahertz", &format!("{:#}", super::gigahertz(1.0)));
421    }
422
423    #[test]
424    fn test_default_fmt_range() {
425        assert_eq!(
426            "0.000001 MHz - 0.00001 MHz",
427            &FrequencyRange::new(super::hertz(1.0), super::hertz(10.0)).to_string()
428        );
429        assert_eq!(
430            "0.001 MHz - 0.01 MHz",
431            &FrequencyRange::new(super::kilohertz(1.0), super::kilohertz(10.0)).to_string()
432        );
433        assert_eq!(
434            "1 MHz - 10 MHz",
435            &FrequencyRange::new(super::megahertz(1.0), super::megahertz(10.0)).to_string()
436        );
437        assert_eq!(
438            "1000 MHz - 10000 MHz",
439            &FrequencyRange::new(super::gigahertz(1.0), super::gigahertz(10.0)).to_string()
440        );
441    }
442}