DDESystem
Construction of DDESystem
A DDESystem is represented by the following state equation
\[ \dot{x} = f(x, h, u, t) \quad t \geq t_0\]
where $t$ is the time, $x$ is the value of the state, $u$ is the value of the input. $h$ is the history function for which
\[ x(t) = h(t) \quad t \leq t_0\]
and by the output equation
\[ y = g(x, u, t) \]
where $y$ is the value of the output.
As an example, consider a system with the state equation
\[ \begin{array}{l} \dot{x} = -x(t - \tau) \quad t \geq 0 \\ x(t) = 1. -\tau \leq t \leq 0 \\ \end{array}\]
First, we define the history function histfunc,
julia> const out = zeros(1)
1-element Array{Float64,1}:
0.0
julia> histfunc(out, u, t) = (out .= 1.);Note that histfunc mutates a vector out. This mutation is for performance reasons. Next the state function can be defined
julia> function statefunc(dx, x, h, u, t)
h(out, u, t - tau) # Update out vector
dx[1] = out[1] + x[1]
end
statefunc (generic function with 1 method)and let us take all the state variables as outputs. Thus, the output function is
julia> outputfunc(x, u, t) = x
outputfunc (generic function with 1 method)Next, we need to define the history for the system. History is defined by specifying a history function, and the type of the lags. There may be two different lag: constant lags which are independent of the state variable $x$ and the dependent lags which are mainly the functions of the state variable $x$. Note that for this example, the have constant lags. Thus,
julia> tau = 1
1
julia> conslags = [tau]
1-element Array{Int64,1}:
1At this point, we are ready to construct the system.
julia> ds = DDESystem(righthandside=statefunc, history=histfunc, readout=outputfunc, state=[1.], input=nothing, output=Outport(), constlags=conslags, depslags=nothing)
DDESystem(righthandside:statefunc, readout:outputfunc, state:[1.0], t:0.0, input:nothing, output:Outport(numpins:1, eltype:Outpin{Float64}))Basic Operation of DDESystem
The basis operaiton of DDESystem is the same as those of other dynamical systems. When triggered from its trigger link, the DDESystem reads its time from its trigger link, reads input, solves its differential equation, computes its output and writes the computed output to its output bus. To drive DDESystem, we must first launch it,
julia> iport, trg, hnd = Inport(), Outpin(), Inpin{Bool}()
(Inport(numpins:1, eltype:Inpin{Float64}), Outpin(eltype:Float64, isbound:false), Inpin(eltype:Bool, isbound:false))
julia> connect!(ds.output, iport)
1-element Array{Link{Float64},1}:
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) @0x00007f1fca575d50
julia> task2 = @async while true
all(take!(iport) .=== NaN) && break
end
Task (runnable) @0x00007f1fcf7f3340When launched, ds is drivable. To drive ds, we can use the syntax drive(ds, t) or put!(ds.trigger, t) where t is the time until which ds is to be driven.
julia> put!(trg, 1.)When driven, ds reads the time t from its trigger link, (since its input is nothing, ds does nothing during its input reading stage), solves its differential equation, computes output and writes the value of its output to its output bus. To signify, the step was taken with success, ds writes true to its handshake which must be read to further drive ds. For this, we can use the syntax approve!(ds) or take!(ds.handshake).
julia> take!(hnd)
trueWe can continue to drive ds.
julia> for t in 2. : 10.
put!(trg, t)
take!(hnd)
endWhen launched, we constructed a task whose state is running which implies that ds can be driven.
julia> task
Task (runnable) @0x00007f1fca575d50
julia> task2
Task (runnable) @0x00007f1fcf7f3340As long as the state of the task is running, ds can be driven. To terminate task safely, we need to terminate the ds.
julia> put!(trg, NaN)Note that the state of task is done which implies that ds is not drivable any more.
Note that the output values of ds is written to its output bus.
julia> iport[1].link.buffer
64-element Buffer{Cyclic,Float64,1}:
436466.81811256823
121540.54530408025
33844.744019186095
9424.577256280585
2624.41135280592
730.8063984953665
203.5040896555394
56.66744834264986
15.77810935478092
4.436563289075519
⋮
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0Full API
Causal.@def_dde_system — Macro@def_dde_system exwhere ex is the expression to define to define a new AbstractDDESystem component type. The usage is as follows:
@def_dde_system mutable struct MyDDESystem{T1,T2,T3,...,TN,OP,RH,RO,ST,IP,OP} <: AbstractDDESystem
param1::T1 = param1_default # optional field
param2::T2 = param2_default # optional field
param3::T3 = param3_default # optional field
⋮
paramN::TN = paramN_default # optional field
constlags::CL = constlags_default # mandatory field
depslags::DL = depslags_default # mandatory field
righthandside::RH = righthandside_function # mandatory field
history::HST = history_function # mandatory field
readout::RO = readout_function # mandatory field
state::ST = state_default # mandatory field
input::IP = input_defauult # mandatory field
output::OP = output_default # mandatory field
endHere, MyDDESystem has N parameters. MyDDESystem is represented by the righthandside and readout function. state, input and output is the state, input port and output port of MyDDESystem.
righthandside must have the signature
function righthandside(dx, x, u, t, args...; kwargs...)
dx .= .... # update dx
endand readout must have the signature
function readout(x, u, t)
y = ...
return y
endNew DDE system must be a subtype of AbstractDDESystem to function properly.
Example
julia> _delay_feedback_system_cache = zeros(1)
1-element Array{Float64,1}:
0.0
julia> _delay_feedback_system_tau = 1.
1.0
julia> _delay_feedback_system_constlags = [1.]
1-element Array{Float64,1}:
1.0
julia> _delay_feedback_system_history(cache, u, t) = (cache .= 1.)
_delay_feedback_system_history (generic function with 1 method)
julia> function _delay_feedback_system_rhs(dx, x, h, u, t,
cache=_delay_feedback_system_cache, τ=_delay_feedback_system_tau)
h(cache, u, t - τ) # Update cache
dx[1] = cache[1] + x[1]
end
_delay_feedback_system_rhs (generic function with 3 methods)
julia> @def_dde_system mutable struct MyDDESystem{RH, HST, RO, IP, OP} <: AbstractDDESystem
constlags::Vector{Float64} = _delay_feedback_system_constlags
depslags::Nothing = nothing
righthandside::RH = _delay_feedback_system_rhs
history::HST = _delay_feedback_system_history
readout::RO = (x, u, t) -> x
state::Vector{Float64} = rand(1)
input::IP = nothing
output::OP = Outport(1)
end
julia> ds = MyDDESystem();Causal.DDESystem — Typemutable struct DDESystem{CL, DL, RH, HST, RO, ST<:(AbstractArray{var"#s301",1} where var"#s301"<:Real), IP<:(Union{var"#s300", var"#s299"} where var"#s299"<:Nothing where var"#s300"<:Inport), OP<:(Union{var"#s298", var"#s297"} where var"#s297"<:Nothing where var"#s298"<:Outport), var"253", var"254", var"255", Symbol, var"256", Float64, var"257", var"258", var"259", var"260", var"261", var"262"} <: AbstractDDESystemConstruct a generic DDE system
Fields
constlags::AnyConstant lags
depslags::AnyDependent lags
righthandside::AnyRight-hand-side function
history::AnyHistory function
readout::AnyReadout function
state::AbstractArray{var"#s301",1} where var"#s301"<:RealState
input::Union{var"#s300", var"#s299"} where var"#s299"<:Nothing where var"#s300"<:InportInput. Expected to be an
InportorNothingoutput::Union{var"#s298", var"#s297"} where var"#s297"<:Nothing where var"#s298"<:OutportOutput port
trigger::Anyhandshake::Anycallbacks::Anyname::Anyid::Anyt::Anymodelargs::Anymodelkwargs::Anysolverargs::Anysolverkwargs::Anyalg::Anyintegrator::Any
Causal.DelayFeedbackSystem — Typemutable struct DelayFeedbackSystem{CL<:(AbstractArray{var"#s301",1} where var"#s301"<:Real), RH, HST, RO, ST<:(AbstractArray{var"#s300",1} where var"#s300"<:Real), IP<:(Union{var"#s299", var"#s298"} where var"#s298"<:Nothing where var"#s299"<:Inport), OP<:(Union{var"#s297", var"#s296"} where var"#s296"<:Nothing where var"#s297"<:Outport), var"253", var"254", var"255", Symbol, var"256", Float64, var"257", var"258", var"259", var"260", var"261", var"262"} <: AbstractDDESystemConstructs DelayFeedbackSystem
Fields
constlags::AbstractArray{var"#s301",1} where var"#s301"<:RealConstant lags
depslags::NothingDependent lags
righthandside::AnyRight-hand-side function
history::AnyHistory function
readout::AnyReadout function
state::AbstractArray{var"#s300",1} where var"#s300"<:RealState
input::Union{var"#s299", var"#s298"} where var"#s298"<:Nothing where var"#s299"<:InportInput, Expected to be an
InportofNothingoutput::Union{var"#s297", var"#s296"} where var"#s296"<:Nothing where var"#s297"<:OutportOutput port
trigger::Anyhandshake::Anycallbacks::Anyname::Anyid::Anyt::Anymodelargs::Anymodelkwargs::Anysolverargs::Anysolverkwargs::Anyalg::Anyintegrator::Any