Skip to content

Time

Clocks that measure real time, timeouts, periodic behaviour, and what to do when your platform only gives you a timer input.

A tick is a step of logical time: it takes no time at all, and nothing in a chart says how far apart two ticks are. Real controllers still have to wait real time. A stairwell light stays on for five seconds, an LED blinks twice a second, a sensor is read every half second. SCCharts gives you two ways to do this. Timed SCCharts add clock variables that measure the time the environment reports to the chart. The other way is to count the pulses of a timer input that your hardware provides. This chapter covers both, starting with clocks.

EggTimerSimulation

Diagram

Diagram of EggTimerStates: Boiling (initial), Done (final). Transitions: Boiling to Done: t >= 3000 / ring = true.EggTimeroutput boolring = falseclocktBoilingDonet >= 3000/ ring = true

Code

scchart EggTimer {
output bool ring = false
clock t
initial state Boiling
if t >= 3000 do ring = true go to Done
final state Done
}
Tick 0 of 5
Inputs for tick 1
Timing diagram of EggTimer
Tickoutput bool ringlocal float tActive state of the chart
Click a tick to show it, or use the Left and Right arrow keys to go back and step.
Guided tour, 5 ticks Press Next to run tick 1, or Take over to set the inputs yourself.

Guided tour, 5 ticks:

  1. deltaT = 1000Tick 1 enters Boiling. A clock does not advance in the tick its region starts, so t = 0 although deltaT says 1000 ms passed.
  2. deltaT = 1000One second later. Boiling was already active, so the clock advances first: t = 1000. Then the transition is tested: 1000 is not ≥ 3000.
  3. deltaT = 1000t = 2000.
  4. deltaT = 1000t = 3000, and the transition sees the new value in the same tick: ring = true, the chart moves to Done and terminates.
  5. deltaT = 1000The chart has terminated: nothing changes any more.
Each tick is 1000 ms after the last. Watch t stay at 0 in tick 1 and reach 3000 in tick 4.

clock t declares a clock: a float variable that starts at 0 and measures time. Declaring a clock adds two variables to the chart’s interface:

  • the input deltaT: how much time has passed since the previous tick. The environment supplies it.
  • the output sleepT: how long the environment may wait before the next tick (more on this below).

Time passes only through deltaT. At the start of every tick, before any transition is tested, KIELER adds deltaT to the clock. It does so in whatever state the clock’s region is in (the region whose transitions test the clock), whether or not that state looks at the clock itself. The one tick in which the clock does not move is the tick in which that region is entered: tick 1 for the egg timer.

Tick deltaT t State after ring
1 1000 0 Boiling false
2 1000 1000 Boiling false
3 1000 2000 Boiling false
4 1000 3000 Done true

So the timeout if t >= 3000 fires in the tick in which the clock reaches 3000, three ticks after Boiling was entered. Clocks have no built-in unit: t counts in whatever unit the environment uses for deltaT. This chapter uses milliseconds.

In a simulator you play the environment, so you type in how much time passed. If deltaT stays 0, no clock ever moves and nothing times out.

Time arrives in steps of deltaT, and a clock seldom lands exactly on the number you wrote. Here is the same egg timer ticked every 1300 ms, next to a copy that tests t == 3000:

EggTimer and EggTimerEqualComparison

Diagrams

EggTimer

Diagram of EggTimerStates: Boiling (initial), Done (final). Transitions: Boiling to Done: t >= 3000 / ring = true.EggTimeroutput boolring = falseclocktBoilingDonet >= 3000/ ring = true

EggTimerEqual

Diagram of EggTimerEqualStates: Boiling (initial), Done (final). Transitions: Boiling to Done: t == 3000 / ring = true.EggTimerEqualoutput boolring = falseclocktBoilingDonet == 3000/ ring = true

Code

EggTimer

scchart EggTimer {
output bool ring = false
clock t
initial state Boiling
if t >= 3000 do ring = true go to Done
final state Done
}

