iliekturtles / uom

Units of measurement -- type-safe zero-cost dimensional analysis
Apache License 2.0
1.01k stars 92 forks source link

Quantity-Aware access parts of quantity with complex storage type #454

Open mkalte666 opened 8 months ago

mkalte666 commented 8 months ago

It can be interesting (or needed) to access only the real or imaginary part of a complex quantity.

Currently, i have solved this for my codebase like this, but it would be nice to have this available in uom directly as well. For all i know, its already there; im known to miss the most obvious functions out there :D

/// Helper trait to grab real or complex parts of Quantities
pub trait ComplexAccess {
    type VT;
    type AT;
    /// Get the real part of Self
    fn real(&self) -> Self::VT;

    /// Get the imaginary part of Self
    fn imag(&self) -> Self::VT;

    /// Get the norm of Self
    fn norm(&self) -> Self::VT;

    /// Get the argument of Self
    fn arg(&self) -> Self::AT;
}

use uom::{storage_type_complex32, storage_type_complex64};

storage_types! {
    pub types: Complex;

    impl<D> crate::ComplexAccess for uom::si::Quantity<D,uom::si::SI<V>,V>
    where
        D: uom::si::Dimension + ?Sized,
    {
        type VT = uom::si::Quantity<D,uom::si::SI<VV>,VV>;
        type AT = uom::si::angle::Angle<uom::si::SI::<VV>,VV>;
        fn real(&self) -> Self::VT {
            Self::VT {
                dimension: self.dimension,
                units: std::marker::PhantomData::default(),
                value: self.value.re
            }
        }

        fn imag(&self) -> Self::VT {
            Self::VT {
                dimension: self.dimension,
                units: std::marker::PhantomData::default(),
                value: self.value.im
            }
        }

        fn norm(&self) -> Self::VT
        {
            Self::VT {
                dimension: self.dimension,
                units: std::marker::PhantomData::default(),
                value: self.value.norm()
            }
        }

        fn arg(&self) -> Self::AT
        {
           Self::AT::new::<uom::si::angle::radian>(self.value.arg())
        }
    }
}

Example usage would be somthing like this:

let z = si::complex64::ElectricalResistance::new::<ohm>(Complex64::new(123.0,321.0));
let im : si::f64::ElectricalResistance = z.real(); 
assert_eq!(im.get::<ohm>(), 321.0);
// do something with re; i.e compute a capacitance or whatever else 
iliekturtles commented 8 months ago

I don't think the trait is necessary. Similar to how how methods for other underlying types are implemented, we would just need to add methods for Complex to return the re/im fields.

e.g. is_nan for floating point types: https://github.com/iliekturtles/uom/blob/85b665e8e574ff9b5ab91163f5b95c0e10412b9b/src/system.rs#L759-L780

mkalte666 commented 8 months ago

oh sorry I should have clarified this; im using the trait because I don't wanna keep track of(rather, don't have the time for) more patching right now. Basically a quick and dirty way to get this to work for me right now without much thought^^

A solution like you described would be much preferable :D

Maybe I can get to that as well later, but right now I'm quite busy in way to may ways ;_;