RODESystem
Construction of RODESystem
A RODESystem is represented by the state function
and the output function
where $t$ is the time, $x \in R^n$ is the state, $u \in R^p$ and $y \in R^m$ is output of the system. Therefore to construct a RODESystem, we need to define statefunc and outputfunc with the corresponding syntax,
function statefunc(dx, x, u, t)
dx .= ... # Update dx
endand
function outputfunc(x, u, t)
y = ... # Compute y
return y
endAs an example, consider the system with the state function
and with the output function
That is, all the state variable are taken as output. The statefunc and the outputfunc is defined as,
julia> function statefunc(dx, x, u, t, W)
dx[1] = 2x[1]*sin(W[1] - W[2])
dx[2] = -2x[2]*cos(W[1] + W[2])
end
statefunc (generic function with 1 method)
julia> outputfunc(x, u, t) = x
outputfunc (generic function with 1 method)To construct the RODESystem, we need to specify the initial condition and time.
julia> x0 = [1., 1.]
2-element Array{Float64,1}:
1.0
1.0
julia> t = 0.
0.0Note from statefunc, the system has not any input, i.e. input is nothing, and has an output with a dimension of 1.
julia> input = nothing
julia> output = Outport(2)
2-element Outport{Outpin{Float64}}:
Outpin(eltype:Float64, isbound:false)
Outpin(eltype:Float64, isbound:false)We are ready to construct the system
julia> ds = RODESystem(statefunc, outputfunc, x0, t, input, output, solverkwargs=(dt=0.01,))
RODESystem(state:[1.0, 1.0], t:0.0, input:nothing, output:Outport(numpins:2, eltype:Outpin{Float64}))Note that ds has a solver to solve its state function statefunc which is random differential equation. To solve its statefunc, the step size of the solver must be specified. See Random Differential Equtions of DifferentialEquations package.
Basic Operation of RODESystem
When a RODESystem is triggered from its trigger link, it read the current time from its trigger link, reads its input (if available, i.e. its input is not nothing), solves its state function, computes its output value and writes its output value its output bus (again, if available, i.e., its output bus is not nothing). To drive a RODESystem, it must be launched. Let us continue with ds constructed in the previous section.
julia> iport, trg, hnd = Inport(2), Outpin(), Inpin{Bool}()
(Inport(numpins:2, eltype:Inpin{Float64}), Outpin(eltype:Float64, isbound:false), Inpin(eltype:Bool, isbound:false))
julia> connect!(ds.output, iport)
2-element Array{Link{Float64},1}:
Link(state:open, eltype:Float64, isreadable:false, iswritable:false)
Link(state:open, eltype:Float64, isreadable:false, iswritable:false)
julia> connect!(trg, ds.trigger)
Link(state:open, eltype:Float64, isreadable:false, iswritable:false)
julia> connect!(ds.handshake, hnd)
Link(state:open, eltype:Bool, isreadable:false, iswritable:false)
julia> task = launch(ds)
Task (runnable) @0x00007ffa59f66e60
julia> task2 = @async while true
all(take!(iport) .=== NaN) && break
end
Task (runnable) @0x00007ffa54717340When launched, ds is ready to be driven. We can drive ds by drive(ds, t) or put!(ds.trigger, t) where t is the time until which we will drive ds.
julia> put!(trg, 1.)When triggered, ds read the time t from its trigger link, solved its differential equation, computed its value and writes its output value to its output bus. To signal that, the evolution is succeeded, ds writes true to its handshake link which must be taken to further drive ds. (approve!(ds)) can also be used.
julia> take!(hnd)
trueWe can continue to drive ds.
julia> for t in 2. : 10.
put!(trg, t)
take!(hnd)
endAfter each evolution, ds writes its current output value to its output bus.
julia> [outbuf(pin.link.buffer) for pin in iport]
2-element Array{Array{Float64,1},1}:
[62.34787917492586, 424.0644921168532, 168.04807362885012, 50.635593401560456, 13.486441908218948, 32.370471588152526, 43.510574854787926, 13.006621292806043, 6.297871512233011, 3.9063440479253724 … 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
[8.508143462123904e-5, 0.00011059407336745026, 0.0002458416284793932, 0.0006925802467170718, 0.0010365855882468404, 0.0013865847718157016, 0.0020321676920098865, 0.013550493376789199, 0.08189005776821781, 0.3133487727320893 … 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]When launched, a task was constructed which still running. As long as no exception is thrown during the evolution of ds, the state of task is running which implies ds can be driven.
julia> task
Task (runnable) @0x00007ffa59f66e60
julia> task2
Task (runnable) @0x00007ffa54717340To terminate the task safely, ds should be terminated safely.
julia> put!(trg, NaN)
julia> put!(ds.output, [NaN, NaN])
2-element Array{Float64,1}:
NaN
NaNNote that the state of task is done which implies the task has been terminated safely.
julia> task
Task (done) @0x00007ffa59f66e60
julia> task2
Task (done) @0x00007ffa54717340