measurements/
frequency.rs

1//! Types and constants for handling frequencies.
2
3use super::measurement::*;
4use crate::time;
5
6/// Number of nanohertz in a Hz
7pub const HERTZ_NANOHERTZ_FACTOR: f64 = 1e9;
8/// Number of µHz in a Hz
9pub const HERTZ_MICROHERTZ_FACTOR: f64 = 1e6;
10/// Number of mHz in a Hz
11pub const HERTZ_MILLIHERTZ_FACTOR: f64 = 1e3;
12/// Number of kHz in a Hz
13pub const HERTZ_KILOHERTZ_FACTOR: f64 = 1e-3;
14/// Number of MHz in a Hz
15pub const HERTZ_MEGAHERTZ_FACTOR: f64 = 1e-6;
16/// Number of GHz in a Hz
17pub const HERTZ_GIGAHERTZ_FACTOR: f64 = 1e-9;
18/// Number of THz in a Hz
19pub const HERTZ_TERAHERTZ_FACTOR: f64 = 1e-12;
20
21/// The Frequency struct can be used to deal with frequencies in a common way.
22/// Common SI prefixes are supported.
23///
24/// # Example
25///
26/// ```
27/// use measurements::Frequency;
28///
29/// let radio_station = Frequency::from_hertz(101.5e6);
30/// println!("Tune to {}.", radio_station);
31/// ```
32#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
33#[derive(Copy, Clone, Debug, Default)]
34pub struct Frequency {
35    hertz: f64,
36}
37
38/// Distance is a synonym for Frequency
39pub type Distance = Frequency;
40
41impl Frequency {
42    /// Create a new Frequency from a floating point value in hertz
43    pub fn from_hertz(hertz: f64) -> Self {
44        Frequency { hertz }
45    }
46
47    /// Create a new Frequency from a floating point value in Nanohertz.
48    pub fn from_nanohertz(nanohertz: f64) -> Self {
49        Self::from_hertz(nanohertz / HERTZ_NANOHERTZ_FACTOR)
50    }
51
52    /// Create a new Frequency from a floating point value in Microhertz.
53    pub fn from_microhertz(microhertz: f64) -> Self {
54        Self::from_hertz(microhertz / HERTZ_MICROHERTZ_FACTOR)
55    }
56
57    /// Create a new Frequency from a floating point value in Millihertz.
58    pub fn from_millihertz(millihertz: f64) -> Self {
59        Self::from_hertz(millihertz / HERTZ_MILLIHERTZ_FACTOR)
60    }
61
62    /// Create a new Frequency from a floating point value in Kilohertz (kHz).
63    pub fn from_kilohertz(kilohertz: f64) -> Self {
64        Self::from_hertz(kilohertz / HERTZ_KILOHERTZ_FACTOR)
65    }
66
67    /// Create a new Frequency from a floating point value in Megahertz (MHz).
68    pub fn from_megahertz(megahertz: f64) -> Self {
69        Self::from_hertz(megahertz / HERTZ_MEGAHERTZ_FACTOR)
70    }
71
72    /// Create a new Frequency from a floating point value in Gigahertz (GHz).
73    pub fn from_gigahertz(gigahertz: f64) -> Self {
74        Self::from_hertz(gigahertz / HERTZ_GIGAHERTZ_FACTOR)
75    }
76
77    /// Create a new Frequency from a floating point value in Terahertz (THz).
78    pub fn from_terahertz(terahertz: f64) -> Self {
79        Self::from_hertz(terahertz / HERTZ_TERAHERTZ_FACTOR)
80    }
81
82    /// Create a new Frequency from a floating point value of the period in seconds.
83    pub fn from_period(period: time::Duration) -> Self {
84        Self::from_hertz(1.0 / period.as_base_units())
85    }
86
87    /// Convert this Frequency to a floating point value in Nanohertz
88    pub fn as_nanohertz(&self) -> f64 {
89        self.hertz * HERTZ_NANOHERTZ_FACTOR
90    }
91
92    /// Convert this Frequency to a floating point value in Microhertz
93    pub fn as_microhertz(&self) -> f64 {
94        self.hertz * HERTZ_MICROHERTZ_FACTOR
95    }
96
97    /// Convert this Frequency to a floating point value in Millihertz
98    pub fn as_millihertz(&self) -> f64 {
99        self.hertz * HERTZ_MILLIHERTZ_FACTOR
100    }
101
102    /// Convert this Frequency to a floating point value in Hertz (Hz)
103    pub fn as_hertz(&self) -> f64 {
104        self.hertz
105    }
106
107    /// Convert this Frequency to a floating point value in Kilohertz (kHz)
108    pub fn as_kilohertz(&self) -> f64 {
109        self.hertz * HERTZ_KILOHERTZ_FACTOR
110    }
111
112    /// Convert this Frequency to a floating point value in Megahertz (MHz)
113    pub fn as_megahertz(&self) -> f64 {
114        self.hertz * HERTZ_MEGAHERTZ_FACTOR
115    }
116
117    /// Convert this Frequency to a floating point value in gigahertz (GHz)
118    pub fn as_gigahertz(&self) -> f64 {
119        self.hertz * HERTZ_GIGAHERTZ_FACTOR
120    }
121
122    /// Convert this Frequency to a floating point value in terahertz (THz)
123    pub fn as_terahertz(&self) -> f64 {
124        self.hertz * HERTZ_TERAHERTZ_FACTOR
125    }
126
127    /// Convert this Frequency to a floating point value of the period in seconds.
128    pub fn as_period(&self) -> time::Duration {
129        time::Duration::from_base_units(1.0 / self.hertz)
130    }
131}
132
133impl Measurement for Frequency {
134    fn get_appropriate_units(&self) -> (&'static str, f64) {
135        // Smallest to largest
136        let list = [
137            ("nHz", 1e-9),
138            ("\u{00B5}Hz", 1e-6),
139            ("mHz", 1e-3),
140            ("Hz", 1e0),
141            ("kHz", 1e3),
142            ("MHz", 1e6),
143            ("GHz", 1e9),
144            ("THz", 1e12),
145        ];
146        self.pick_appropriate_units(&list)
147    }
148
149    fn get_base_units_name(&self) -> &'static str {
150        "Hz"
151    }
152
153    fn as_base_units(&self) -> f64 {
154        self.hertz
155    }
156
157    fn from_base_units(units: f64) -> Self {
158        Self::from_hertz(units)
159    }
160}
161
162implement_measurement! { Frequency }
163
164#[cfg(test)]
165mod test {
166    use super::*;
167    use crate::{test_utils::assert_almost_eq, time};
168
169    #[test]
170    pub fn hertz() {
171        let i1 = Frequency::from_hertz(100.0);
172        let r1 = i1.as_hertz();
173        assert_almost_eq(r1, 100.0);
174    }
175
176    #[test]
177    pub fn nanohertz() {
178        let i1 = Frequency::from_hertz(100.0);
179        let r1 = i1.as_nanohertz();
180        let i2 = Frequency::from_nanohertz(100.0);
181        let r2 = i2.as_hertz();
182        assert_almost_eq(r1, 1e+11);
183        assert_almost_eq(r2, 1e-7);
184    }
185
186    #[test]
187    pub fn microhertz() {
188        let i1 = Frequency::from_hertz(100.0);
189        let r1 = i1.as_microhertz();
190        let i2 = Frequency::from_microhertz(100.0);
191        let r2 = i2.as_hertz();
192        assert_almost_eq(r1, 1e+8);
193        assert_almost_eq(r2, 1e-4);
194    }
195
196    #[test]
197    pub fn millihertz() {
198        let i1 = Frequency::from_hertz(100.0);
199        let r1 = i1.as_millihertz();
200        let i2 = Frequency::from_millihertz(100.0);
201        let r2 = i2.as_hertz();
202        assert_almost_eq(r1, 1e+5);
203        assert_almost_eq(r2, 1e-1);
204    }
205
206    #[test]
207    pub fn kilohertz() {
208        let i1 = Frequency::from_hertz(100.0);
209        let r1 = i1.as_kilohertz();
210        let i2 = Frequency::from_kilohertz(100.0);
211        let r2 = i2.as_hertz();
212        assert_almost_eq(r1, 1e-1);
213        assert_almost_eq(r2, 1e+5);
214    }
215
216    #[test]
217    pub fn megahertz() {
218        let i1 = Frequency::from_hertz(100.0);
219        let r1 = i1.as_megahertz();
220        let i2 = Frequency::from_megahertz(100.0);
221        let r2 = i2.as_hertz();
222        assert_almost_eq(r1, 1e-4);
223        assert_almost_eq(r2, 1e+8);
224    }
225
226    #[test]
227    pub fn gigahertz() {
228        let i1 = Frequency::from_hertz(100.0);
229        let r1 = i1.as_gigahertz();
230        let i2 = Frequency::from_gigahertz(100.0);
231        let r2 = i2.as_hertz();
232        assert_almost_eq(r1, 1e-7);
233        assert_almost_eq(r2, 1e+11);
234    }
235
236    #[test]
237    pub fn terahertz() {
238        let i1 = Frequency::from_hertz(100.0);
239        let r1 = i1.as_terahertz();
240        let i2 = Frequency::from_terahertz(100.0);
241        let r2 = i2.as_hertz();
242        assert_almost_eq(r1, 1e-10);
243        assert_almost_eq(r2, 1e+14);
244    }
245
246    #[test]
247    pub fn period() {
248        let i1 = Frequency::from_hertz(100.0);
249        let r1 = i1.as_period().as_base_units();
250        let i2 = Frequency::from_period(time::Duration::new(100, 0));
251        let r2 = i2.as_hertz();
252        assert_almost_eq(r1, 1e-2);
253        assert_almost_eq(r2, 1e-2);
254    }
255
256    // Traits
257    #[test]
258    fn add() {
259        let a = Frequency::from_hertz(2.0);
260        let b = Frequency::from_hertz(4.0);
261        let c = a + b;
262        let d = b + a;
263        assert_almost_eq(c.as_hertz(), 6.0);
264        assert_eq!(c, d);
265    }
266
267    #[test]
268    fn sub() {
269        let a = Frequency::from_hertz(2.0);
270        let b = Frequency::from_hertz(4.0);
271        let c = a - b;
272        assert_almost_eq(c.as_hertz(), -2.0);
273    }
274
275    #[test]
276    fn mul() {
277        let a = Frequency::from_hertz(3.0);
278        let b = a * 2.0;
279        let c = 2.0 * a;
280        assert_almost_eq(b.as_hertz(), 6.0);
281        assert_eq!(b, c);
282    }
283
284    #[test]
285    fn div() {
286        let a = Frequency::from_hertz(2.0);
287        let b = Frequency::from_hertz(4.0);
288        let c = a / b;
289        let d = a / 2.0;
290        assert_almost_eq(c, 0.5);
291        assert_almost_eq(d.as_hertz(), 1.0);
292    }
293
294    #[test]
295    fn eq() {
296        let a = Frequency::from_hertz(2.0);
297        let b = Frequency::from_hertz(2.0);
298        assert_eq!(a == b, true);
299    }
300
301    #[test]
302    fn neq() {
303        let a = Frequency::from_hertz(2.0);
304        let b = Frequency::from_hertz(4.0);
305        assert_eq!(a == b, false);
306    }
307
308    #[test]
309    fn cmp() {
310        let a = Frequency::from_hertz(2.0);
311        let b = Frequency::from_hertz(4.0);
312        assert_eq!(a < b, true);
313        assert_eq!(a <= b, true);
314        assert_eq!(a > b, false);
315        assert_eq!(a >= b, false);
316    }
317}