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()andFlow)
backup alternative
To split Complex equations manually. This works, but Symbolics should do this for me.
Thanks