|
1 |
| -@data Clocks begin |
| 1 | +abstract type AbstractClock end |
| 2 | + |
| 3 | +@data Clocks<:AbstractClock begin |
2 | 4 | ContinuousClock
|
3 | 5 | struct PeriodicClock
|
4 | 6 | dt::Union{Nothing, Float64, Rational{Int}}
|
5 | 7 | phase::Float64 = 0.0
|
6 | 8 | end
|
7 | 9 | SolverStepClock
|
| 10 | + struct EventClock |
| 11 | + id::Symbol |
| 12 | + end |
8 | 13 | end
|
9 | 14 |
|
| 15 | +@derive Clocks[Show, Hash, Eq] |
| 16 | + |
10 | 17 | # for backwards compatibility
|
11 |
| -const TimeDomain = Clocks.Type |
12 |
| -using .Clocks: ContinuousClock, PeriodicClock, SolverStepClock |
| 18 | +const TimeDomain = AbstractClock |
| 19 | +using .Clocks: ContinuousClock, PeriodicClock, SolverStepClock, EventClock |
13 | 20 | const Continuous = ContinuousClock()
|
14 | 21 | (clock::TimeDomain)() = clock
|
15 | 22 |
|
@@ -40,44 +47,99 @@ discrete-time systems that assume a fixed sample time, such as PID controllers a
|
40 | 47 | filters.
|
41 | 48 | """ SolverStepClock
|
42 | 49 |
|
43 |
| -isclock(c::TimeDomain) = @match c begin |
| 50 | +isclock(c::Clocks.Type) = @match c begin |
44 | 51 | PeriodicClock() => true
|
45 | 52 | _ => false
|
46 | 53 | end
|
| 54 | +isclock(::TimeDomain) = false |
47 | 55 |
|
48 |
| -issolverstepclock(c::TimeDomain) = @match c begin |
| 56 | +issolverstepclock(c::Clocks.Type) = @match c begin |
49 | 57 | SolverStepClock() => true
|
50 | 58 | _ => false
|
51 | 59 | end
|
| 60 | +issolverstepclock(::TimeDomain) = false |
52 | 61 |
|
53 |
| -iscontinuous(c::TimeDomain) = @match c begin |
| 62 | +iscontinuous(c::Clocks.Type) = @match c begin |
54 | 63 | ContinuousClock() => true
|
55 | 64 | _ => false
|
56 | 65 | end
|
| 66 | +iscontinuous(::TimeDomain) = false |
| 67 | + |
| 68 | +iseventclock(c::Clocks.Type) = @match c begin |
| 69 | + EventClock() => true |
| 70 | + _ => false |
| 71 | +end |
| 72 | +iseventclock(::TimeDomain) = false |
57 | 73 |
|
58 | 74 | is_discrete_time_domain(c::TimeDomain) = !iscontinuous(c)
|
59 | 75 |
|
60 | 76 | # workaround for https://github.com/Roger-luo/Moshi.jl/issues/43
|
61 | 77 | isclock(::Any) = false
|
62 | 78 | issolverstepclock(::Any) = false
|
63 | 79 | iscontinuous(::Any) = false
|
| 80 | +iseventclock(::Any) = false |
64 | 81 | is_discrete_time_domain(::Any) = false
|
65 | 82 |
|
66 |
| -function first_clock_tick_time(c, t0) |
| 83 | +# public |
| 84 | +function first_clock_tick_time(c::Clocks.Type, t0) |
67 | 85 | @match c begin
|
68 | 86 | PeriodicClock(dt) => ceil(t0 / dt) * dt
|
69 | 87 | SolverStepClock() => t0
|
70 | 88 | ContinuousClock() => error("ContinuousClock() is not a discrete clock")
|
| 89 | + EventClock() => error("Event clocks do not have a defined first tick time.") |
| 90 | + _ => error("Unimplemented for clock $c") |
71 | 91 | end
|
72 | 92 | end
|
73 | 93 |
|
74 |
| -struct IndexedClock{I} |
75 |
| - clock::TimeDomain |
| 94 | +function first_clock_tick_time(c::TimeDomain, _) |
| 95 | + error("Unimplemented for clock $c") |
| 96 | +end |
| 97 | + |
| 98 | +# public |
| 99 | +""" |
| 100 | + $(TYPEDEF) |
| 101 | +
|
| 102 | +A struct representing the operation of indexing a clock to obtain a subset of the time |
| 103 | +points at which it ticked. The actual list of time points depends on the tick instances |
| 104 | +on which the clock was ticking, and can be obtained via `canonicalize_indexed_clock` |
| 105 | +by providing a timeseries solution object. |
| 106 | +
|
| 107 | +For example, `IndexedClock(PeriodicClock(0.1), 3)` refers to the third time that |
| 108 | +`PeriodicClock(0.1)` ticked. If the simulation started at `t = 0`, then this would be |
| 109 | +`t = 0.2`. Similarly, `IndexedClock(PeriodicClock(0.1), [1, 5])` refers to `t = 0.0` |
| 110 | +and `t = 0.4` in this context. |
| 111 | +
|
| 112 | +# Fields |
| 113 | +
|
| 114 | +$(TYPEDFIELDS) |
| 115 | +""" |
| 116 | +struct IndexedClock{C <: AbstractClock, I} |
| 117 | + """ |
| 118 | + The clock being indexed. A subtype of `SciMLBase.AbstractClock` |
| 119 | + """ |
| 120 | + clock::C |
| 121 | + """ |
| 122 | + The subset of indexes being referred to. This can be an integer, an array of integers, |
| 123 | + a range or `Colon()` to refer to all the points that the clock ticked. |
| 124 | + """ |
76 | 125 | idx::I
|
77 | 126 | end
|
78 | 127 |
|
79 |
| -Base.getindex(c::TimeDomain, idx) = IndexedClock(c, idx) |
| 128 | +# public |
| 129 | +""" |
| 130 | + $(TYPEDSIGNATURES) |
| 131 | +
|
| 132 | +Return a `SciMLBase.IndexedClock` representing the subset of the time points that the clock |
| 133 | +ticked indicated by `idx`. |
| 134 | +""" |
| 135 | +Base.getindex(c::AbstractClock, idx) = IndexedClock(c, idx) |
80 | 136 |
|
| 137 | +# public |
| 138 | +""" |
| 139 | + $(TYPEDSIGNATURES) |
| 140 | +
|
| 141 | +Return the time points in the interval |
| 142 | +""" |
81 | 143 | function canonicalize_indexed_clock(ic::IndexedClock, sol::AbstractTimeseriesSolution)
|
82 | 144 | c = ic.clock
|
83 | 145 |
|
|
0 commit comments