From 0200b91cd1a753bfc1b8e54b44111f89a2151bc6 Mon Sep 17 00:00:00 2001 From: Gustav Palmqvist Date: Sat, 12 Dec 2020 01:08:42 +0100 Subject: [PATCH] Added logarithmic units --- src/lib.rs | 44 ++++++++++++++++++++++++++++++++- src/quantity.rs | 48 ++++++++++++++++++++++++++++++++++-- src/si/electric_potential.rs | 5 ++++ src/si/power.rs | 16 ++++++++++++ src/si/ratio.rs | 2 ++ 5 files changed, 112 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0125f5db..1e2c26b6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -396,7 +396,8 @@ pub enum ConstantOp { /// /// [units]: http://jcgm.bipm.org/vim/en/1.13.html /// [factor]: https://jcgm.bipm.org/vim/en/1.24.html -pub trait Conversion { +pub trait Conversion where + V: Conversion { /// Conversion factor type specific to the underlying storage type. type T: ConversionFactor; @@ -420,6 +421,28 @@ pub trait Conversion { ::zero() } + #[inline(always)] + #[allow(unused_variables)] + fn base() -> Self::T { + ::one() + } + + #[inline(always)] + #[allow(unused_variables)] + fn scale() -> Self::T { + ::one() + } + + #[inline(always)] + fn into_linear(x: V) -> V { + x + } + + #[inline(always)] + fn from_linear(x: V) -> V { + x + } + /// Instance [conversion factor](https://jcgm.bipm.org/vim/en/1.24.html). /// /// Default implementation returns the coefficient: `Self::coefficient()`. @@ -449,6 +472,16 @@ pub trait ConversionFactor: /// Raises a `ConversionFactor` to an integer power. fn powi(self, e: i32) -> Self; + /// Raises a `ConversionFactor` to a power. + fn pow(self, v: V) -> V { + unimplemented!() + } + + /// Takes the log_`ConversionFactor` of a value. + fn log(self, v: V) -> V { + unimplemented!() + } + /// Converts a `ConversionFactor` into its underlying storage type. fn value(self) -> V; } @@ -503,6 +536,15 @@ storage_types! { fn value(self) -> V { self } + + fn pow(self, v: V) -> V { + ::powf(self, v) + } + + /// Takes the log_`ConversionFactor` of a value. + fn log(self, v: V) -> V { + ::log(self, v) + } } } diff --git a/src/quantity.rs b/src/quantity.rs index 3464b899..892c1745 100644 --- a/src/quantity.rs +++ b/src/quantity.rs @@ -187,6 +187,20 @@ macro_rules! quantity { fn constant(op: $crate::ConstantOp) -> Self::T { quantity!(@constant op $($conversion),+) } + + #[inline(always)] + #[allow(unused_variables)] + fn base() -> Self::T { + quantity!(@base $($conversion),+) + } + + #[inline(always)] + #[allow(unused_variables)] + fn scale() -> Self::T { + quantity!(@scale $($conversion),+) + } + + quantity!(@logarithmic $($conversion),+); } impl super::Conversion for super::$unit {})+ @@ -356,7 +370,7 @@ macro_rules! quantity { $quantity { dimension: $crate::lib::marker::PhantomData, units: $crate::lib::marker::PhantomData, - value: super::to_base::(&v), + value: super::to_base::(&::into_linear(v)), } } @@ -369,7 +383,7 @@ macro_rules! quantity { where N: Unit + $crate::Conversion, { - super::from_base::(&self.value) + ::from_linear(super::from_base::(&self.value)) } /// Returns the largest integer less than or equal to a number in the given @@ -589,12 +603,42 @@ macro_rules! quantity { pub struct $unit; }; (@coefficient $factor:expr, $const:expr) => { $factor }; + (@coefficient $factor:expr, $base:expr, $scale:expr) => { $factor }; (@coefficient $factor:expr) => { $factor }; (@constant $op:ident $factor:expr, $const:expr) => { $const }; + (@constant $op:ident $factor:expr, $base:expr, $scale:expr) => { + match $op { + $crate::ConstantOp::Add => -0.0, + $crate::ConstantOp::Sub => 0.0, + } + }; (@constant $op:ident $factor:expr) => { match $op { $crate::ConstantOp::Add => -0.0, $crate::ConstantOp::Sub => 0.0, } }; + (@base $factor:expr, $base:expr, $scale:expr) => { $base }; + (@base $factor:expr, $const:expr) => { 1.0 }; + (@base $factor:expr) => { 1.0 }; + (@scale $factor:expr, $base:expr, $scale:expr) => { $scale }; + (@scale $factor:expr, $const:expr) => { 1.0 }; + (@scale $factor:expr) => { 1.0 }; + (@logarithmic $factor:expr, $base:expr, $scale:expr) => { + #[inline(always)] + fn into_linear(x: V) -> V { + use $crate::ConversionFactor; + >::base().pow(( + (<>::T as $crate::num::One>::one() / >::scale()) * x.into_conversion() + ).value()) + } + + #[inline(always)] + fn from_linear(x: V) -> V { + use $crate::ConversionFactor; + (>::scale() * x.into_conversion().log(>::base().value()).into_conversion()).value() + } + }; + (@logarithmic $factor:expr, $const:expr) => { }; + (@logarithmic $factor:expr) => { }; } diff --git a/src/si/electric_potential.rs b/src/si/electric_potential.rs index 0bce3ccb..f5f7de0a 100644 --- a/src/si/electric_potential.rs +++ b/src/si/electric_potential.rs @@ -38,6 +38,11 @@ quantity! { @abvolt: 1.0_E-8; "abV", "abvolt", "abvolts"; @statvolt: 2.997_925_E2; "statV", "statvolt", "statvolts"; + + @decibel_volt: prefix!(none), 10.0, 20.0; "dBV", "decibel-volt", "decibel-volts"; + @decibel_millivolt: prefix!(milli), 10.0, 20.0; "dBmV", "decibel-millivolt", "decibel-millivolts"; + @decibel_microvolt: prefix!(micro), 10.0, 20.0; "dBµV", "decibel-microvolt", "decibel-microvolts"; + @decibel_unit: 0.7746E0, 10.0, 20.0; "dBu", "decibel-unit", "decibel-units"; } } diff --git a/src/si/power.rs b/src/si/power.rs index 844c74a8..fb3cfa0f 100644 --- a/src/si/power.rs +++ b/src/si/power.rs @@ -36,6 +36,10 @@ quantity! { @zeptowatt: prefix!(zepto); "zW", "zeptowatt", "zeptowatts"; @yoctowatt: prefix!(yocto); "yW", "yoctowatt", "yoctowatts"; + @decibel_watt: prefix!(none), 10.0, 10.0; "dBW", "decibel-watt", "decibel-watts"; + @decibel_milliwatt: prefix!(milli), 10.0, 10.0; "dBm", "decibel-milliwatt", "decibel-milliwatts";// dBm is more common than dBmW + @decibel_microwatt: prefix!(micro), 10.0, 10.0; "dBµW", "decibel-microwatt", "decibel-microwatts"; + @erg_per_second: 1.0_E-7; "erg/s", "erg per second", "ergs per second"; @foot_pound_per_hour: 3.766_161_111_111_111_E-4; "ft · lbf/h", "foot pound-force per hour", "foot pounds-force per hour"; @@ -58,6 +62,18 @@ quantity! { #[cfg(test)] mod tests { + + #[test] + fn test_dbm() { + use crate::si::power as p; + use crate::si::quantities::*; + use crate::tests::Test; + + let x = Power::new::(0.0); + println!("{:?}", x.get::()); + println!("{:?}", x.get::()); + } + storage_types! { use crate::num::One; use crate::si::energy as e; diff --git a/src/si/ratio.rs b/src/si/ratio.rs index 9c19b979..db8d3b79 100644 --- a/src/si/ratio.rs +++ b/src/si/ratio.rs @@ -29,6 +29,8 @@ quantity! { @part_per_billion: 1.0_E-9; "ppb", "part per billion", "parts per billion"; @part_per_trillion: 1.0_E-12; "ppt", "part per trillion", "parts per trillion"; @part_per_quadrillion: 1.0_E-15; "ppq", "part per quadrillion", "parts per quadrillion"; + + @decibel: 1.0, 10.0, 20.0; "dB", "decibel", "decibels"; } }