EggTimerEqual

scchart EggTimerEqual {
output bool ring = false
clock t
initial state Boiling
if t == 3000 do ring = true go to Done
final state Done
}
Tick 0 of 4
Inputs for tick 1, for both charts
Timing diagram of EggTimer and EggTimerEqual, no ticks yet
Tickinput float deltaTEggTimer: output bool ringEggTimer: output float sleepTEggTimer: Active state of the chartEggTimerEqual: output bool ringEggTimerEqual: output float sleepTEggTimerEqual: Active state of the chart
Click a tick to show it, or use the Left and Right arrow keys to go back and step.
Guided tour, 4 ticks Both charts get the same inputs. Press Next to run tick 1, or Take over to set the inputs yourself.

Guided tour, 4 ticks, the same inputs for both charts:

  1. deltaT = 1300Both egg timers are ticked every 1300 ms (deltaT = 1300). Tick 1 enters Boiling: t = 0.
  2. deltaT = 1300t = 1300 in both.
  3. deltaT = 1300t = 2600. (sleepT differs too: EggTimer asks to be woken in 400 ms, exactly at its timeout, while == gives EggTimerEqual no bound to aim for. More on sleepT below.)
  4. deltaT = 1300t = 3900: the clock has jumped over 3000. EggTimer: t >= 3000 holds, so ring comes on, 900 ms late. EggTimerEqual: t == 3000 was never true and never will be, so ring stays false.
Both are ticked every 1300 ms. In tick 4 the clock jumps from 2600 to 3900: >= notices, 900 ms late; == never fires.

t >= 3000 fires in the first tick at or after 3000, so at most one step of deltaT late. t == 3000 is true only if a tick happens to fall on 3000 exactly, and here none does. t > 3000 works, but it is false at exactly 3000: with steps of 1000 it fires a tick later than >= does. Write every timeout as clock >= value.

A clock starts at 0 when the state that declares it is entered. For a clock declared at the top of the chart that is tick 1, and from then on it never stops: it keeps counting in states that never look at it. To time an interval, set the clock back to 0 on the transition that starts the interval:

StairLightSimulation

Diagram

Diagram of StairLightStates: Off (initial), On. Transitions: Off to On: button / light = true; t = 0; On to On: 1: button / t = 0; On to Off: 2: t >= 5000 / light = false.StairLightinput boolbuttonoutput boollight = falseclocktOffOnbutton/ light = true;t = 01: button/ t = 02: t >= 5000/ light = false

Code

scchart StairLight {
input bool button
output bool light = false
clock t
initial state Off
if button do light = true; t = 0 go to On
state On
if button do t = 0 go to On
if t >= 5000 do light = false go to Off
}
Tick 0 of 11
Inputs for tick 1 Boolean input: true while on. It keeps its value until you change it.
Timing diagram of StairLight
Tickinput bool buttonoutput bool lightlocal float tActive state of the chart
Click a tick to show it, or use the Left and Right arrow keys to go back and step.
Guided tour, 11 ticks Press Next to run tick 1, or Take over to set the inputs yourself.

Guided tour, 11 ticks:

  1. button = false, deltaT = 1000Each tick is one second later than the last (deltaT = 1000). Tick 1 enters Off.
  2. button = truePressed. The root’s clock has been running since tick 1 (it says 1000 here before the transition), so the transition resets it: t = 0, light on.
  3. button = falseThe clock advances in On just as it did in Off: t = 1000.
  4. t = 2000.
  5. button = truePressed again. The clock first advances to 3000, then the self-loop (priority 1) resets it: t = 0. The five seconds start again.
  6. button = falset = 1000.
  7. t = 2000.
  8. t = 3000.
  9. t = 4000.
  10. t = 5000: the timeout fires in this tick and light goes off, five seconds after the second press.
  11. The clock is never stopped: it keeps counting in Off (t = 6000). That is why the transition into On resets it.
