use crate::{Per, Quantity, Unit};
pub use crate::dimension::FrequencyDim;
pub trait FrequencyUnit: Unit<Dim = FrequencyDim> {}
impl<T: Unit<Dim = FrequencyDim>> FrequencyUnit for T {}
pub type Frequency<N, D> = Quantity<Per<N, D>>;
#[cfg(test)]
mod tests {
use super::*;
use crate::units::angular::{Degree, Degrees, MilliArcsecond, Radian};
use crate::units::time::{Day, Days, Year};
use crate::Per;
use approx::{assert_abs_diff_eq, assert_relative_eq};
use proptest::prelude::*;
use std::f64::consts::PI;
#[test]
fn deg_per_day_to_rad_per_day() {
let f: Frequency<Degree, Day> = Frequency::new(180.0);
let f_rad: Frequency<Radian, Day> = f.to();
assert_abs_diff_eq!(f_rad.value(), PI, epsilon = 1e-12);
}
#[test]
fn rad_per_day_to_deg_per_day() {
let f: Frequency<Radian, Day> = Frequency::new(PI);
let f_deg: Frequency<Degree, Day> = f.to();
assert_abs_diff_eq!(f_deg.value(), 180.0, epsilon = 1e-12);
}
#[test]
fn deg_per_day_to_deg_per_year() {
let f: Frequency<Degree, Day> = Frequency::new(1.0);
let f_year: Frequency<Degree, Year> = f.to();
assert_relative_eq!(f_year.value(), 365.2425, max_relative = 1e-6);
}
#[test]
fn deg_per_year_to_deg_per_day() {
let f: Frequency<Degree, Year> = Frequency::new(365.2425);
let f_day: Frequency<Degree, Day> = f.to();
assert_relative_eq!(f_day.value(), 1.0, max_relative = 1e-6);
}
#[test]
fn mas_per_day_to_deg_per_day() {
let f: Frequency<MilliArcsecond, Day> = Frequency::new(3_600_000.0);
let f_deg: Frequency<Degree, Day> = f.to();
assert_abs_diff_eq!(f_deg.value(), 1.0, epsilon = 1e-9);
}
#[test]
fn per_ratio_deg_day() {
let ratio = <Per<Degree, Day>>::RATIO;
assert_abs_diff_eq!(ratio, 1.0 / 86400.0, epsilon = 1e-12);
}
#[test]
fn per_ratio_rad_day() {
let ratio = <Per<Radian, Day>>::RATIO;
assert_relative_eq!(ratio, (180.0 / PI) / 86400.0, max_relative = 1e-12);
}
#[test]
fn frequency_times_time() {
let f: Frequency<Degree, Day> = Frequency::new(360.0);
let t: Days = Days::new(0.5);
let angle: Degrees = (f * t).to();
assert_abs_diff_eq!(angle.value(), 180.0, epsilon = 1e-9);
}
#[test]
fn time_times_frequency() {
let f: Frequency<Degree, Day> = Frequency::new(360.0);
let t: Days = Days::new(0.5);
let angle: Degrees = (t * f).to();
assert_abs_diff_eq!(angle.value(), 180.0, epsilon = 1e-9);
}
#[test]
fn angle_div_time() {
let angle: Degrees = Degrees::new(360.0);
let t: Days = Days::new(1.0);
let f: Frequency<Degree, Day> = angle / t;
assert_abs_diff_eq!(f.value(), 360.0, epsilon = 1e-9);
}
#[test]
fn roundtrip_deg_rad_per_day() {
let original: Frequency<Degree, Day> = Frequency::new(90.0);
let converted: Frequency<Radian, Day> = original.to();
let back: Frequency<Degree, Day> = converted.to();
assert_abs_diff_eq!(back.value(), original.value(), epsilon = 1e-9);
}
proptest! {
#[test]
fn prop_roundtrip_deg_rad_per_day(f in 1e-6..1e6f64) {
let original: Frequency<Degree, Day> = Frequency::new(f);
let converted: Frequency<Radian, Day> = original.to();
let back: Frequency<Degree, Day> = converted.to();
prop_assert!((back.value() - original.value()).abs() < 1e-9 * f.abs().max(1.0));
}
#[test]
fn prop_frequency_time_roundtrip(
f_val in 1e-3..1e3f64,
t_val in 1e-3..1e3f64
) {
let f: Frequency<Degree, Day> = Frequency::new(f_val);
let t: Days = Days::new(t_val);
let angle: Degrees = (f * t).to();
let f_back: Frequency<Degree, Day> = angle / t;
prop_assert!((f_back.value() - f.value()).abs() / f.value() < 1e-12);
}
}
}