Skip to main content

Markers and measurements

A marker is a named point in time. A measurement spans two markers on a channel and publishes numbers about what happens between them: duration, frequency, edge count. Markers are reached through workspace.markers, measurements through workspace.measures.

Measurements are computed on the server and anchored to their markers: move a marker, and the numbers are recomputed.

add, move, remove​

first = workspace.markers.add(sample=0) # returns the marker id
second = workspace.markers.add(sample=250_000)

workspace.markers.move_to(first, sample=1_000)
workspace.markers.remove(first)

for marker in workspace.markers.all():
marker.id
marker.label # "M1", "M2"... assigned by the server
marker.sample
marker.trigger # True for the marker the trigger placed
Removing a marker removes its measurements

A measurement is anchored to two markers. Remove one of them and the measurement goes with it.

measure​

Creates a measurement between two markers on a channel. Computation starts immediately.

measure_id = workspace.measures.add(
first, second,
channel=0,
kinds=["time", "frequency", "edges"],
time_precision=3,
freq_precision=3,
)

measures.between​

The same thing without placing the markers yourself: give two sample indices and the SDK creates the markers for you.

measure_id = workspace.measures.between(
0, workspace.capture.last_sample,
channel=0,
kinds=["frequency", "duty"],
)

The measurement kinds​

kinds is a list drawn from this vocabulary, exported as the constant MEASURE_KINDS in Python, NodeJS and Rust:

time frequency samples edges duty min max average rms
What the server computes today

The server currently does not treat these nine as distinct measurements. It recognises two cases:

You ask forYou get back
A list containing edgesedges alone — the number of edges on the channel between the markers
Anything else, or nothingThe standard timing set: time_total, freq_avg, freq_min, freq_max

So ["time"], ["duty"], ["rms"] and [] all return the same four results, and ["time", "edges"] returns only edges.

The names in a result are not the names you asked for. Read result.kind rather than assuming it echoes your request.

The result kinds you will actually see:

Result kindWhat it is
time_totalDuration between the two markers, in seconds.
freq_avgMean frequency of the signal over that span, in hertz.
freq_minLowest instantaneous frequency in the span.
freq_maxHighest instantaneous frequency in the span.
edgesNumber of edges on the channel between the markers.

Ask for ["edges"] when you want an edge count, and leave kinds alone when you want timing. Requesting the other seven names is accepted and harmless, but does not currently change what comes back.

wait and results​

Measurements are computed asynchronously. wait blocks until nothing is still computing, and hands back the results.

for measure in workspace.measures.wait(timeout=60.0):
measure.id
measure.channel
measure.marker_a, measure.marker_b
measure.computing # False once it is settled
for result in measure.results:
print(result.kind, result.value) # "time" 0.000123

Example output. One measurement asked for the standard timing set and one asked for edges, over the same 500 000-sample window:

time_total 0.02
freq_avg 51480.173999
freq_min 19638.648861
freq_max 107758.62069
edges 101.0

Values are plain numbers in SI units: seconds for time_total, hertz for the three frequencies. The result names are not the kind names you asked for.

measures() returns the current list without waiting, if you would rather poll computing yourself.

Values are numbers, not display strings

result.value is a plain number in SI units (seconds, hertz). The precision settings control how ScanaStudio displays the value; they do not round what you read here.

set_kinds​

Changes what an existing measurement publishes, without recreating it.

workspace.measures.set_kinds(measure_id, ["time", "samples"], time_precision=6)

Clearing​

workspace.measures.remove(measure_id) # one measurement, markers stay
workspace.measures.clear() # every measurement, markers stay
workspace.markers.clear() # everything: markers and measurements