Understanding @connector in MTK

Hello,
I have trouble understanding the modeling scheme of modern MTK with pins /connectors and so on. As a toy example, I try to implement this simple system of two coupled oscillators:

I tried to model it using the following code:

using Pkg
pkg"activate --temp"
pkg"add ModelingToolkit"

using ModelingToolkit
using ModelingToolkit: t_nounits as t, D_nounits as Dt

@connector θPPin begin
    θ(t), [description = "voltage angle"]
    P(t), [connect = Flow, description = "Power"]
end

@mtkmodel Swing begin
    @components begin
        terminal = θPPin()
    end
    @variables begin
        ω(t) = 0.0, [description = "Rotor frequency"]
    end
    @parameters begin
        M = 1, [description = "Inertia"]
        D = 0.1, [description = "Damping"]
        Pmech, [description = "Mechanical Power"]
    end
    @equations begin
        Dt(terminal.θ) ~ ω
        Dt(ω) ~ 1/M * (Pmech - D*ω - terminal.P)
    end
end

@mtkmodel Line begin
   @components begin
       dst = θPPin()
       src = θPPin()
   end
   @parameters begin
       K = 1.0, [description = "Line conductance"]
   end
   @variables begin
       P(t), [description = "Power flow"]
   end
   @equations begin
       P ~ -K*sin(dst.θ - src.θ)
       src.P ~ -P
       dst.P ~ P
   end
end

@named swing1 = Swing(Pmech=1)
@named swing2 = Swing(Pmech=-1)
@named line = Line()

eqs = [connect(swing1.terminal, line.src),
       connect(swing2.terminal, line.dst)]

@named twoswingmodel = ODESystem(eqs, t, systems = [swing1, swing2, line])
equations(twoswingmodel) # output not helpful because I don't know what happens in `connect()`

sys = structural_simplify(twoswingmodel)
equations(sys)

I know the system is completely reducable to a 4-state ODE. However there seems to be something wrong with my implementation. structural_simplify gets rid of the coupling entirely.

julia> equations(sys)
4-element Vector{Equation}:
 Differential(t)(swing1₊terminal₊θ(t)) ~ swing1₊ω(t)
 Differential(t)(swing1₊ω(t)) ~ (swing1₊Pmech - swing1₊terminal₊P(t) - swing1₊D*swing1₊ω(t)) / swing1₊M
 Differential(t)(swing2₊terminal₊θ(t)) ~ swing2₊ω(t)
 Differential(t)(swing2₊ω(t)) ~ (swing2₊Pmech - swing2₊terminal₊P(t) - swing2₊D*swing2₊ω(t)) / swing2₊M

You can check observed(sys) for the equations that were removed. full_equations(sys) is a nice way to see the fully simplified system.

2 Likes

Thanks Chris, full_equations was exactly what I was looking for. I thought the plain equations already included those algebraic substitutions. Now everything works :slight_smile: