Closed ValentinKaisermayer closed 4 years ago
The Sys
must be mutable.
@def_ode_system mutable struct Sys{RH,RO,ST,IP,OP} <: AbstractODESystem
righthandside::RH = function ode(dx, x, u, t)
dx[1] = x[2]
dx[2] = x[3]
dx[3] = -200. * x[1] - 230. * x[2] - 31. * x[3] + u[1](t)
end
readout::RO = (x, u, t) -> 500. * x[1]
state::ST = [0., 0., 0.]
input::IP = Inport()
output::OP = Outport()
end
Then, the simulation works without a problem.
The problem was that during the run stage of the simulation Sys
cannot be mutated(its current time, state, etc.) and the task corresponding to Sys
component fails, which causes the simulation to stop. By the way, you can use troubleshoot function to see the errors thrown during the simulation.
You may also prefer describing the model as
@defmodel model begin
@nodes begin
step = StepGenerator(delay=0.)
sys = Sys()
writer = Writer(input=Inport(2))
end
@branches begin
step[1] => sys[1]
step[1] => writer[1]
sys[1] => writer[2]
end
end
which, I think, looks simpler.
The Sys must be mutable.
Thank you! I see ODESystem
is defined in this way but otherwise the doc strings do not say anything about it.
My fault ! The docstring of @def_ode_system
will completely be revised.
Sry to bother you again... I have added a simple control loop to the model:
using Jusdl, Plots
@def_ode_system mutable struct Sys{RH,RO,ST,IP,OP} <: AbstractODESystem
righthandside::RH = function ode(dx, x, u, t)
dx[1] = x[2]
dx[2] = x[3]
dx[3] = -200. * x[1] - 230. * x[2] - 31. * x[3] + u[1](t)
end
readout::RO = (x, u, t) -> 500. * x[1]
state::ST = [0., 0., 0.]
input::IP = Inport()
output::OP = Outport()
end
@def_ode_system mutable struct PIController{RH,RO,ST,IP,OP} <: AbstractODESystem
kp::Float64 = 1.
Tn::Float64 = 0.1
righthandside::RH = (dx, x, u, t, kp = kp, Tn = Tn) -> (dx[1] = kp / Tn * u[1](t))
readout::RO = (x, u, t, kp = kp) -> kp * u[1](t) + x[1]
state::ST = [0.]
input::IP = Inport()
output::OP = Outport()
end
# Construct the model
model = Model(clock=Clock(0., 0.01, 10.))
addnode!(model, StepGenerator(delay=1.), label=:step)
addnode!(model, Adder(signs=(+, -)), label=:sum)
addnode!(model, PIController(kp=0.2, Tn=0.58), label=:pi)
addnode!(model, Sys(), label=:sys)
addnode!(model, Writer(input=Inport(2)), label=:writer)
addbranch!(model, :step => :sum, 1 => 1)
addbranch!(model, :sys => :sum, 1 => 2)
addbranch!(model, :sum => :pi, 1 => 1)
addbranch!(model, :step => :writer, 1 => 1)
addbranch!(model, :sys => :writer, 1 => 2)
# troubleshoot(model)
sim = simulate!(model)
# Read and plot data
t, x = read(getnode(model, :writer).component)
plot(t, x[:, 1], label="r(t)", xlabel="t")
plot!(t, x[:, 2], label="y(t)", xlabel="t")
But it gets stuck when running the simulation (I do not even get the progressbar). However, troubleshoot(model)
does not reveal any errors (I guess because it errors anyway)
julia> troubleshoot(model)
ERROR: MethodError: no method matching istaskfailed(::Nothing)
The block diagram of the model you try to simulate is as follows.
But the problem is input
port of Sys
and output
port of PI
is not terminated. In Jusdl, all the ports of the components should be terminated.
My fault! I missed the connection of PI
and Sys
.
Besides, I added some extra checks to inspect
stage of the simulation. To use them, please check out the master branch.
]add Jusdl#master
Thx!
In case the simulation gets stuck and you want to see the problem, then you stop the execution by Ctrl+c
first and then call troubleshoot(model)
.
Consider the following two very similar implementations. First with a custom type that derives of
AbstractODESystem
:The simulation will not really work. The estimated ETA is 06:28.
Now the same system but implemented using
ODESystem
:This one is really fast:
However, I can not understand the problem and what the difference between the first and second implementation is.