Warning: KIELER warns about a potential instantaneous loop here, but compiles and runs the chart correctly
  • Warning, line 6, column 17KIELER says: Instantaneous loop detected!KIELER's loop check works on the compiled chart, in which clocks (their timeouts and sleepT) are extra regions and transitions, and warns whenever control could go round a circle there within one tick, without checking whether the triggers prevent it: here the circle runs through On and Off. The chart works as written.About this message
Press in tick 2, press again in tick 5: the light goes off five seconds after the last press.

The transition into On resets the clock, and so does the self-loop that a second press takes. In tick 5 the clock first advances to 3000, then the self-loop sets it back to 0. (The counters pattern builds the same light without a clock, by counting ticks.)

Forgetting the reset is the classic bug of timed charts. Without it the clock keeps the time since tick 1, and once it has passed a bound, every later test against that bound is already true:

Blink and BlinkForgetfulComparison

Diagrams

Blink

Diagram of BlinkStates: Off (initial), On. Transitions: Off to On: t >= 500 / led = true; t = 0; On to Off: t >= 500 / led = false; t = 0.Blinkoutput boolled = falseclocktOffOnt >= 500/ led = true;t = 0t >= 500/ led = false;t = 0

BlinkForgetful

Diagram of BlinkForgetfulStates: Off (initial), On. Transitions: Off to On: t >= 500 / led = true; On to Off: t >= 500 / led = false.BlinkForgetfuloutput boolled = falseclocktOffOnt >= 500/ led = truet >= 500/ led = false

Code

Blink

scchart Blink {
output bool led = false
clock t
initial state Off
if t >= 500 do led = true; t = 0 go to On
state On
if t >= 500 do led = false; t = 0 go to Off
}

BlinkForgetful

scchart BlinkForgetful {
output bool led = false
clock t
initial state Off
if t >= 500 do led = true go to On
state On
if t >= 500 do led = false go to Off
}
Tick 0 of 8
Inputs for tick 1, for both charts
Timing diagram of Blink and BlinkForgetful, no ticks yet
Tickinput float deltaTBlink: output bool ledBlink: output float sleepTBlink: Active state of the chartBlinkForgetful: output bool ledBlinkForgetful: output float sleepTBlinkForgetful: Active state of the chart
Click a tick to show it, or use the Left and Right arrow keys to go back and step.
Guided tour, 8 ticks Both charts get the same inputs. Press Next to run tick 1, or Take over to set the inputs yourself.

Guided tour, 8 ticks, the same inputs for both charts:

  1. deltaT = 250Both blinkers are ticked every 250 ms. Tick 1: t = 0, the LED is off.
  2. deltaT = 250t = 250 in both.
  3. deltaT = 250t = 500: both LEDs come on. Blink resets the clock on the way (t = 0); BlinkForgetful does not (t = 500).
  4. deltaT = 250Blink: t = 250. BlinkForgetful: t = 750, already past 500, so its LED goes off again after only 250 ms.
  5. deltaT = 250Blink: t = 500, so the LED goes off after 500 ms on, and t = 0 again. BlinkForgetful: t = 1000, and its LED is on again: from now on, every timeout test it makes is already true.
  6. deltaT = 250Blink stays off (t = 250); BlinkForgetful flips off.
  7. deltaT = 250Blink comes on after 500 ms off; BlinkForgetful flips on.
  8. deltaT = 250Blink keeps its rhythm, 500 ms on and 500 ms off. BlinkForgetful flips in every tick.
Warning: KIELER warns about a potential instantaneous loop here, but compiles and runs the chart correctly (Blink and BlinkForgetful)
  • Warning in Blink and BlinkForgetful, line 5, column 17KIELER says: Instantaneous loop detected!KIELER's loop check works on the compiled chart, in which clocks (their timeouts and sleepT) are extra regions and transitions, and warns whenever control could go round a circle there within one tick, without checking whether the triggers prevent it: here the circle runs through Off and On. The chart works as written.About this message
