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