Part I: Foundations of Sensory AI
Chapter 3: Signals, Sampling, Time, and Synchronization

Event-driven vs clock-driven sensing

"You told me to report every millisecond. For six hours nothing moved, and I dutifully filed six hours of the word 'still'."

An Overworked Telemetry Agent

Two ways to decide when to look

A sensing system faces a scheduling question before it faces any signal-processing question: when do I take a sample? There are exactly two answers. Let a clock decide, and sample on a fixed cadence whether or not anything changed. Or let the signal decide, and emit a sample only when something worth reporting happens. This section is about that fork. It sounds like an implementation detail. It is not. The choice sets your data volume, your power draw, your worst-case latency, and even the mathematical form of the time series that every later chapter has to consume. Pick wrong and you either drown a battery in redundant samples or miss the one microsecond that mattered.

Section 3.1 assumed a uniform sampling grid: take a reading every \(\Delta t\) seconds and reason about aliasing against the Nyquist limit. That is the clock-driven world, and it is the default almost everyone learns first. This section names its opposite and shows when the opposite wins. We keep the book's notation: the continuous signal is \(x(t)\), a clock-driven stream is \(x[n] = x(n\,\Delta t)\), and an event-driven stream is a list of timestamped pairs \((t_k, x_k)\) where the gaps \(t_{k+1} - t_k\) are not constant. If the idea of a transducer emitting an asynchronous pulse feels abstract, Chapter 2 grounds it in the physics of the devices that do exactly this.

Clock-driven sensing: the metronome

What it is. A clock-driven (also called synchronous, periodic, or time-triggered) sensor is paced by a timer. Every \(\Delta t\) seconds the analog-to-digital converter fires, a number lands in a buffer, and the cadence never varies. The sampling rate \(f_s = 1/\Delta t\) is a design constant, and the resulting stream is a uniform grid indexed by an integer \(n\).

Why it dominates. Uniform sampling is the substrate the entire classical toolkit assumes. The Fourier transform, the Nyquist theorem, FIR and IIR filters, and nearly every off-the-shelf neural sequence model expect one sample per tick with a constant spacing. When your data is a uniform grid you can reach for Chapter 6's filters and Chapter 7's spectra without a second thought. Simplicity is the whole selling point.

What it costs. A metronome is indifferent to content. If the world is quiet, the clock keeps sampling anyway, spending bandwidth, storage, and energy on samples that repeat the last one to the bit. If the world produces a spike between two ticks, the clock never sees it: temporal resolution is capped at \(\Delta t\) no matter how fast the event was. You pay a fixed cost for a variable world, and the mismatch is exactly where event-driven sensing gets its opening.

Event-driven sensing: report only on change

What it is. An event-driven (asynchronous, data-triggered) sensor stays silent until the signal does something notable, then emits a timestamped sample. "Notable" is defined by a rule baked into the device: cross a threshold, change by more than \(\delta\) since the last report, or trip an interrupt line. The output is not a grid but a sparse sequence \((t_k, x_k)\), dense in time when the world is active and empty when it is calm.

Why it exists. Three pressures push designs toward events. First, power: a device that transmits nothing during quiet stretches can idle its radio and its processor, which is decisive for coin-cell and batteryless deployments where every transmission is a measurable fraction of the energy budget. Second, latency: an interrupt fires the instant a threshold is crossed, so the reaction time is set by the event, not by waiting for the next scheduled tick. Third, dynamic range in time: a level-crossing scheme captures a microsecond transient and a multi-hour plateau in the same stream, something no single fixed \(f_s\) can do without either oversampling the plateau or aliasing the transient.

The canonical hardware. The dynamic-vision sensor, or event camera, is the purest example: each pixel independently emits an event only when its log-brightness changes past a threshold, so a static scene produces no data and a fast-moving edge produces microsecond-resolution events. We treat these devices in depth in Chapter 46. The humbler cousins are everywhere too: an accelerometer's motion-interrupt pin, a door contact, a Geiger counter, and send-on-delta industrial telemetry all speak in events.

The axis is scheduling, not sensor type

Clock-driven versus event-driven is not a property of the physics being measured; it is a decision about when to convert and when to transmit. The same accelerometer can run in periodic mode (256 Hz uniform samples) or interrupt mode (a pulse when acceleration exceeds a threshold). Choosing between them is choosing where to spend your scarcest resource: cycles and energy on a calm signal, or resolution and simplicity on a bursty one. Every later trade in this chapter, from timestamps to buffering, inherits this first choice.

Level-crossing sampling: the bridge concept

The cleanest way to turn a continuous signal into events is level-crossing (or send-on-delta) sampling. Instead of sampling the time axis uniformly, you sample the amplitude axis uniformly: emit \((t_k, x_k)\) whenever \(x(t)\) has moved by more than a fixed step \(\delta\) from the last value you reported. Formally, given the last emitted sample \(x_{k}\), the next event occurs at the first \(t\) where \(|x(t) - x_k| \ge \delta\). Flat regions generate almost nothing; steep regions generate a burst. The code below runs the rule over a synthetic trace and counts how few samples survive.

import numpy as np

# A calm baseline with one short burst: mostly flat, briefly active.
t = np.linspace(0, 10, 10_000)                 # 1 kHz clock-driven grid
x = 0.05 * np.sin(2 * np.pi * 0.2 * t)         # slow, low-amplitude drift
x[4800:5000] += np.hanning(200) * 2.0          # a fast transient at t~5 s