Both are ticked every 250 ms. Blink: 500 ms on, 500 ms off. BlinkForgetful: the clock is never reset, so after the first timeout the LED flips in every tick.

A clock declared inside a superstate belongs to that state. Like any local variable it is set to its initial value, 0, every time the state is entered, so restarting the timer is the same as entering the state again:

StairLightLocalSimulation

Diagram

Diagram of StairLightLocalStates: Off (initial), On (superstate), Lit (initial), Expired (final). Transitions: Lit to Expired: t >= 5000; Off to On: button; On to On: 1: button; On to Off: 2:.StairLightLocalinput boolbuttonoutput boollight = falseOffOnclocktentry/ light = trueexit/ light = falseLitExpiredt >= 5000button1: button2:

Code

scchart StairLightLocal {
input bool button
output bool light = false
initial state Off
if button go to On
state On {
clock t
entry do light = true
exit do light = false
initial state Lit
if t >= 5000 go to Expired
final state Expired
}
if button go to On
join to Off
}
Tick 0 of 11
Inputs for tick 1 Boolean input: true while on. It keeps its value until you change it.
Timing diagram of StairLightLocal
Tickinput bool buttoninput float deltaToutput bool lightoutput float sleepTActive state of the chartActive state of the region of On
Click a tick to show it, or use the Left and Right arrow keys to go back and step.
Guided tour, 11 ticks Press Next to run tick 1, or Take over to set the inputs yourself.

Guided tour, 11 ticks:

  1. button = false, deltaT = 1000One second per tick. Tick 1 enters Off.
  2. button = truePressed: On is entered, its entry action switches the light on, and its own clock starts at 0.
  3. button = falseThe clock of On is at 1000. It is declared inside On, so the trace does not show it.
  4. 2000.
  5. button = truePressed again: the self-loop leaves On (the exit action switches the light off) and enters it afresh (the entry action switches it on again). Entering On re-initialises its clock to 0, with no reset written anywhere.
  6. button = false1000.
  7. 2000.
  8. 3000.
  9. 4000.
  10. 5000: Lit → Expired reaches the final state, join to Off fires in the same tick and the exit action switches the light off.
  11. In Off. There is no clock running now: it belongs to On.
Warning: KIELER warns about a potential instantaneous loop here, but compiles and runs the chart correctly
  • Warning, line 13, column 19KIELER says: Instantaneous loop detected!KIELER's loop check works on the compiled chart, in which entry and exit actions and clocks (their timeouts and sleepT) are extra regions and transitions, and warns whenever control could go round a circle there within one tick, without checking whether the triggers prevent it: here the circle runs through On, Lit and Expired. The chart works as written.About this message
The same light, with the clock declared inside On. A second press re-enters On, which restarts its clock.

There is no t = 0 anywhere in this version. The clock of On is a local of a nested state, not part of the chart’s interface, so the trace does not show it.

KIELER handles a clock only if the transitions that test it all belong to the states of one region:

TwoTimersChart

Diagram

Diagram of TwoTimersStates: Steeping (initial), Ready, Boiling (initial), Ready. Transitions: Steeping to Ready: t >= 3000 / tea = true; Boiling to Ready: t >= 5000 / egg = true.TwoTimersoutput booltea = false, egg = falseclocktSteepingReadyt >= 3000/ tea = trueBoilingReadyt >= 5000/ egg = true

Code

scchart TwoTimers {
output bool tea = false, egg = false
clock t
region {
initial state Steeping
if t >= 3000 do tea = true go to Ready
state Ready
}
region {
initial state Boiling
if t >= 5000 do egg = true go to Ready
state Ready
}
}

KIELER rejects this chart

  • Line 13, column 10Clock t is read by several concurrent regions of TwoTimers.KIELER says: Cannot handle concurrent timed automata using the same clock. Add @ClocksUseSD annotation for experimental support based on schduling directives.Declare one clock per region and reset it on entry. KIELER's timed automata give every clock to one region, which advances it.About this message
