observation_sampling

adapters.observation_sampling

Backend-agnostic resolver for observation-monitor sampling step counts.

Observation models (e.g. BOLD_TVB) are declared once as a backend-neutral YAML pipeline. The number of samples an observation emits, however, depends on the integration time-step dt chosen at run time, not on any value that can be frozen into the YAML. Freezing a step count into the pipeline (as subsample_to_period.stepsize = 180) only holds when the input already sits on a particular stock grid; a backend that applies that literal to the raw integration grid produces the wrong sample count.

This module is the single source of truth that every Python backend (tvboptim, jax, tvb) uses to turn (declarative observation, integration dt) into the integer step counts that drive downsampling. Backends legitimately diverge only in how those counts are applied (circular-buffer convolution vs. functional window-mean+subsample vs. TVB monitor step-mod loop); the counts themselves must be identical.

It is intentionally free of heavy dependencies (no jax/tvb/juliacall, no tvbo.classes) so both the tvboptim runtime module and the export adapters can import it cheaply and without circular-import risk.

Classes

Name Description
ObservationSampling Resolved sampling step counts for one observation at a given dt.

ObservationSampling

adapters.observation_sampling.ObservationSampling(
    period,
    downsample_period,
    interim_istep,
    output_istep,
    output_interim_count,
)

Resolved sampling step counts for one observation at a given dt.

Attributes

Name Type Description
period float | None Output sampling period in ms (TR).
downsample_period float Interim/stock-grid period in ms.
interim_istep int Integration steps per interim (stock) sample.
output_istep int Integration steps per output sample (period / dt).
output_interim_count int Interim samples per output sample (output_istep // interim_istep).

Functions

Name Description
resolve_observation_sampling Resolve an observation’s sampling step counts from the integration dt.
tvb_iround TVB’s iround, character for character, so a monitor’s step count is the one TVB would compute.

resolve_observation_sampling

adapters.observation_sampling.resolve_observation_sampling(
    observation,
    dt,
    *,
    default_downsample_period=4.0,
)

Resolve an observation’s sampling step counts from the integration dt.

This is the single supervenient resolver: it computes the integer step counts from the declarative observation plus the run-time dt. Every Python backend routes through it so the emitted sample count is identical.

Parameters

Name Type Description Default
observation Any A schema observation (must expose pipeline and either period or a TR parameter for output-sampled monitors). required
dt float Integration time-step in ms. required
default_downsample_period float Fallback interim period (ms) when the pipeline declares no stock_dt argument. 4.0

Returns

Name Type Description
An ObservationSampling class:ObservationSampling with the resolved step counts. When the
ObservationSampling observation declares no output period, output_istep /
ObservationSampling output_interim_count are 0.

tvb_iround

adapters.observation_sampling.tvb_iround(value)

TVB’s iround, character for character, so a monitor’s step count is the one TVB would compute.

The body is copied rather than reasoned about: it delegates to Python’s round, which is round-half-to-EVEN, and the - 0.5 correction that follows only guards the float-representation case the TVB docstring cites. So this is not floor(x + 0.5) and differs from it at every exact half — tvb_iround(2.5) is 2, not 3. It is the canonical rounding shared by every backend, so that boundary ratios resolve to the same step count everywhere; a backend spelling it int(round(x)) gets the same answer, and should call this anyway so the definition stays in one place.