Complex equations

After >20 years working with MODELICA I tried to use Complex equations in MTK.

In a simple example an ohmic resistor and a inductor are connected in series to a constant voltage source. I used per unit system with space-phasors and variable speed of reference frame @parameters wReference.

using ModelingToolkit
using DifferentialEquations
using Plots

frequency = 50.0
Omegarated = frequency*2pi
JJ = 1.0im


function NewVars(eqName::String, CCX::Vector{Complex{Num}})::Tuple{Expr, Expr}
    vari::String = "newVariables = @variables "
    substi::String = ""
    for cx in CCX
        stcx = string(cx)[1:end-3]  # without '(t)'
        vari = string(vari,stcx*"₋re(t) ",stcx*"₋im(t) ")
        substi = string(substi,"$eqName = substitute($eqName,(real($stcx)=>$(stcx)₋re)); ")
        substi = string(substi,"$eqName = substitute($eqName,(imag($stcx)=>$(stcx)₋im)); ")
    end
    return (Meta.parse(vari), Meta.parse(substi))
end

@variables t rad(t)=0.0  w(t)

CX = @variables begin
    deri(t)::ComplexF64
    amps(t)::ComplexF64
    gridVolts(t)::ComplexF64
end


@parameters  x r wReference = 1.0

D = Differential(t)
# DiffC(cpx) =  Complex(D(real(cpx)),D(imag(cpx)))  # used for testing

#NOTE
#NOTE  this line was added in Symbolics - diff.jl
# (D::Differential)(x::Complex{Num}) = Num(D(real(x)))+Num(D(imag(x)))*im
#NOTE


eqs1 = [ D(amps) ~ deri*Omegarated
        gridVolts ~ x*(deri + wReference*amps*JJ) + r*amps
        w ~ D(rad)
        w ~ Omegarated*(1.0-wReference)
        gridVolts ~ Complex(cos(rad), sin(rad))
    ]

eqs=deepcopy(eqs1)

(Bvaria, Bsubst) = NewVars("eqs",CX)
eval(Bvaria) # create new variables
eval(Bsubst) # substitute

pr = 0.3; px = 0.1
u0 = [0.0, 0.0, 0.0]
p = [x => px, r=> pr, wReference => 1.0]

# exact solution
strom = (1.0+0im)/(pr+JJ*px)
println("exact solution: amps = $(strom)")


@named model = ODESystem(eqs)
sys = structural_simplify(model)

prob = ODEProblem(sys, u0, (0., 1.0/frequency), p)
sol = solve(prob, Tsit5())
plot(sol)

my approach

(D::Differential)(x::Complex{Num}

an additional line in diff.jl
(D::Differential)(x::Complex{Num}) = Num(D(real(x)))+Num(D(imag(x)))*im

substitute real(x), imag(x)

real(x), imag(x) are replaced by new @variables x_re x_im

Questions

  • This works with monolithic models. But how to do with component based models? (e.g. connect() and Flow )

backup alternative

To split Complex equations manually. This works, but Symbolics should do this for me.

Thanks

It should, that’s just not all complete yet. For now the splitting needs to be done manually, but it’s on the menu.