Two concurrent regions test the same clock t.

KIELER rejects two arrangements:

  • One clock tested in two concurrent regions, as above. Official KIELER says (the misspelling is KIELER’s)

    Cannot handle concurrent timed automata using the same clock. Add @ClocksUseSD annotation for experimental support based on schduling directives.

    and SCCharts Lab says

    Clock t is read by several concurrent regions of TwoTimers.
  • One clock tested by a superstate’s own transitions and inside it. Official KIELER says

    Cannot handle hierarchical timed automata. Add @ClocksUseSD annotation for experimental support based on SDs.

    and SCCharts Lab says Clock t is read both by Outer and inside it.

Charts in which a timeout lies on a cycle of states, such as the blinker and the stair light, compile with a warning: Instantaneous loop detected! in official KIELER, and in SCCharts Lab

Potential instantaneous loop through the timed transitions on t.

The loop analysis does not know that a clock needs time to reach a timeout. The warning is advisory: the chart is accepted and runs as shown here, as long as no timeout is 0 (more about this warning).

On a real device a chart does not have to be ticked all the time. With dynamic ticks the environment runs a tick when an input changes or when the chart asks for one, measures how long it waited, and passes that time in as the next deltaT. The chart asks through sleepT: at the end of every tick it is the time until the nearest timeout of the active states, or 1000 if that is further away or there is no timeout. Take the egg timer ticked every 1300 ms again. Predict sleepT after ticks 2 and 3, check, then open the explanation:

EggTimerPrediction

Diagram

Diagram of EggTimerStates: Boiling (initial), Done (final). Transitions: Boiling to Done: t >= 3000 / ring = true.EggTimeroutput boolring = falseclocktBoilingDonet >= 3000/ ring = true

Code

scchart EggTimer {
output bool ring = false
clock t
initial state Boiling
if t >= 3000 do ring = true go to Done
final state Done
}

deltaT is 1300 in every tick, and the timeout is t >= 3000.

Inputs per tick. A value in grey was not set in that tick: it holds from an earlier one.

TickdeltaT
11300
21300
31300
Plays the scenario on the diagram, then marks each answer.
Explanation

After tick 2 the clock is at 1300, so the timeout is 1700 away. That is more than 1000, so sleepT is 1000. After tick 3 the clock is at 2600, 400 short of the timeout: sleepT is 400. Tick by tick:

Tick deltaT t sleepT Why
1 1300 0 1000 3000 to go; at most 1000
2 1300 1300 1000 1700 to go
3 1300 2600 400 400 to go
4 1300 3900 1000 fired; no timeout left

If the environment had woken the chart 400 ms after tick 3, ring would have come on exactly at 3000. You can play such an environment on this site: next to the deltaT field of a timed chart, Advance by sleepT sets deltaT to the sleepT of the tick shown and steps.

A chart running on a fixed tick instead (every 10 ms, say) ignores sleepT and passes deltaT = 10 in every tick. From chart to C shows both kinds of main loop.

Annotations on the chart change the defaults. They go before scchart:

  • @SimulateSleep: in every tick after the first, deltaT is set to the previous sleepT, so the chart pretends that exactly the requested time passed.
  • @DefaultSleep 5000: the largest (and the default) sleepT is 5000 instead of 1000.
  • @IntegerClockType: clocks, deltaT and sleepT are int instead of float.
  • @NoSleep: no sleepT output at all.

@SimulateSleep is the easiest way to watch a timed chart in a simulator, because you never type a deltaT. The chart jumps from timeout to timeout:

BlinkSleepSimulation

Diagram

Diagram of BlinkSleepStates: Off (initial), On. Transitions: Off to On: t >= 500 / led = true; t = 0; On to Off: t >= 300 / led = false; t = 0.BlinkSleepoutput boolled = falseclocktOffOnt >= 500/ led = true;t = 0t >= 300/ led = false;t = 0

