Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add units #90

Open
dodoplus opened this issue Jun 29, 2022 · 8 comments
Open

Add units #90

dodoplus opened this issue Jun 29, 2022 · 8 comments

Comments

@dodoplus
Copy link

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
Copy link
Author

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

@ChrisRackauckas
Copy link
Member

Interesting approach. @YingboMa thoughts?

@baggepinnen
Copy link
Contributor

baggepinnen commented Jun 30, 2022

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.

@dodoplus
Copy link
Author

dodoplus commented Jul 1, 2022

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)

@YingboMa
Copy link
Member

YingboMa commented Jul 1, 2022

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.

@baggepinnen
Copy link
Contributor

baggepinnen commented Jul 1, 2022

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.

@YingboMa
Copy link
Member

YingboMa commented Jul 1, 2022

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.

@ValentinKaisermayer
Copy link
Contributor

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants