qtty_core/units/
frequency.rs1use crate::{Per, Quantity, Unit};
16
17pub use crate::dimension::FrequencyDim;
19
20pub trait FrequencyUnit: Unit<Dim = FrequencyDim> {}
22impl<T: Unit<Dim = FrequencyDim>> FrequencyUnit for T {}
23
24pub type Frequency<N, D> = Quantity<Per<N, D>>;
37
38#[cfg(test)]
39mod tests {
40 use super::*;
41 use crate::units::angular::{Degree, Degrees, MilliArcsecond, Radian};
42 use crate::units::time::{Day, Days, Year};
43 use crate::Per;
44 use approx::{assert_abs_diff_eq, assert_relative_eq};
45 use proptest::prelude::*;
46 use std::f64::consts::PI;
47
48 #[test]
53 fn deg_per_day_to_rad_per_day() {
54 let f: Frequency<Degree, Day> = Frequency::new(180.0);
55 let f_rad: Frequency<Radian, Day> = f.to();
56 assert_abs_diff_eq!(f_rad.value(), PI, epsilon = 1e-12);
58 }
59
60 #[test]
61 fn rad_per_day_to_deg_per_day() {
62 let f: Frequency<Radian, Day> = Frequency::new(PI);
63 let f_deg: Frequency<Degree, Day> = f.to();
64 assert_abs_diff_eq!(f_deg.value(), 180.0, epsilon = 1e-12);
65 }
66
67 #[test]
68 fn deg_per_day_to_deg_per_year() {
69 let f: Frequency<Degree, Day> = Frequency::new(1.0);
70 let f_year: Frequency<Degree, Year> = f.to();
71 assert_relative_eq!(f_year.value(), 365.2425, max_relative = 1e-6);
73 }
74
75 #[test]
76 fn deg_per_year_to_deg_per_day() {
77 let f: Frequency<Degree, Year> = Frequency::new(365.2425);
78 let f_day: Frequency<Degree, Day> = f.to();
79 assert_relative_eq!(f_day.value(), 1.0, max_relative = 1e-6);
80 }
81
82 #[test]
83 fn mas_per_day_to_deg_per_day() {
84 let f: Frequency<MilliArcsecond, Day> = Frequency::new(3_600_000.0);
85 let f_deg: Frequency<Degree, Day> = f.to();
86 assert_abs_diff_eq!(f_deg.value(), 1.0, epsilon = 1e-9);
88 }
89
90 #[test]
95 fn per_ratio_deg_day() {
96 let ratio = <Per<Degree, Day>>::RATIO;
99 assert_abs_diff_eq!(ratio, 1.0 / 86400.0, epsilon = 1e-12);
100 }
101
102 #[test]
103 fn per_ratio_rad_day() {
104 let ratio = <Per<Radian, Day>>::RATIO;
106 assert_relative_eq!(ratio, (180.0 / PI) / 86400.0, max_relative = 1e-12);
107 }
108
109 #[test]
114 fn frequency_times_time() {
115 let f: Frequency<Degree, Day> = Frequency::new(360.0);
116 let t: Days = Days::new(0.5);
117 let angle: Degrees = (f * t).to();
118 assert_abs_diff_eq!(angle.value(), 180.0, epsilon = 1e-9);
119 }
120
121 #[test]
122 fn time_times_frequency() {
123 let f: Frequency<Degree, Day> = Frequency::new(360.0);
124 let t: Days = Days::new(0.5);
125 let angle: Degrees = (t * f).to();
126 assert_abs_diff_eq!(angle.value(), 180.0, epsilon = 1e-9);
127 }
128
129 #[test]
134 fn angle_div_time() {
135 let angle: Degrees = Degrees::new(360.0);
136 let t: Days = Days::new(1.0);
137 let f: Frequency<Degree, Day> = angle / t;
138 assert_abs_diff_eq!(f.value(), 360.0, epsilon = 1e-9);
139 }
140
141 #[test]
146 fn roundtrip_deg_rad_per_day() {
147 let original: Frequency<Degree, Day> = Frequency::new(90.0);
148 let converted: Frequency<Radian, Day> = original.to();
149 let back: Frequency<Degree, Day> = converted.to();
150 assert_abs_diff_eq!(back.value(), original.value(), epsilon = 1e-9);
151 }
152
153 proptest! {
158 #[test]
159 fn prop_roundtrip_deg_rad_per_day(f in 1e-6..1e6f64) {
160 let original: Frequency<Degree, Day> = Frequency::new(f);
161 let converted: Frequency<Radian, Day> = original.to();
162 let back: Frequency<Degree, Day> = converted.to();
163 prop_assert!((back.value() - original.value()).abs() < 1e-9 * f.abs().max(1.0));
164 }
165
166 #[test]
167 fn prop_frequency_time_roundtrip(
168 f_val in 1e-3..1e3f64,
169 t_val in 1e-3..1e3f64
170 ) {
171 let f: Frequency<Degree, Day> = Frequency::new(f_val);
172 let t: Days = Days::new(t_val);
173 let angle: Degrees = (f * t).to();
174 let f_back: Frequency<Degree, Day> = angle / t;
176 prop_assert!((f_back.value() - f.value()).abs() / f.value() < 1e-12);
177 }
178 }
179}