DiscreteSystem

Construction of DiscreteSystem

DiscreteSystems evolve by the following discrete time difference equation.

\[ x_{k + 1} = f(x_k, u_k, k) \\ y_k = g(x_k, u_k, k)\]

where $x_k$ is the state, $y_k$ is the value of output and $u_k$ is the value of input at discrete time t. $f$ is the state function and $g$ is the output function of the system. See the main constructor.

Basic Construction of DiscreteSystem

When a DiscreteSystem is triggered from its trigger link, it reads current time from its trigger link, reads its input, solves its difference equation, computes its output and writes its output value to its output bus. Let us continue with an example.

We first define state function sfunc and output function ofunc of the system,

julia> using Causal # hide

julia> sfunc(dx, x, u, t) = (dx .= -0.5x)
sfunc (generic function with 1 method)

julia> ofunc(x, u, t) = x
ofunc (generic function with 1 method)

From sfunc, it is seen that the system does not have any input, and from ofunc the system has one output. Thus, the input and output of the system is

julia> input = nothing

julia> output = Outport(1)
1-element Outport{Outpin{Float64}}:
 Outpin(eltype:Float64, isbound:false)

We also need to specify the initial condition and time of the system

julia> x0  = [1.]
1-element Array{Float64,1}:
 1.0

julia> t = 0.
0.0

We are now ready to construct the system ds.

julia> ds = DiscreteSystem(righthandside=sfunc, readout=ofunc, state=x0, input=input, output=output)
DiscreteSystem(righthandside:sfunc, readout:ofunc, state:[1.0], t:0.0, input:nothing, output:Outport(numpins:1, eltype:Outpin{Float64}))

To drive ds, we need to launch it.

julia> iport, trg, hnd = Inport(1), 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) @0x00007f1fca591870

julia> task2 = @async while true
           all(take!(iport) .=== NaN) && break
           end
Task (runnable) @0x00007f1fca8b1d50

At this point, ds is ready to be driven. To drive ds, we can either use drive(ds, t) or put!(ds.trigger, t).

julia> put!(trg, 1.)

When the above code is executed, ds evolves until its time is ds.t is 1., During this evolution, ds reads time t from its trigger link, reads its input (in this example, ds has no input, so it does nothing when reading its input), solves its difference equation, computes its output and writes its output value to its output. To signal that the evolution is succeeded, ds writes true its handshake link which needs to be taken to further drive ds.

julia> hnd.link  # `handshake` link is readable
Link(state:open, eltype:Bool, isreadable:true, iswritable:false)

julia> take!(hnd)
true

We continue to drive ds,

julia> for i in 2. : 10.
           put!(trg, i)
           take!(hnd)
       end

Note that all the output values of ds is written to its output bus.

julia> iport[1].link.buffer
64-element Buffer{Cyclic,Float64,1}:
  0.0009765625
 -0.001953125
  0.00390625
 -0.0078125
  0.015625
 -0.03125
  0.0625
 -0.125
  0.25
 -0.5
  ⋮
  0.0
  0.0
  0.0
  0.0
  0.0
  0.0
  0.0
  0.0
  0.0

When we launched ds, we constructed a task which is still running.

julia> task
Task (runnable) @0x00007f1fca591870

julia> task2
Task (runnable) @0x00007f1fca8b1d50

As long nothing goes wrong, i.e. no exception is thrown, during the evolution of ds, it is possible to drive ds. To safely terminate the task, we need to terminate the ds.

julia> put!(trg, NaN)

julia> put!(ds.output, [NaN])
1-element Array{Float64,1}:
 NaN

We can confirm that the task is not running and its state is done.

julia> task
Task (done) @0x00007f1fca591870

julia> task2
Task (done) @0x00007f1fca8b1d50

Since the task is not running any more, ds cannot be drivable any more. However to drive ds again, we need launch ds again.

Full API

Causal.@def_discrete_systemMacro
@def_discrete_system ex

