From 991b86123982df5444e257e27ee00a308924e0fc Mon Sep 17 00:00:00 2001 From: Zachary Sunforge Date: Tue, 9 Jul 2024 22:37:00 -0700 Subject: [PATCH] Migrated from uom to custom quantity implementation. --- Cargo.toml | 37 ++-- node/Cargo.toml | 2 - src/adc/stm32.rs | 16 +- src/circuit/resistive_divider.rs | 34 ++-- src/lib.rs | 4 +- src/quantity/irradiance.rs | 22 +++ src/quantity/mod.rs | 205 +++++++++++++++++++++ src/quantity/resistance.rs | 22 +++ src/quantity/temperature.rs | 157 ++++++++++++++++ src/quantity/voltage.rs | 86 +++++++++ src/quantity/volume_rate.rs | 22 +++ src/transducer/part/lm35.rs | 20 +- src/transducer/part/thermistor.rs | 30 ++- src/transducer/part/thermocouple/type_k.rs | 63 +++---- src/uom.rs | 16 -- 15 files changed, 604 insertions(+), 132 deletions(-) create mode 100644 src/quantity/irradiance.rs create mode 100644 src/quantity/mod.rs create mode 100644 src/quantity/resistance.rs create mode 100644 src/quantity/temperature.rs create mode 100644 src/quantity/voltage.rs create mode 100644 src/quantity/volume_rate.rs delete mode 100644 src/uom.rs diff --git a/Cargo.toml b/Cargo.toml index eea3093..60fd6ae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ members = [ ] [workspace.package] -version = "0.3.4" +version = "0.3.5" edition = "2021" repository = "https://git.bfpower.io/BFPOWER/physical" readme = "README.md" @@ -22,11 +22,8 @@ version = "0.2.*" default-features = false [workspace.dependencies.libm] version = "0.2.*" -# Units of measurement -[workspace.dependencies.uom] -version = "0.36.*" -default-features = false -features = ["f32", "si"] +[workspace.dependencies.float-cmp] +version = "0.9.*" # Logging [workspace.dependencies.tracing] version = "0.1.*" @@ -61,7 +58,6 @@ git = "https://git.bfpower.io/BFPOWER/bfpower-drivers.git" features = ["defmt"] [workspace.dependencies.ads1256] git = "https://git.bfpower.io/BFPOWER/bfpower-drivers.git" -features = ["uom"] # Embassy [workspace.dependencies.embassy-futures] version = "0.1.*" @@ -85,7 +81,9 @@ features = ["defmt", "unstable-pac"] [workspace.dependencies.embassy-nrf] version = "0.1.*" features = ["defmt"] -# Macros +# Meta +[workspace.dependencies.derive_more] +version = "0.99.*" [workspace.dependencies.syn] version = "2.0.*" features = ["extra-traits", "parsing"] @@ -107,6 +105,8 @@ readme.workspace = true license.workspace = true [features] +std = ["num-traits/std"] +libm = ["dep:libm", "num-traits/libm"] resistive-divider = [] thermocouple-k = ["libm"] thermistor = ["libm"] @@ -114,11 +114,22 @@ lm35 = [] pid = [] stm32 = [] -[dependencies] -uom = { workspace = true } -num-traits = { workspace = true } -libm = { workspace = true, optional = true } -serde = { workspace = true, optional = true } +[dependencies.num-traits] +workspace = true +[dependencies.derive_more] +workspace = true +[dependencies.defmt] +workspace = true +optional = true +[dependencies.libm] +workspace = true +optional = true +[dependencies.serde] +workspace = true +optional = true + +[dev-dependencies.float-cmp] +workspace = true #--------------------------------------------------------------------------------------------------------------------- #----- Profiles ------------------------ diff --git a/node/Cargo.toml b/node/Cargo.toml index 520b5d8..47dcc77 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -21,8 +21,6 @@ workspace = true workspace = true [dependencies.defmt] workspace = true -[dependencies.uom] -workspace = true [dependencies.embassy-stm32] workspace = true optional = true diff --git a/src/adc/stm32.rs b/src/adc/stm32.rs index 068e596..d5dccc9 100644 --- a/src/adc/stm32.rs +++ b/src/adc/stm32.rs @@ -1,13 +1,9 @@ -use uom::si::electric_potential::millivolt; -use uom::si::quantities::ElectricPotential; +use crate::quantity::{MilliVolts, Quantity}; pub fn reading_to_voltage( - reading: u16, - reference_voltage: ElectricPotential, - v_ref_int_scale: f32, -) -> ElectricPotential { - let reference_mv = reference_voltage.get::(); - let reading = f32::from(reading); - - ElectricPotential::new::(reading * v_ref_int_scale / reference_mv) + reading: u32, + reference_voltage: MilliVolts, + v_ref_int_scale: u32, +) -> MilliVolts { + MilliVolts((reading * v_ref_int_scale / reference_voltage.value()) as u16) } diff --git a/src/circuit/resistive_divider.rs b/src/circuit/resistive_divider.rs index a82b752..8490c8b 100644 --- a/src/circuit/resistive_divider.rs +++ b/src/circuit/resistive_divider.rs @@ -1,31 +1,19 @@ -use uom::si::electric_potential::volt; -use uom::si::electrical_resistance::ohm; -use uom::si::quantities::{ElectricPotential, ElectricalResistance}; +use crate::quantity::{Ohms, Quantity, Volts}; /// Given the resistance of the second resistor in a resistive voltage divider, calculate the resistance of the first resistor. pub fn solve_r1( - voltage_src: ElectricPotential, - voltage_read: ElectricPotential, - r2: ElectricalResistance, -) -> ElectricalResistance { - let volts_src = voltage_src.get::(); - let volts_read = voltage_read.get::(); - let ohms2 = r2.get::(); - - let ohms1 = ohms2 * (volts_src / volts_read - 1.0); - ElectricalResistance::new::(ohms1) + voltage_src: Volts, + voltage_read: Volts, + r2: Ohms, +) -> Ohms { + Ohms(r2.value() * (voltage_src.value() / voltage_read.value() - 1.0)) } /// Given the resistance of the first resistor in a resistive voltage divider, calculate the resistance of the second resistor. pub fn solve_r2( - voltage_src: ElectricPotential, - voltage_read: ElectricPotential, - r1: ElectricalResistance, -) -> ElectricalResistance { - let volts_src = voltage_src.get::(); - let volts_read = voltage_read.get::(); - let ohms1 = r1.get::(); - - let ohms2 = ohms1 * (1.0 / (volts_src / volts_read) - 1.0); - ElectricalResistance::new::(ohms2) + voltage_src: Volts, + voltage_read: Volts, + r1: Ohms, +) -> Ohms { + Ohms(r1.value() * (1.0 / (voltage_src.value() / voltage_read.value()) - 1.0)) } diff --git a/src/lib.rs b/src/lib.rs index dc334f2..d31b4d5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,11 +1,11 @@ -#![no_std] +#![cfg_attr(not(feature = "std"), no_std)] pub mod transducer; pub mod control; pub mod error; pub mod adc; -pub mod uom; pub mod circuit; +pub mod quantity; pub use error::CriticalError; diff --git a/src/quantity/irradiance.rs b/src/quantity/irradiance.rs new file mode 100644 index 0000000..1e1ec56 --- /dev/null +++ b/src/quantity/irradiance.rs @@ -0,0 +1,22 @@ +use derive_more::{Add, AddAssign, Display, Sub, SubAssign}; +use crate::quantity::{Quantity, Value}; + +// --------------------------------------------------------------------------------------------------------------------- +// ----- Watts per Square Meter ------------------------ +// --------------------------------------------------------------------------------------------------------------------- +#[derive(Copy, Clone, PartialEq, PartialOrd, Add, AddAssign, Sub, SubAssign, Display)] +#[display(fmt = "{} {}", _0, "Self::symbol()")] +#[repr(transparent)] +pub struct WatterPerSquareMeter(pub V); + +impl Quantity for WatterPerSquareMeter { + #[inline(always)] + fn value(self) -> V { + self.0 + } + + #[inline(always)] + fn symbol() -> &'static str { + "W/m²" + } +} \ No newline at end of file diff --git a/src/quantity/mod.rs b/src/quantity/mod.rs new file mode 100644 index 0000000..de25987 --- /dev/null +++ b/src/quantity/mod.rs @@ -0,0 +1,205 @@ +mod irradiance; +mod resistance; +mod temperature; +mod voltage; +mod volume_rate; + +#[cfg(feature = "defmt")] +pub use defmt_impl::*; + +pub use irradiance::*; +pub use resistance::*; +pub use temperature::*; +pub use voltage::*; +pub use volume_rate::*; + +use core::fmt::Display; +use core::marker::PhantomData; +use core::ops::{Add, Sub}; +use num_traits::{FromPrimitive, Num, NumCast}; + +const DECA: u8 = 10; +const DECI: u8 = 10; +const HECTO: u8 = 100; +const CENTI: u8 = 100; +const KILO: u16 = 1_000; +const MILLI: u16 = 1_000; +const MEGA: u32 = 1_000_000; +const MICRO: u32 = 1_000_000; +const GIGA: u32 = 1_000_000_000; +const NANO: u32 = 1_000_000_000; + +pub trait Quantity: Copy + PartialEq + PartialOrd + Add + Sub { + fn value(self) -> V; + + fn symbol() -> &'static str; + + /// Returns a wrapper that implements [Display] and [defmt::Format] for [Quantity]s with core number values. + /// + /// - `rounding` - Sets the number of decimal places to round to when formatting (currently ignored with defmt). + #[inline(always)] + fn fmt(self, rounding: Option) -> Fmt { + Fmt::new(self, rounding) + } +} + +pub trait Value: Num + Copy + PartialOrd + FromPrimitive + NumCast + Display { + //----- Temperature ---------------------------------- + #[inline(always)] + fn kelvins(self) -> Kelvins { + Kelvins(self) + } + + #[inline(always)] + fn deci_kelvins(self) -> DeciKelvins { + DeciKelvins(self) + } + + #[inline(always)] + fn degrees_celsius(self) -> DegreesCelsius { + DegreesCelsius(self) + } + + #[inline(always)] + fn deci_degrees_celsius(self) -> DeciDegreesCelsius { + DeciDegreesCelsius(self) + } + + //----- Voltage ---------------------------------- + #[inline(always)] + fn volts(self) -> Volts { + Volts(self) + } + + #[inline(always)] + fn millivolts(self) -> MilliVolts { + MilliVolts(self) + } + + //----- Resistance ---------------------------------- + #[inline(always)] + fn ohms(self) -> Ohms { + Ohms(self) + } + + //----- Volume rate ---------------------------------- + #[inline(always)] + fn liters_per_minute(self) -> LitersPerMinute { + LitersPerMinute(self) + } + + //----- Irradiance ---------------------------------- + #[inline(always)] + fn watts_per_square_meter(self) -> WatterPerSquareMeter { + WatterPerSquareMeter(self) + } +} + +impl Value for V where V: Num + Copy + PartialOrd + FromPrimitive + NumCast + Display {} + +#[derive(Copy, Clone)] +pub struct Fmt> { + quantity: Q, + rounding: Option, + _phantom: PhantomData, +} + +impl> Fmt { + #[inline(always)] + fn new(quantity: Q, rounding: Option) -> Self { + Self { + quantity, + rounding, + _phantom: PhantomData, + } + } +} + +impl> Display for Fmt { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self.rounding { + Some(places) => { + write!(f, "{:.prec$} {}", self.quantity.value(), Q::symbol(), prec = places) + }, + None => write!(f, "{} {}", self.quantity.value(), Q::symbol()), + } + } +} + +#[cfg(feature = "defmt")] +mod defmt_impl { + use super::*; + use defmt::{write, Format, Formatter}; + + impl> Format for Fmt { + fn format(&self, fmt: Formatter) { + write!(fmt, "{} {}", self.quantity.value(), Q::symbol()); + } + } + + impl> Format for Fmt { + fn format(&self, fmt: Formatter) { + write!(fmt, "{} {}", self.quantity.value(), Q::symbol()); + } + } + + impl> Format for Fmt { + fn format(&self, fmt: Formatter) { + write!(fmt, "{} {}", self.quantity.value(), Q::symbol()); + } + } + + impl> Format for Fmt { + fn format(&self, fmt: Formatter) { + write!(fmt, "{} {}", self.quantity.value(), Q::symbol()); + } + } + + impl> Format for Fmt { + fn format(&self, fmt: Formatter) { + write!(fmt, "{} {}", self.quantity.value(), Q::symbol()); + } + } + + impl> Format for Fmt { + fn format(&self, fmt: Formatter) { + write!(fmt, "{} {}", self.quantity.value(), Q::symbol()); + } + } + + impl> Format for Fmt { + fn format(&self, fmt: Formatter) { + write!(fmt, "{} {}", self.quantity.value(), Q::symbol()); + } + } + + impl> Format for Fmt { + fn format(&self, fmt: Formatter) { + write!(fmt, "{} {}", self.quantity.value(), Q::symbol()); + } + } + + impl> Format for Fmt { + fn format(&self, fmt: Formatter) { + write!(fmt, "{} {}", self.quantity.value(), Q::symbol()); + } + } + + impl> Format for Fmt { + fn format(&self, fmt: Formatter) { + write!(fmt, "{} {}", self.quantity.value(), Q::symbol()); + } + } + + impl> Format for Fmt { + fn format(&self, fmt: Formatter) { + write!(fmt, "{} {}", self.quantity.value(), Q::symbol()); + } + } + + impl> Format for Fmt { + fn format(&self, fmt: Formatter) { + write!(fmt, "{} {}", self.quantity.value(), Q::symbol()); + } + } +} diff --git a/src/quantity/resistance.rs b/src/quantity/resistance.rs new file mode 100644 index 0000000..01b0bee --- /dev/null +++ b/src/quantity/resistance.rs @@ -0,0 +1,22 @@ +use derive_more::{Add, AddAssign, Display, Sub, SubAssign}; +use crate::quantity::{Quantity, Value}; + +// --------------------------------------------------------------------------------------------------------------------- +// ----- Ohms ------------------------ +// --------------------------------------------------------------------------------------------------------------------- +#[derive(Copy, Clone, PartialEq, PartialOrd, Add, AddAssign, Sub, SubAssign, Display)] +#[display(fmt = "{} {}", _0, "Self::symbol()")] +#[repr(transparent)] +pub struct Ohms(pub V); + +impl Quantity for Ohms { + #[inline(always)] + fn value(self) -> V { + self.0 + } + + #[inline(always)] + fn symbol() -> &'static str { + "Ω" + } +} diff --git a/src/quantity/temperature.rs b/src/quantity/temperature.rs new file mode 100644 index 0000000..b98b796 --- /dev/null +++ b/src/quantity/temperature.rs @@ -0,0 +1,157 @@ +use derive_more::{Add, AddAssign, Display, Sub, SubAssign}; +use num_traits::float::FloatCore; +use crate::quantity::{DECI, Quantity, Value}; + +const KELVIN_CELSIUS_OFFSET: f64 = 273.15; + +// --------------------------------------------------------------------------------------------------------------------- +// ----- Kelvins ------------------------ +// --------------------------------------------------------------------------------------------------------------------- +#[derive(Copy, Clone, PartialEq, PartialOrd, Add, AddAssign, Sub, SubAssign, Display)] +#[display(fmt = "{} {}", _0, "Self::symbol()")] +#[repr(transparent)] +pub struct Kelvins(pub V); + +impl Quantity for Kelvins { + #[inline(always)] + fn value(self) -> V { + self.0 + } + + #[inline(always)] + fn symbol() -> &'static str { + "K" + } +} + +impl Kelvins { + #[inline] + pub fn to_degrees_celsius(self) -> DegreesCelsius { + //TODO: Make const + let offset = V::from_f64(KELVIN_CELSIUS_OFFSET).unwrap(); + DegreesCelsius(self.0 - offset) + } + + #[inline] + pub fn to_deci_kelvins(self) -> DeciKelvins { + let multiplier = V::from_u8(DECI).unwrap(); + DeciKelvins(self.0 * multiplier) + } +} + +// --------------------------------------------------------------------------------------------------------------------- +// ----- Deci Kelvins ------------------------ +// --------------------------------------------------------------------------------------------------------------------- +#[derive(Copy, Clone, PartialEq, PartialOrd, Add, AddAssign, Sub, SubAssign, Display)] +#[display(fmt = "{} {}", _0, "Self::symbol()")] +#[repr(transparent)] +pub struct DeciKelvins(pub V); + +impl Quantity for DeciKelvins { + #[inline(always)] + fn value(self) -> V { + self.0 + } + + #[inline(always)] + fn symbol() -> &'static str { + "dK" + } +} + +impl DeciKelvins { + #[inline] + pub fn to_kelvins(self) -> Kelvins { + let divisor = V::from_u8(DECI).unwrap(); + Kelvins(self.0 / divisor) + } +} + +// --------------------------------------------------------------------------------------------------------------------- +// ----- Degrees Celsius ------------------------ +// --------------------------------------------------------------------------------------------------------------------- +#[derive(Copy, Clone, PartialEq, PartialOrd, Add, AddAssign, Sub, SubAssign, Display)] +#[display(fmt = "{} {}", _0, "Self::symbol()")] +#[repr(transparent)] +pub struct DegreesCelsius(pub V); + +impl Quantity for DegreesCelsius { + #[inline(always)] + fn value(self) -> V { + self.0 + } + + #[inline(always)] + fn symbol() -> &'static str { + "℃" + } +} + +impl DegreesCelsius { + #[inline] + pub fn to_kelvins(self) -> Kelvins { + //TODO: Make const + let offset = V::from_f64(KELVIN_CELSIUS_OFFSET).unwrap(); + Kelvins(self.0 + offset) + } + + #[inline] + pub fn to_deci_degrees_celsius(self) -> DeciDegreesCelsius { + let multiplier = V::from_u8(DECI).unwrap(); + DeciDegreesCelsius(self.0 * multiplier) + } +} + +// --------------------------------------------------------------------------------------------------------------------- +// ----- Deci Degrees Celsius ------------------------ +// --------------------------------------------------------------------------------------------------------------------- +#[derive(Copy, Clone, PartialEq, PartialOrd, Add, AddAssign, Sub, SubAssign, Display)] +#[display(fmt = "{} {}", _0, "Self::symbol()")] +#[repr(transparent)] +pub struct DeciDegreesCelsius(pub V); + +impl Quantity for DeciDegreesCelsius { + #[inline(always)] + fn value(self) -> V { + self.0 + } + + #[inline(always)] + fn symbol() -> &'static str { + "d℃" + } +} + +impl DeciDegreesCelsius { + #[inline] + pub fn to_degrees_celsius(self) -> DegreesCelsius { + let divisor = V::from_u8(DECI).unwrap(); + DegreesCelsius(self.0 / divisor) + } +} + +// --------------------------------------------------------------------------------------------------------------------- +// ----- Tests ------------------------ +// --------------------------------------------------------------------------------------------------------------------- +#[cfg(test)] +mod tests { + use float_cmp::assert_approx_eq; + use super::*; + + #[test] + fn convert() { + let kelvins: Kelvins = 298.15.kelvins(); + let deci_kelvins: DeciKelvins = 2_981.5.deci_kelvins(); + let celsius: DegreesCelsius = 25.0.degrees_celsius(); + let deci_celsius: DeciDegreesCelsius = 250.0.deci_degrees_celsius(); + + assert_approx_eq!(f32, kelvins.to_degrees_celsius().0, celsius.0); + assert_approx_eq!(f32, celsius.to_kelvins().0, kelvins.0); + + assert_approx_eq!(f32, deci_kelvins.to_kelvins().0, kelvins.0); + assert_approx_eq!(f32, kelvins.to_deci_kelvins().0, deci_kelvins.0); + + assert_approx_eq!(f32, deci_celsius.to_degrees_celsius().0, celsius.0); + assert_approx_eq!(f32, celsius.to_deci_degrees_celsius().0, deci_celsius.0); + } +} diff --git a/src/quantity/voltage.rs b/src/quantity/voltage.rs new file mode 100644 index 0000000..500c32f --- /dev/null +++ b/src/quantity/voltage.rs @@ -0,0 +1,86 @@ +use derive_more::{Add, AddAssign, Display, Sub, SubAssign}; +use crate::quantity::{Quantity, Value}; + +const VOLT_MV_RATIO: u16 = 1_000; + +// --------------------------------------------------------------------------------------------------------------------- +// ----- Volts ------------------------ +// --------------------------------------------------------------------------------------------------------------------- +#[derive(Copy, Clone, PartialEq, PartialOrd, Add, AddAssign, Sub, SubAssign, Display)] +#[display(fmt = "{} {}", _0, "Self::symbol()")] +#[repr(transparent)] +pub struct Volts(pub V); + +impl Quantity for Volts { + #[inline(always)] + fn value(self) -> V { + self.0 + } + + #[inline(always)] + fn symbol() -> &'static str { + "V" + } +} + +impl Volts { + #[inline] + pub fn to_millivolts(self) -> MilliVolts { + let multiplier = V::from_u16(VOLT_MV_RATIO).unwrap(); + MilliVolts(self.0 * multiplier) + } +} + +// --------------------------------------------------------------------------------------------------------------------- +// ----- MilliVolts ------------------------ +// --------------------------------------------------------------------------------------------------------------------- +#[derive(Copy, Clone, PartialEq, PartialOrd, Add, AddAssign, Sub, SubAssign, Display)] +#[display(fmt = "{} {}", _0, "Self::symbol()")] +#[repr(transparent)] +pub struct MilliVolts(pub V); + +impl Quantity for MilliVolts { + #[inline(always)] + fn value(self) -> V { + self.0 + } + + #[inline(always)] + fn symbol() -> &'static str { + "mV" + } +} + +impl MilliVolts { + pub fn to_volts(self) -> Volts { + let divisor = V::from_u16(VOLT_MV_RATIO).unwrap(); + Volts(self.0 / divisor) + } +} + +// --------------------------------------------------------------------------------------------------------------------- +// ----- Tests ------------------------ +// --------------------------------------------------------------------------------------------------------------------- +#[cfg(test)] +mod tests { + use float_cmp::assert_approx_eq; + use super::*; + + #[test] + fn convert_u32() { + let volts: Volts = 3.volts(); + let millivolts: MilliVolts = 3_000.millivolts(); + + assert_eq!(volts.to_millivolts().0, millivolts.0); + assert_eq!(millivolts.to_volts().0, volts.0); + } + + #[test] + fn convert_f64() { + let volts: Volts = 3.0.volts(); + let millivolts: MilliVolts = 3_000.0.millivolts(); + + assert_approx_eq!(f64, volts.to_millivolts().0, millivolts.0); + assert_approx_eq!(f64, millivolts.to_volts().0, volts.0); + } +} \ No newline at end of file diff --git a/src/quantity/volume_rate.rs b/src/quantity/volume_rate.rs new file mode 100644 index 0000000..04cc14a --- /dev/null +++ b/src/quantity/volume_rate.rs @@ -0,0 +1,22 @@ +use derive_more::{Add, AddAssign, Display, Sub, SubAssign}; +use crate::quantity::{Quantity, Value}; + +// --------------------------------------------------------------------------------------------------------------------- +// ----- Liters per Minute------------------------ +// --------------------------------------------------------------------------------------------------------------------- +#[derive(Copy, Clone, PartialEq, PartialOrd, Add, AddAssign, Sub, SubAssign, Display)] +#[display(fmt = "{} {}", _0, "Self::symbol()")] +#[repr(transparent)] +pub struct LitersPerMinute(pub V); + +impl Quantity for LitersPerMinute { + #[inline(always)] + fn value(self) -> V { + self.0 + } + + #[inline(always)] + fn symbol() -> &'static str { + "L/min" + } +} \ No newline at end of file diff --git a/src/transducer/part/lm35.rs b/src/transducer/part/lm35.rs index e3f9f7e..eac7039 100644 --- a/src/transducer/part/lm35.rs +++ b/src/transducer/part/lm35.rs @@ -1,21 +1,15 @@ use crate::error::InvalidValue; -use uom::si::electric_potential::volt; -use uom::si::quantities::{ElectricPotential, ThermodynamicTemperature}; -use uom::si::thermodynamic_temperature::degree_celsius; +use crate::quantity::{DeciDegreesCelsius, MilliVolts, Quantity}; #[inline] pub fn convert( - voltage: ElectricPotential, -) -> Result, InvalidValue> { - const MIN_VOLTS: f32 = -0.55; - const MAX_VOLTS: f32 = 1.50; - const SCALE_FACTOR: f32 = 100.0; + voltage: MilliVolts, +) -> Result, InvalidValue> { + const MIN_VOLTAGE: MilliVolts = MilliVolts(-550); + const MAX_VOLTAGE: MilliVolts = MilliVolts(1_500); - let volts = voltage.get::(); - - if volts >= MIN_VOLTS && volts <= MAX_VOLTS { - let celsius = volts * SCALE_FACTOR; - Ok(ThermodynamicTemperature::new::(celsius)) + if voltage >= MIN_VOLTAGE && voltage <= MAX_VOLTAGE { + Ok(DeciDegreesCelsius(voltage.value())) } else { Err(InvalidValue) } diff --git a/src/transducer/part/thermistor.rs b/src/transducer/part/thermistor.rs index ab23d83..3d0274d 100644 --- a/src/transducer/part/thermistor.rs +++ b/src/transducer/part/thermistor.rs @@ -1,33 +1,25 @@ use libm::{log, logf}; -use uom::si::electrical_resistance::ohm; -use uom::si::quantities::{ThermodynamicTemperature, ElectricalResistance}; -use uom::si::thermodynamic_temperature::kelvin; +use crate::quantity::{Kelvins, Ohms}; /// Convert thermistor resistance to a temperature using beta parameter equation pub fn convert_beta( - resistance: ElectricalResistance, + resistance: Ohms, beta: f32, - reference_temp: ThermodynamicTemperature, - reference_resist: ElectricalResistance, -) -> ThermodynamicTemperature { - let ohms = resistance.get::(); - let reference_kelvin = reference_temp.get::(); - let reference_ohms = reference_resist.get::(); - - let result_kelvin = 1.0 / ((1.0 / reference_kelvin) + (1.0 / beta) * logf(ohms / reference_ohms)); - ThermodynamicTemperature::new::(result_kelvin) + reference_temp: Kelvins, + reference_resist: Ohms, +) -> Kelvins { + let kelvins = 1.0 / ((1.0 / reference_temp.0) + (1.0 / beta) * logf(resistance.0 / reference_resist.0)); + Kelvins(kelvins) } /// Convert thermistor resistance to a temperature using Steinhart-Hart equation pub fn convert_steinhart( - resistance: ElectricalResistance, + resistance: Ohms, a: f64, b: f64, c: f64, -) -> ThermodynamicTemperature { - let ohms = resistance.get::() as f64; - - let log_omhs = log(ohms); +) -> Kelvins { + let log_omhs = log(resistance.0); let kelvins = 1.0 / (a + b * log_omhs + c * log_omhs * log_omhs * log_omhs); - ThermodynamicTemperature::new::(kelvins as f32) + Kelvins(kelvins as f32) } diff --git a/src/transducer/part/thermocouple/type_k.rs b/src/transducer/part/thermocouple/type_k.rs index 08451d3..9dbfec4 100644 --- a/src/transducer/part/thermocouple/type_k.rs +++ b/src/transducer/part/thermocouple/type_k.rs @@ -2,14 +2,12 @@ use libm::pow; use crate::error::InvalidValue; -use uom::si::electric_potential::millivolt; -use uom::si::quantities::{ElectricPotential, ThermodynamicTemperature}; -use uom::si::thermodynamic_temperature::degree_celsius; +use crate::quantity::{DegreesCelsius, MilliVolts, Quantity}; fn _convert( - voltage: ElectricPotential, -) -> Result, InvalidValue> { - let mv = voltage.get::() as f64; + voltage: MilliVolts, +) -> Result, InvalidValue> { + let mv = voltage.value(); let mv_pow2 = mv * mv; let mv_pow3 = mv_pow2 * mv; let mv_pow4 = mv_pow3 * mv; @@ -29,7 +27,7 @@ fn _convert( + -1.0450598E-2 * mv_pow7 + -5.1920577E-4 * mv_pow8; - Ok(ThermodynamicTemperature::new::(celsius as f32)) + Ok(DegreesCelsius(celsius as f32)) } else if mv > 0.0 && mv < 20.644 { let mv_pow7 = mv_pow6 * mv; let mv_pow8 = mv_pow7 * mv; @@ -45,7 +43,7 @@ fn _convert( + 1.057734E-6 * mv_pow8 + -1.052755E-8 * mv_pow9; - Ok(ThermodynamicTemperature::new::(celsius as f32)) + Ok(DegreesCelsius(celsius as f32)) } else if mv >= 20.644 && mv <= 54.886 { let celsius = 1.318058e2 + 4.830222E+1 * mv @@ -55,7 +53,7 @@ fn _convert( + 8.802193E-6 * mv_pow5 + -3.110810E-8 * mv_pow6; - Ok(ThermodynamicTemperature::new::(celsius as f32)) + Ok(DegreesCelsius(celsius as f32)) } else { Err(InvalidValue) } @@ -70,13 +68,12 @@ fn _convert( /// This function uses the [NIST type K thermocouple linearisation polynomial](https://srdata.nist.gov/its90/type_k/kcoefficients_inverse.html). #[inline] pub fn convert_direct( - voltage: ElectricPotential, - r_junction: ThermodynamicTemperature, -) -> Result, InvalidValue> { - let base_celsius = _convert(voltage)?.get::(); - let r_junction_celsius = r_junction.get::(); + voltage: MilliVolts, + r_junction: DegreesCelsius, +) -> Result, InvalidValue> { + let base_temp = _convert(voltage)?; - Ok(ThermodynamicTemperature::new::(base_celsius + r_junction_celsius)) + Ok(base_temp + r_junction) } /// Convert from a voltage produced by a type k thermocouple to a temperature using polynomial and @@ -87,11 +84,11 @@ pub fn convert_direct( /// This function uses the [NIST type K thermocouple linearisation polynomial](https://srdata.nist.gov/its90/type_k/kcoefficients_inverse.html). #[inline] pub fn convert_seebeck( - voltage: ElectricPotential, - r_junction: ThermodynamicTemperature, -) -> Result, InvalidValue> { + voltage: MilliVolts, + r_junction: DegreesCelsius, +) -> Result, InvalidValue> { let voltage_correction = temp_to_voltage_seebeck(r_junction)?; - _convert(voltage + voltage_correction) + _convert(MilliVolts(voltage.0 + voltage_correction.0 as f64)) } /// Convert from a voltage produced by a type k thermocouple to a temperature using polynomial and @@ -102,17 +99,17 @@ pub fn convert_seebeck( /// This function uses the [NIST type K thermocouple linearisation polynomial](https://srdata.nist.gov/its90/type_k/kcoefficients_inverse.html). #[inline] pub fn convert_polynomial( - voltage: ElectricPotential, - r_junction: ThermodynamicTemperature, -) -> Result, InvalidValue> { + voltage: MilliVolts, + r_junction: DegreesCelsius, +) -> Result, InvalidValue> { let voltage_correction = temp_to_voltage_poly(r_junction)?; - _convert(voltage + voltage_correction) + _convert(MilliVolts(voltage.0 + voltage_correction.0 as f64)) } pub fn temp_to_voltage_poly( - temperature: ThermodynamicTemperature, -) -> Result, InvalidValue> { - let celsius = temperature.get::() as f64; + temperature: DegreesCelsius, +) -> Result, InvalidValue> { + let celsius = temperature.value(); let cel_pow2 = celsius * celsius; let cel_pow3 = cel_pow2 * celsius; let cel_pow4 = cel_pow3 * celsius; @@ -136,7 +133,7 @@ pub fn temp_to_voltage_poly( + -0.198892668780E-19 * cel_pow9 + -0.163226974860E-22 * cel_pow10; - Ok(ElectricPotential::new::(mv as f32)) + Ok(MilliVolts(mv as f32)) } else if celsius >= 0.0 && celsius <= 1372.0 { let base = celsius - 0.126968600000E+03; let exp = -0.118343200000E-03 * (base * base); @@ -154,7 +151,7 @@ pub fn temp_to_voltage_poly( + -0.121047212750E-25 * cel_pow9 + addition; - Ok(ElectricPotential::new::(mv as f32)) + Ok(MilliVolts(mv as f32)) } else { Err(InvalidValue) } @@ -162,12 +159,10 @@ pub fn temp_to_voltage_poly( #[inline] pub fn temp_to_voltage_seebeck( - temperature: ThermodynamicTemperature, -) -> Result, InvalidValue> { - let celsius = temperature.get::(); - if celsius >= -2.0 && celsius <= 800.0 { - let mv = 0.041 * celsius; - Ok(ElectricPotential::new::(mv)) + temperature: DegreesCelsius, +) -> Result, InvalidValue> { + if temperature.value() >= -2.0 && temperature.value() <= 800.0 { + Ok(MilliVolts(0.041 * temperature.value())) } else { Err(InvalidValue) } diff --git a/src/uom.rs b/src/uom.rs deleted file mode 100644 index 955a205..0000000 --- a/src/uom.rs +++ /dev/null @@ -1,16 +0,0 @@ -//TODO: Everything in here is implemented standalone and not integrated with uom library because it is spawned from macro -// soup + has shit documentation and I cannot figure out how to add a custom unit to SI. This should be integrated with -// UoM - -#[derive(Copy, Clone, PartialEq, PartialOrd, Debug, Default)] -pub struct Irradiance(f32); - -pub fn watts_per_sq_meter(value: f32) -> Irradiance { - Irradiance(value) -} - -impl Irradiance { - fn to_watts_per_sq_meter(self) -> f32 { - self.0 - } -} \ No newline at end of file