Qu

signal_slice_time

Builtin index · Signal processing

result = signal_slice_time(sig, t0, t1)

Input: sig, t0, t1 · Output: result

What it is

sig: a length-N Signal; t0, t1: numbers (seconds).

Overloads

One call shape — this function is not overloaded.

CodeInputOutputDescription
result = signal_slice_time(sig, t0, t1)
sig Signalsig: a length-N Signal.
t0 numbert0, t1: numbers (seconds).
t1 numbert0, t1: numbers (seconds).
result Signal
Returns a new Signal at the same Fs. The original name for the same operation as cut above — kept as a working alias, not deprecated.

Examples

From the documentation, and run by the build -- the output and the figure below are what the engine actually produced. Simplest first.

fs = 1000
tone = sine(50, fs, 20)
bits = sigma_delta(tone)            # 1-bit noise-shaping quantizer

print("sigma_delta output range: [{min(bits)}, {max(bits)}]")

s = signal(0 to 9, 10)
trimmed = signal_slice_time(s, 0.2, 0.6)   # same operation `cut` is the friendlier name for

print("signal_slice_time(0.2, 0.6) -> {trimmed}")
output
sigma_delta output range: [-1, 1]
signal_slice_time(0.2, 0.6) -> signal(Fs=10) [2, 3, 4, 5, 6]

from signal-processing

How it works

signal_slice_time(sig, t0, t1) — slices a Signal by a TIME range in seconds (half-open [t0, t1), matching the ordinary x[a:b] index grammar's own half-open/0-based convention — see resolve_sel/exec_index_assign above) instead of raw sample positions, converting via the signal's own Fs (i = round(t * Fs), the exact inverse of the already-shipped sig.t accessor's i / Fs). Built as a builtin rather than new x[time: t0 .. t1] index syntax after reading qu-syntax's Idx grammar: index_one parses a:b by first parsing a as a plain expression, then checking for a following : — so time before a : is already meaningful today (it's an ordinary slice lower bound, e.g. x[time:end] where time is a variable holding an index). Special-casing a literal time/freq identifier immediately before : to mean something else entirely would silently change what any existing script using a variable named time or freq as a slice bound does — real risk to established indexing behavior for a feature explicitly scoped (BACKLOG.md) to stay small and self-contained, separate from the bigger named/labeled-axis-indexing design (already flagged there as needing its own design pass). A plain builtin needs no grammar change at all and is exactly as capable for this scope. cut(sig, t_start, t_end) (added alongside the 3 new § signal builtins, 2026-09) is the same operation under a friendlier public name — deliberately NOT a second, separately maintained implementation: a time-based trim only has one sane boundary convention already established in this codebase (INCLUSIVE [t_start, t_end], matching x[a:b]'s own inclusive slice convention and to's), so both names share this one match arm and its error messages via f (the matched name) rather than inventing a third convention or forking the logic. That parenthesis used to say HALF-OPEN, and said so for long enough that book/src/stdlib/signal-processing.md copied it ("the one range in the language that excludes its upper end") and help("cut") inherited it from the book. The arm's own inner comment below had already recorded the change to inclusive; this outer one was never updated to match, so the file contradicted itself and the docs followed the wrong half. Measured on the built binary before correcting it: cut(signal(0 to 9, 10), 0.2, 0.7) is six samples, 2..=7 -- inclusive. Both spellings corrected 2026-09-18, alongside the extraction of signal_time_span, which now makes the bracket form s[t0 s : t1 s] a THIRD spelling sharing this body. Boundary handling: t_start/t_end round to the nearest sample via the signal's own Fs (i = round(t*Fs), the exact inverse of sig.t's i/Fs); t_end past the signal's actual duration clamps to the last sample (matching ordinary slice hi clamping, e.g. x[0:1000] on a 10-element vector), while a negative t_start or t_end < t_start is a clear error rather than a silent empty result — a typo'd negative time is far more likely a mistake than an intentional empty cut.

From the note above this builtin in the interpreter, where the reasoning was written down as it was built.