where ex is the expression to define to define a new AbstractDiscreteSystem component type. The usage is as follows:

@def_discrete_system mutable struct MyDiscreteSystem{T1,T2,T3,...,TN,OP,RH,RO,ST,IP,OP} <: AbstractDiscreteSystem
    param1::T1 = param1_default                 # optional field 
    param2::T2 = param2_default                 # optional field 
    param3::T3 = param3_default                 # optional field
        ⋮
    paramN::TN = paramN_default                 # optional field 
    righthandside::RH = righthandside_function  # mandatory field
    readout::RO = readout_function              # mandatory field
    state::ST = state_default                   # mandatory field
    input::IP = input_default                   # mandatory field
    output::OP = output_default                 # mandatory field 
end

Here, MyDiscreteSystem has N parameters. MyDiscreteSystem is represented by the righthandside and readout function. state, input and output is the state, input port and output port of MyDiscreteSystem.

Warning

righthandside must have the signature

function righthandside(dx, x, u, t, args...; kwargs...)
    dx .= .... # update dx 
end

and readout must have the signature

function readout(x, u, t)
    y = ...
    return y
end
Warning

New discrete system must be a subtype of AbstractDiscreteSystem to function properly.

Example

julia> @def_discrete_system mutable struct MyDiscreteSystem{RH, RO, IP, OP} <: AbstractDiscreteSystem 
       α::Float64 = 1. 
       β::Float64 = 2. 
       righthandside::RH = (dx, x, u, t, α=α) -> (dx[1] = α * x[1] + u[1](t))
       state::Vector{Float64} = [1.]
       readout::RO = (x, u, t) -> x
       input::IP = Inport(1) 
       output::OP = Outport(1) 
       end

julia> ds = MyDiscreteSystem();

julia> ds.input 
1-element Inport{Inpin{Float64}}:
 Inpin(eltype:Float64, isbound:false)