Code

@SimulateSleep
scchart BlinkSleep {
output bool led = false
clock t
initial state Off
if t >= 500 do led = true; t = 0 go to On
state On
if t >= 300 do led = false; t = 0 go to Off
}
Tick 0 of 5
Inputs for tick 1
Timing diagram of BlinkSleep
Tickoutput bool ledlocal float tActive state of the chart
Click a tick to show it, or use the Left and Right arrow keys to go back and step.
Guided tour, 5 ticks Press Next to run tick 1, or Take over to set the inputs yourself.

Guided tour, 5 ticks:

  1. deltaT = 0Tick 1 enters Off. The next timeout is 500 ms away: sleepT = 500.
  2. With @SimulateSleep the chart assumes that exactly the requested time passed: deltaT is set to the last sleepT (500), so the timeout fires at once and the LED comes on. On wants 300 ms: sleepT = 300.
  3. deltaT = 300: off again.
  4. deltaT = 500: on. Every tick is a timeout; nothing happens in between.
  5. deltaT = 300: off.
Warning: KIELER warns about a potential instantaneous loop here, but compiles and runs the chart correctly
  • Warning, line 6, column 17KIELER says: Instantaneous loop detected!KIELER's loop check works on the compiled chart, in which clocks (their timeouts and sleepT) are extra regions and transitions, and warns whenever control could go round a circle there within one tick, without checking whether the triggers prevent it: here the circle runs through Off and On. The chart works as written.About this message
On for 300 ms, off for 500 ms: every tick is a timeout, and deltaT is filled in from sleepT.

period 500 in a state makes the inside of that state run only in ticks in which another 500 time units have passed. KIELER gives the state a hidden clock and guards every action and transition inside with “has the period elapsed?”. The default soft reset keeps any excess time; @HardReset before the period throws it away:

Sampler and SamplerHardComparison

Diagrams

Sampler

Diagram of SamplerStates: Run (initial, superstate), Measure (initial). Transitions: Measure to Measure: / samples++.Sampleroutput intsamples = 0Runperiod500Measure/ samples++

SamplerHard

Diagram of SamplerHardStates: Run (initial, superstate), Measure (initial). Transitions: Measure to Measure: / samples++.SamplerHardoutput intsamples = 0Runperiod500Measure/ samples++

Code

Sampler

scchart Sampler {
output int samples = 0
initial state Run {
period 500
initial state Measure
do samples++ go to Measure
}
}

SamplerHard

scchart SamplerHard {
output int samples = 0
initial state Run {
@HardReset
period 500
initial state Measure
do samples++ go to Measure
}
}
Tick 0 of 12
Inputs for tick 1, for both charts
Timing diagram of Sampler and SamplerHard, no ticks yet
Tickinput float deltaTSampler: output int samplesSampler: output float sleepTSampler: Active state of the chartSampler: Active state of the region of RunSamplerHard: output int samplesSamplerHard: output float sleepTSamplerHard: Active state of the chartSamplerHard: Active state of the region of Run
Click a tick to show it, or use the Left and Right arrow keys to go back and step.
Guided tour, 12 ticks Both charts get the same inputs. Press Next to run tick 1, or Take over to set the inputs yourself.

