Component based modelling with ModelingToolkit.jl

I want to model a simple heating system using ModelingToolkit.jl. It consists of a thermal storage, a boiler and a heat consumer.
The following equations govern this model.

Thermal Storage
The thermal storage has one state variable and is modelled with
\frac{d}{dt}soc(t) = -\alpha soc(t) - \frac{1}{m_{max}}(\dot{m}_{in,A}(t) + \dot{m}_{out,B}(t))
where soc(t) is the state-of-charge of the thermal storage. \dot{m}_{in,A}(t) and \dot{m}_{out,B}(t) are the in and outflowing massflows of hot water.

Boiler
The boiler has no dynamics and is modelled with
\dot{m}_{in,b}(t)T_{in,b}c_p+\dot{m}_{out,b}(t)T_{out,b}c_p+\dot{Q}(t)=0
\dot{Q}(t) = k u(t)
\dot{m}_{in,b}(t)+\dot{m}_{out,b}(t) = 0
where \dot{m}_{in,b}(t)\leq0 and \dot{m}_{out,b}(t)\geq0 are the in and outflowing massflows of water. T_{in,b} and T_{out,b} are the respective temperatures and c_p is the specific heat capacity of water. u(t)\in(0,1) is the control input of the boiler. \dot{Q}(t)\geq0 is therefore the produced heat of the boiler.

Heat Consumer
The heat consumer has no dynamics and is modelled with
\dot{m}_{in,hc}(t)T_{in,hc}c_p+\dot{m}_{out,hc}(t)T_{out,hc}c_p-\dot{Q}_{demand}(t)=0
\dot{m}_{in,hc}(t)+\dot{m}_{out,hc}(t) = 0
where \dot{Q}_{demand}(t)\geq0 is the known heat demand of the cosumer. Again \dot{m}_{in,hc}(t)\leq0 and \dot{m}_{out,hc}(t)\geq0 are the in and outflowing massflows of water. T_{in,hc} and T_{out,hc} are the respective temperatures and c_p is the specific heat capacity of water.

Connections
\dot{m}_{out,B}(t) + \dot{m}_{in,hc}(t) = 0
\dot{m}_{out,b}(t) + \dot{m}_{in,A}(t) = 0

For this simple example the whole thing could be condensed into one single ODE
\frac{d}{dt}soc(t) = -\alpha soc(t) - \frac{1}{m_{max}}(\frac{1}{(T_{in,b}-T_{out,b})c_p}k u(t) + \frac{1}{(T_{in,hc}-T_{out,hc})c_p}\dot{Q}_{demand}(t))
but I want to automate that.

My questions?

  • The ODE for the thermal storage is quite clear but how can I model the other to componets with ModelingToolkit.jl? Is this even possible since they have no state variables?
  • How would I provide known variables like \dot{Q}_{demand}(t) or u(t) using ModelingToolkit.jl? u(t) can only change a fixed time steps and \dot{Q}_{demand}(t) would have to be interpolated for a given t. I guess this is something for a PeriodicCallback?

For the manual approach I have:

mutable struct SimType{T} <: DEDataVector{T}
    x::Vector{T}
    u::T
    Qdot_hc::T
end

function f(du, u, p, t)
    mdot_in_gb = k * u.u / (cp_W * (T_in_gb - T_out_gb))
    mdot_out_hc = u.Qdot_hc / (cp_W * (T_in_hc - T_out_hc))

    du[1] = - alpha * u[1] - 1 / m_max * (mdot_in_gb + mdot_out_hc)
    return
end

function cb(int)
    timestamp = t0 + int.t
    int.u.u = # interpolate from data
    int.u.Qdot_hc = # interpolate from data
    return
end

u0 = SimType([0.5], 0.0, Qdot_hc_0)
tspan = (0.0, 900. * 96) # 24h @ 15min
prob = ODEProblem(f, u0, tspan)
sol = solve(prob, Tsit5(); callback = PeriodicCallback(cb, 900.))

However, I do not quite get the correct results. Is there any obvious mistake?

Thanks!

It looks like you’ve got yourself a DAE. The best way to handle this is probably with a singular mass matrix.

1 Like