def level_crossing(t, x, delta):
    """Emit (t_k, x_k) only when x moves by >= delta since the last event."""
    ts, xs = [t[0]], [x[0]]
    last = x[0]
    for ti, xi in zip(t[1:], x[1:]):
        if abs(xi - last) >= delta:
            ts.append(ti); xs.append(xi); last = xi
    return np.array(ts), np.array(xs)

et, ex = level_crossing(t, x, delta=0.1)
print(f"clock-driven samples: {x.size}")       # 10000, one per tick
print(f"event-driven samples: {et.size}")      # a few hundred, clustered in the burst
print(f"fraction kept: {et.size / x.size:.3%}")
A send-on-delta sampler run over a signal that is flat except for one transient. The clock-driven grid spends 10,000 samples regardless; the level-crossing rule keeps only the handful near the burst, and the kept fraction is a direct measure of how much redundancy periodic sampling was paying for.

Run it and the printout tells the whole story: the uniform grid pays 10,000 samples to describe a signal that was interesting for two hundredths of its duration, while the event stream concentrates its samples exactly where the action was. That concentration is the benefit. The cost arrives the moment a downstream tool wants a uniform grid back, because most of Part II and Part IV assume one.

Rebuilding a uniform grid in two lines

Reconstructing a clock-driven series from events (zero-order hold: each event's value persists until the next) is a loop over segments with edge cases at the ends, easily 15 to 20 lines done by hand. pandas collapses it to two, because reindex-plus-forward-fill is a zero-order hold:

import pandas as pd
events = pd.Series(ex, index=pd.to_timedelta(et, unit="s"))
grid = events.reindex(pd.timedelta_range(0, periods=10_000, freq="1ms")).ffill()
Resampling an irregular event stream onto a 1 ms uniform grid with reindex().ffill(), which is exactly a zero-order-hold reconstruction, replacing a hand-written segment loop.

The library handles the timestamp alignment, the fill semantics, and the boundary samples, turning a fiddly reconstruction into a one-liner you can trust.

Choosing, and blending, the two

When clock-driven wins. Reach for periodic sampling when the signal is continuously informative (audio, a spinning-machine vibration line that never truly rests), when you need clean spectra, or when downstream models demand a fixed grid and the power budget is generous. Its predictability is a feature: buffer sizes, latency, and bandwidth are all constant and easy to reason about.

When event-driven wins. Reach for events when the signal is sparse in time (rare threshold crossings, mostly-still scenes), when energy is the binding constraint, or when you need sub-tick latency on a specific trigger. The irregular timestamps are the price, and they ripple forward: models built for uneven spacing, such as the continuous-time state-space models of Chapter 16, exist partly to consume event streams natively rather than forcing them onto a grid first.

The common answer is both. Real systems hybridize. A wearable runs its accelerometer in low-rate periodic mode as a baseline and arms a high-rate interrupt that wakes a burst capture when motion spikes. The periodic stream gives context and clean features; the event trigger buys latency and detail without paying for them during the many quiet hours. That two-tier pattern feeds directly into the streaming-inference budgets of Chapter 60.

A structural-health monitor on a highway bridge

An engineering team instrumented a highway overpass with accelerometers to catch fatigue-inducing vibration from heavy-truck crossings. A pure clock-driven design at 500 Hz per channel across dozens of channels would have generated tens of gigabytes a day, almost all of it recording an empty bridge at rest, and drained the solar-buffered nodes overnight. They went hybrid. Each node held a slow 10 Hz periodic heartbeat for baseline temperature-and-strain trending, plus an amplitude-triggered event mode: when vertical acceleration crossed a threshold, the node captured a 500 Hz burst window around the crossing and transmitted only that. Data volume fell by more than an order of magnitude, the batteries survived the winter, and every genuine truck event was captured at full resolution. The clock watched the calm; the event caught the load.

Exercise: size the trade for a leak detector

You are designing a battery water-leak sensor for under a kitchen sink. It reports over a low-power radio, and each transmission costs a fixed energy \(E_{tx}\). Ninety-nine percent of the time the reading is bone dry and unchanging; a leak, when it happens, must be reported within 5 seconds. (1) Write the expected daily energy for a clock-driven design at rate \(f_s\), and for an event-driven design that transmits only on a wet-threshold crossing plus one heartbeat per hour. (2) At what \(f_s\) does the clock-driven design cost 100x more energy than the event-driven one? (3) State one failure mode the event-driven design has that the clock-driven design does not, and how a periodic heartbeat mitigates it.

Self-check

  1. Rewrite a clock-driven stream \(x[n] = x(n\,\Delta t)\) and an event-driven stream \((t_k, x_k)\) in words: what is held constant in each, the time axis or the amplitude axis?
  2. Give one signal where clock-driven sampling is clearly the right default and one where event-driven clearly wins, and justify each in terms of power, latency, or data volume.
  3. You have an event stream and a filter that assumes a uniform grid. Name the reconstruction step that bridges them and one artifact it can introduce.

What's Next

In Section 3.3, we confront the timestamps themselves. An event stream is only as trustworthy as the \(t_k\) attached to each sample, and once several sensors, each on its own clock, must be reconciled into one timeline, the question of what "the same instant" even means becomes the hard part of building a multi-sensor system.