Guided tour, 12 ticks, the same inputs for both charts:

  1. deltaT = 200Tick 1 enters Run in both charts, and both hidden period clocks start at 0. A plain period waits for the first period, so nothing inside runs: samples = 0.
  2. deltaT = 200Both period clocks are at 200. Nothing runs.
  3. deltaT = 200400. Still nothing.
  4. deltaT = 200600: the period has elapsed, so the inside runs once in both: samples = 1. Sampler’s soft reset subtracts 500 and keeps the 100 ms excess; SamplerHard’s hard reset sets its clock back to 0.
  5. deltaT = 200Soft: 100 + 200 = 300. Hard: 200.
  6. deltaT = 200Soft: 500, so Sampler takes its second sample, exactly one period after the first. Hard: 400, nothing yet.
  7. deltaT = 200Soft: 200. Hard: 600, so SamplerHard takes its second sample, 600 ms after its first.
  8. deltaT = 200Soft: 400. Hard: 200.
  9. deltaT = 200Soft: 600, the third sample, with 100 kept. Hard: 400.
  10. deltaT = 400From now on the ticks come 400 ms apart. Soft: 100 + 400 = 500, the fourth sample. Hard: 800, its third.
  11. deltaT = 400400 on both clocks: no sample in either.
  12. deltaT = 400800 on both clocks, and both take a sample. After the same 2800 ms the soft reset has 5 samples and the hard reset 4: with the hard reset, every late tick shifts all the following ones.
Warning: KIELER warns about a potential instantaneous loop here, but compiles and runs the chart correctly (Sampler and SamplerHard)
  • Warning in Sampler and SamplerHardKIELER says: Instantaneous loop detected!KIELER's loop check works on the compiled chart, in which periods are extra regions and transitions, and warns whenever control could go round a circle there within one tick, without checking whether the triggers prevent it. The chart works as written.About this message
Nine ticks 200 ms apart, then three ticks 400 ms apart. After those 2800 ms the soft reset has taken 5 samples, the hard reset 4.

The hidden period clocks are not part of the interface, so the simulation cannot show them. Here they are at the end of each tick (deltaT is 200 up to tick 9, then 400):

Tick Soft clock samples Hard clock samples
1 0 0 0 0
2 200 0 200 0
3 400 0 400 0
4 100 1 0 1
5 300 1 200 1
6 0 2 400 1
7 200 2 0 2
8 400 2 200 2
9 100 3 400 2
10 0 4 0 3
11 400 4 400 3
12 300 5 0 4

With the soft reset a late tick lets the next period come sooner, so in the long run the inside runs once per period. With the hard reset every late tick shifts all the following ones.

Two more details. Like a delayed transition, a plain period waits for the first period: nothing inside runs in the tick the state is entered, not even the entry action of its initial state. immediate period 500 lets the inside run in the entry tick as well. And the guard also covers the transitions leaving the state that declares the period.

Not every platform has dynamic ticks, or reports elapsed time at all. A common alternative is a hardware timer that turns an input on once per period, say second, true in one tick each second. The chart then counts pulses, for instance with a count delay (see chapter 11):

PulseTimerSimulation

Diagram

Diagram of PulseTimerStates: Idle (initial), Waiting. Transitions: Idle to Waiting: start / done = false; Waiting to Idle: 2 second / done = true.PulseTimerinput boolstart, secondoutput booldone = falseIdleWaitingstart/ done = false2 second/ done = true

Code

scchart PulseTimer {
input bool start, second
output bool done = false
initial state Idle
if start do done = false go to Waiting
state Waiting
if 2 second do done = true go to Idle
}
Tick 0 of 12
Inputs for tick 1 Boolean input: true while on. It keeps its value until you change it. Boolean input: true while on. It keeps its value until you change it.
Timing diagram of PulseTimer
Tickinput bool startinput bool secondoutput bool doneActive state of the chart
Click a tick to show it, or use the Left and Right arrow keys to go back and step.
Guided tour, 12 ticks Press Next to run tick 1, or Take over to set the inputs yourself.

