ModelingToolkitStandardLibrary.jl icon indicating copy to clipboard operation
ModelingToolkitStandardLibrary.jl copied to clipboard

Add units

Open dodoplus opened this issue 3 years ago • 8 comments

MTK now supports units (via Unitful). The standard library should support these as well:

# Parameters:
- `T`: [K] Fixed temperature boundary condition
"""
function FixedTemperature(; name, T)
    @named port = HeatPort()
    pars = @parameters T = T [unit=u"K"]
    eqs = [
        port.T ~ T,
    ]
    ODESystem(eqs, t, [], pars; systems = [port], name = name)
end

better yet, inputs should allow units:

@named fixed = FixedTemperature(T=30u"°C")

with unit translation done internally.

Best would be for MTK to deal with units (and not require inputs to be stripped)

dodoplus avatar Jun 29 '22 14:06 dodoplus

Proposed solution:

inp(u, x) = x
inp(u, x::Quantity) = ustrip(u, x)

...

function Capacitor(; name, C, v_start = 0.0u"V")
    C = inp(u"F", C); v_start = inp(u"V", v_start)
    @named oneport = OnePort(; v_start = v_start)
    @unpack v, i = oneport
    pars = @parameters C = C [unit=u"F"]
    eqs = [
        D(v) ~ i / C,
    ]
    extend(ODESystem(eqs, t, [], pars; name = name), oneport)
end

This way, units are supported but not required.

DD

dodoplus avatar Jun 30 '22 14:06 dodoplus

Interesting approach. @YingboMa thoughts?

ChrisRackauckas avatar Jun 30 '22 14:06 ChrisRackauckas

Shouldn't the user supplied unit be used for something? It can at least be used for checking that it belongs to the correct dimension, probably also convert the input parameter to the correct unit if not provided in an SI unit.

Edit: My bad, I didn't realize ustrip used that way does check units. It sometimes returns Rational numbers though, so might need a convert etc.

baggepinnen avatar Jun 30 '22 14:06 baggepinnen

It sometimes returns Rational numbers though, so might need a convert etc.

ustrip() can convert the result to a supplied type:

julia> ustrip(u"m", 1u"mm") == 1//1000
true

julia> ustrip(Float64, u"m", 2u"mm") == 0.002
true

(from the docs)

dodoplus avatar Jul 01 '22 04:07 dodoplus

Sometimes unit normalization is necessary to get a stable model. I wonder if we could support that as well. For instance, convert all farads to microfarads or second to micro second.

YingboMa avatar Jul 01 '22 05:07 YingboMa

Anecdotally, most issues related to simulation on the ControlSystems reop is because someone has modeled an electronics circuit in seconds, but the time scales appearing in the model are on nano-micro seconds. The solvers really dislike this. If we could facilitate automatic conversion of units that'd be nice, but it would require all parameters of the model to have units. Consider

f # Frequency, e.g., rad/s
y = user_defined_function(f)

if we change the unit of f, we can't know if the user defined function, which may be nonlinear, will work anymore.

  • https://github.com/JuliaControl/ControlSystems.jl/issues/702

baggepinnen avatar Jul 01 '22 05:07 baggepinnen

Unitful has preferunits, so we can use

julia> using Unitful

julia> Unitful.preferunits(u"ms")

julia> upreferred(1e-12u"F")
1.0 A² ms⁴ kg⁻¹ m⁻²

to scale everything to a consistent time scale.

YingboMa avatar Jul 01 '22 23:07 YingboMa

How does this work if the input would be a Num. See #50

ValentinKaisermayer avatar Jul 02 '22 08:07 ValentinKaisermayer