Skip to content

Commit b3658ec

Browse files
committed
Better speed units.
Also fixed rendering issue with units.
1 parent 51b05bb commit b3658ec

File tree

6 files changed

+364
-2
lines changed

6 files changed

+364
-2
lines changed

examples/frequency.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
extern crate measurements;
2+
3+
fn main() {
4+
// Sinusiodal Oscilator moves at 5 Hz across 50 mm
5+
let f = measurements::Frequency::from_hertz(5.0);
6+
let d = measurements::Distance::from_millimeters(50.0);
7+
// Speed = PI * Frequency * Displacement
8+
// Speed = PI * Displacement / Period
9+
let v = ::std::f64::consts::PI * d / f.as_period();
10+
println!("Maximum speed of a pendulum at {:.1} with max displacement {:.1} is {:.1}", f, d, v);
11+
}
12+

src/frequency.rs

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

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ pub use area::Area;
4848
pub mod angle;
4949
pub use angle::Angle;
5050

51+
pub mod frequency;
52+
pub use frequency::Frequency;
53+
5154
pub mod prelude;
5255

5356
/// For given types A, B and C, implement, using base units:

src/measurement.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,7 @@ macro_rules! implement_display {
8282
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
8383
let (unit, value) = self.get_appropriate_units();
8484
value.fmt(f)?; // Value
85-
"\u{00A0}".fmt(f)?; // Non-breaking space
86-
unit.fmt(f) // Units
85+
write!(f, "\u{00A0}{}", unit)
8786
}
8887
}
8988
)*)

src/speed.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,21 @@ impl Measurement for Speed {
9494
fn as_base_units_name(&self) -> &'static str {
9595
"m/s"
9696
}
97+
98+
fn get_appropriate_units(&self) -> (&'static str, f64) {
99+
// Smallest to largest
100+
let list = [
101+
("nm/s", 1e-9),
102+
("\u{00B5}m/s", 1e-6),
103+
("mm/s", 1e-3),
104+
("m/s", 1e0),
105+
("km/s", 1e3),
106+
("thousand km/s", 1e6),
107+
("million km/s", 1e9),
108+
];
109+
self.pick_appropriate_units(&list)
110+
}
111+
97112
}
98113

99114
implement_measurement! { Speed }

tests/frequency.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
extern crate measurements;
2+
3+
use measurements::test_utils::assert_almost_eq;
4+
5+
#[test]
6+
fn oscillator() {
7+
// Sinusiodal Oscilator moves at 5 Hz across 50 mm
8+
let f = measurements::Frequency::from_hertz(5.0);
9+
let d = measurements::Distance::from_millimeters(50.0);
10+
// Speed = PI * Frequency * Displacement
11+
// Speed = PI * Displacement / Period
12+
let v = ::std::f64::consts::PI * d / f.as_period();
13+
// Check against https://www.spaceagecontrol.com/calcsinm.htm
14+
assert_almost_eq(v.as_meters_per_second(), 0.78539816339745);
15+
}
16+

0 commit comments

Comments
 (0)