Guided tour, 12 ticks:

  1. start = false, second = falseThe environment ticks the chart every 500 ms, and the hardware timer makes second true in every other tick (ticks 2, 4, 6, ...): one pulse per second.
  2. second = true, start = falseA pulse, but nobody is waiting yet.
  3. second = false, start = truestart: Idle → Waiting. This happens just before a pulse: the next one comes in the very next tick.
  4. second = true, start = falseThe first counted pulse, only 500 ms after the start.
  5. second = false, start = falseNo pulse.
  6. second = true, start = falseThe second pulse: if 2 second fires and done is true, 1.5 s after the start.
  7. second = false, start = falseBack in Idle.
  8. second = true, start = truestart again, this time in a tick that has a pulse. A delayed transition does not count the tick its state was entered in, so this pulse does not count.
  9. second = false, start = falseNo pulse.
  10. second = true, start = falseFirst counted pulse.
  11. second = false, start = falseNo pulse.
  12. second = true, start = falseSecond pulse: done, now 2 s after the start. The same chart waited 1.5 s once and 2 s once.
Ticks every 500 ms, a pulse every other tick. The same if 2 second waits 1.5 s the first time and 2 s the second.

The count starts when Waiting is entered, and that can be anywhere between two pulses. Started just before a pulse, the first pulse counts almost at once; started in a tick that has a pulse, that pulse is not counted, because a delayed transition ignores the tick its state was entered in. So “wait for 2 pulses” lasts somewhere between one and two periods. In general, counting n pulses of a timer with period P waits between (n - 1) * P and n * P. This is the phase problem: your interval is not aligned with the timer’s.

How much this matters depends on the job. A faster timer shrinks the error: counting 20 pulses of 100 ms is never more than 100 ms short of two seconds. If the wait must be exact, begin it on a pulse: let the transition into the waiting state wait for second as well (through an intermediate state, if the request can come between pulses). The pulse in the entry tick is not counted, so the wait is then exactly n periods long, at the price of up to one period before it begins. And if the platform can report elapsed time, clocks avoid the problem altogether.

Counting the chart’s own ticks measures time only if the environment ticks the chart at a fixed rate. Under dynamic ticks it measures nothing useful.

Hand dryer

The starter runs the fan only while hands is true. Change it so that the fan keeps running for 2000 ms after the hands are taken away, and keeps running (with a fresh 2000 ms afterwards) if they come back in the meantime. Use a clock. Once the chart has a clock, it gets a deltaT input: test it with deltaT = 500.

Show the starter chart
scchart HandDryer {
input bool hands
output bool fan = false
initial state Idle
if hands do fan = true go to Drying
state Drying
if !hands do fan = false go to Idle
}
Show a solution
scchart HandDryer {
input bool hands
output bool fan = false
clock t
initial state Idle
if hands do fan = true go to Drying
state Drying
if !hands do t = 0 go to Afterrun
state Afterrun
if hands go to Drying
if t >= 2000 do fan = false go to Idle
}
A transition with the effect t = 0 enters a state in tick 5. That state has if t >= 300 go to Next, and deltaT is 100 in every tick. In which tick does the timeout fire?
Show the answer

Answer B: Tick 8

The effect sets the clock to 0 in tick 5, after any advance in that tick. The clock then reaches 100 in tick 6, 200 in tick 7 and 300 in tick 8. It advances before the transition is tested, so the timeout fires in tick 8.

A state is entered with its clock at 0. It has two transitions, if t >= 800 go to A and if t >= 300 go to B. What is sleepT at the end of the entry tick?
Show the answer

Answer A: 300

sleepT asks for the nearest timeout of the active states: 300 time units. Neither bound is more than 1000 away, so the default maximum does not come into it.

Key ideas

  • clock t measures time. The environment reports elapsed time in the input deltaT; the chart asks to be woken through the output sleepT.
  • A clock advances by deltaT at the start of every tick, before any transition is tested, whatever state its region is in; only in the tick its region is entered does it stay put. Write timeouts as t >= value.
  • Reset a clock (t = 0) when a waiting period starts, or declare it in the superstate whose entry should restart it. One clock per region.
  • period v runs a state’s inside once per period. The default is the soft reset, which keeps excess time; @HardReset drops it.
  • Counting a timer input waits between (n - 1) and n periods, depending on the phase.

Next, Methods and code effects: a few lines of code in a transition, with if, loops and local variables.

Report a mistake on this page