source
Causal.DiscreteSystemType
mutable struct DiscreteSystem{RH, 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"} <: AbstractDiscreteSystem

A generic discrete system

Fields

  • righthandside::Any

    Right-hand-side function

  • readout::Any

    Readout function

  • state::AbstractArray{var"#s301",1} where var"#s301"<:Real

    State

  • input::Union{var"#s300", var"#s299"} where var"#s299"<:Nothing where var"#s300"<:Inport

    Input. Expected to be an Inport or Nothing

  • output::Union{var"#s298", var"#s297"} where var"#s297"<:Nothing where var"#s298"<:Outport

    Output port

  • trigger::Any

  • handshake::Any

  • callbacks::Any

  • name::Any

  • id::Any

  • t::Any

  • modelargs::Any

  • modelkwargs::Any

  • solverargs::Any

  • solverkwargs::Any

  • alg::Any

  • integrator::Any

Example

julia> sfuncdiscrete(dx,x,u,t) = (dx .= 0.5x);

julia> ofuncdiscrete(x, u, t) = x;

julia> DiscreteSystem(righthandside=sfuncdiscrete, readout=ofuncdiscrete, state=[1.], input=nothing, output=Outport())
DiscreteSystem(righthandside:sfuncdiscrete, readout:ofuncdiscrete, state:[1.0], t:0.0, input:nothing, output:Outport(numpins:1, eltype:Outpin{Float64}))
source
Causal.DiscreteLinearSystemType
mutable struct DiscreteLinearSystem{T1<:(AbstractArray{var"#s301",2} where var"#s301"<:Real), T2<:(AbstractArray{var"#s300",2} where var"#s300"<:Real), T3<:(AbstractArray{var"#s299",2} where var"#s299"<:Real), T4<:(AbstractArray{var"#s298",2} where var"#s298"<:Real), IP<:(Union{var"#s297", var"#s296"} where var"#s296"<:Nothing where var"#s297"<:Inport), OP<:(Union{var"#s295", var"#s294"} where var"#s294"<:Nothing where var"#s295"<:Outport), ST<:(AbstractArray{var"#s293",1} where var"#s293"<:Real), RH, RO, var"253", var"254", var"255", Symbol, var"256", Float64, var"257", var"258", var"259", var"260", var"261", var"262"} <: AbstractDiscreteSystem

Constructs a DiscreteLinearSystem with input and output. state is the initial state and t is the time. modelargs and modelkwargs are passed into ODEProblem and solverargs and solverkwargs are passed into solve method of DifferentialEquations. alg is the algorithm to solve the differential equation of the system.

The DiscreteLinearSystem is represented by the following state and output equations.

\[\begin{array}{l} \dot{x} = A x + B u \\[0.25cm] y = C x + D u \end{array}\]

where $x$ is state. solver is used to solve the above differential equation.

Fields

  • A::AbstractArray{var"#s301",2} where var"#s301"<:Real

    A

  • B::AbstractArray{var"#s300",2} where var"#s300"<:Real

    B

  • C::AbstractArray{var"#s299",2} where var"#s299"<:Real

    C

  • D::AbstractArray{var"#s298",2} where var"#s298"<:Real

    D

  • input::Union{var"#s297", var"#s296"} where var"#s296"<:Nothing where var"#s297"<:Inport

    Input. Expected to an Inport or Nothing

  • output::Union{var"#s295", var"#s294"} where var"#s294"<:Nothing where var"#s295"<:Outport

    Output port

  • state::AbstractArray{var"#s293",1} where var"#s293"<:Real

    State

  • righthandside::Any

    Right-hand-side function

  • readout::Any

    Readout function

  • trigger::Any

  • handshake::Any

  • callbacks::Any

  • name::Any

  • id::Any

  • t::Any

  • modelargs::Any

  • modelkwargs::Any

  • solverargs::Any

  • solverkwargs::Any

  • alg::Any

  • integrator::Any

source
Causal.HenonSystemType
mutable struct HenonSystem{T1<:Real, T2<:Real, T3<:Real, RH, 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"} <: AbstractDiscreteSystem

Constructs a Henon system evolving with the dynamics

\[\begin{array}{l} \dot{x}_1 = 1 - \alpha (x_1^2) + x_2 \\[0.25cm] \dot{x}_2 = \beta x_1 \end{array}\]

Fields

  • α::Real

    α

  • β::Real

    β

  • γ::Real

    γ

  • righthandside::Any

    Right-hand-side function

  • readout::Any

    Readout function

  • state::AbstractArray{var"#s301",1} where var"#s301"<:Real

    State

  • input::Union{var"#s300", var"#s299"} where var"#s299"<:Nothing where var"#s300"<:Inport

    Input. Expected to be an Inport of Nothing

  • output::Union{var"#s298", var"#s297"} where var"#s297"<:Nothing where var"#s298"<:Outport

    Output port

  • trigger::Any

  • handshake::Any

  • callbacks::Any

  • name::Any

  • id::Any

  • t::Any

  • modelargs::Any

  • modelkwargs::Any

  • solverargs::Any

  • solverkwargs::Any

  • alg::Any

  • integrator::Any

source
Causal.LoziSystemType
mutable struct LoziSystem{T1<:Real, T2<:Real, T3<:Real, RH, 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"} <: AbstractDiscreteSystem

Constructs a Lozi system evolving with the dynamics

\[\begin{array}{l} \dot{x}_1 = 1 - \alpha |x_1| + x_2 \\[0.25cm] \dot{x}_2 = \beta x_1 \end{array}\]

Fields

  • α::Real

    α

  • β::Real

    β

  • γ::Real

    γ

  • righthandside::Any

    Right-hand-side function

  • readout::Any

    Readout function

  • state::AbstractArray{var"#s301",1} where var"#s301"<:Real

    State

  • input::Union{var"#s300", var"#s299"} where var"#s299"<:Nothing where var"#s300"<:Inport

    Input. Expected to be an Inport or Nothing

  • output::Union{var"#s298", var"#s297"} where var"#s297"<:Nothing where var"#s298"<:Outport

    Output port

  • trigger::Any

  • handshake::Any

  • callbacks::Any

  • name::Any

  • id::Any

  • t::Any

  • modelargs::Any

  • modelkwargs::Any

  • solverargs::Any

  • solverkwargs::Any

  • alg::Any

  • integrator::Any

source
Causal.BogdanovSystemType
mutable struct BogdanovSystem{T1<:Real, T2<:Real, T3<:Real, T4<:Real, RH, 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"} <: AbstractDiscreteSystem

Constructs a Bogdanov system with equations

\[\begin{array}{l} \dot{x}_1 = x_1 + \dot{x}_2 \\[0.25cm] \dot{x}_2 = x_2 + \epsilon + x_2 + k x_1 (x_1 - 1) + \mu x_1 x_2 \end{array}\]

Fields

  • ε::Real

    ε

  • μ::Real

    μ

  • k::Real

    k

  • γ::Real

    γ

  • righthandside::Any

    Right-hand-side function

  • readout::Any

    Readout function

  • state::AbstractArray{var"#s301",1} where var"#s301"<:Real

    State

  • input::Union{var"#s300", var"#s299"} where var"#s299"<:Nothing where var"#s300"<:Inport

    Input. Expected to be an Inport or Nothing

  • output::Union{var"#s298", var"#s297"} where var"#s297"<:Nothing where var"#s298"<:Outport

    Output port

  • trigger::Any

  • handshake::Any

  • callbacks::Any

  • name::Any

  • id::Any

  • t::Any

  • modelargs::Any

  • modelkwargs::Any

  • solverargs::Any

  • solverkwargs::Any

  • alg::Any

  • integrator::Any

source
Causal.GingerbreadmanSystemType
mutable struct GingerbreadmanSystem{T1<:Real, RH, 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"} <: AbstractDiscreteSystem

Constructs a GingerbreadmanSystem with the dynamics

\[\begin{array}{l} \dot{x}_1 = 1 - x_2 + |x_1|\\[0.25cm] \dot{x}_2 = x_1 \end{array}\]

Fields

  • γ::Real

    γ

  • righthandside::Any

    Right-hand-side function

  • readout::Any

    Readout function

  • state::AbstractArray{var"#s301",1} where var"#s301"<:Real

    State

  • input::Union{var"#s300", var"#s299"} where var"#s299"<:Nothing where var"#s300"<:Inport

    Input. Expected to be Inport or Nothing

  • output::Union{var"#s298", var"#s297"} where var"#s297"<:Nothing where var"#s298"<:Outport

    Output port

  • trigger::Any

  • handshake::Any

  • callbacks::Any

  • name::Any

  • id::Any

  • t::Any

  • modelargs::Any

  • modelkwargs::Any

  • solverargs::Any

  • solverkwargs::Any

  • alg::Any

  • integrator::Any

source
Causal.LogisticSystemType
mutable struct LogisticSystem{T1<:Real, T2<:Real, RH, 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"} <: AbstractDiscreteSystem

Constructs a LogisticSystem with the dynamics

\[\begin{array}{l} \dot{x} = r x (1 - x) \end{array}\]

Fields

  • r::Real

    r

  • γ::Real

    γ

  • righthandside::Any

    Right-hand-side function

  • readout::Any

    Readout function

  • state::AbstractArray{var"#s301",1} where var"#s301"<:Real

    State

  • input::Union{var"#s300", var"#s299"} where var"#s299"<:Nothing where var"#s300"<:Inport

    Input. Expected to be an Inport or Nothing

  • output::Union{var"#s298", var"#s297"} where var"#s297"<:Nothing where var"#s298"<:Outport

    Output port

  • trigger::Any

  • handshake::Any

  • callbacks::Any

  • name::Any

  • id::Any

  • t::Any

  • modelargs::Any

  • modelkwargs::Any

  • solverargs::Any

  • solverkwargs::Any

  • alg::Any

  • integrator::Any

source