ModelingToolkitStandardLibrary.jl
ModelingToolkitStandardLibrary.jl copied to clipboard
Add units
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)
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
Interesting approach. @YingboMa thoughts?
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.
It sometimes returns
Rationalnumbers though, so might need aconvertetc.
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)
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.
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
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.
How does this work if the input would be a Num. See #50