Skip to content

Diagnostic Normalisation

MIF-016 bounds dirty diagnostic channels before they enter AER encoding. Each calibrated channel declares its physical unit interval, affine offset, scale, clip policy, provenance, and optional AER address. Samples are mapped into [-1, 1] by

\[ x_\mathrm{norm} = 2 \frac{x - x_\min}{x_\max - x_\min} - 1. \]

The runtime never leaves out-of-range handling implicit. clip saturates at the nearest endpoint and records the channel in the clip mask; reject fails closed with a deterministic error. Every output vector is a read-only float64 array bounded in [-1, 1].

Calibration validation also checks the derived affine coefficients, not only the raw endpoint values. A finite endpoint pair is rejected if the physical span or scale would become non-finite. The midpoint is computed as x_min + 0.5 * (x_max - x_min) so finite endpoints with a finite positive span keep a finite offset instead of overflowing through x_min + x_max.

Python API

normalisation

Bound physical diagnostic channels before AER encoding (MIF-016).

Each channel is mapped from its calibrated physical interval [physical_min, physical_max] into [-1, 1] using the affine map

.. math::

x_\mathrm{norm} = 2 \frac{x - x_\min}{x_\max - x_\min} - 1.

Out-of-range behaviour is explicit per channel: clip saturates deterministically at the endpoint and records a clip mask, while reject raises. The resulting feature vectors are read-only float64 NumPy arrays so downstream AER front-ends cannot observe overflow beyond [-1, 1]. Finite endpoint pairs are also rejected when the derived affine span or scale would be non-finite. The stable midpoint offset remains finite whenever both endpoints and the span are finite.

DiagnosticChannelCalibration(name, unit, physical_min, physical_max, clip_policy, provenance, aer_address=None) dataclass

Calibration record for one physical diagnostic channel.

Parameters are deliberately stored in physical units. The derived offset and scale properties are included in manifests so an AER ingestion chain can reproduce the exact affine mapping without inferring it from opaque data.

offset property

Physical midpoint subtracted before applying scale.

scale property

Multiplicative factor from physical units into the normalized interval.

__post_init__()

Validate channel labels, physical range, clip policy, and AER address.

normalise_value(value)

Return (normalised_value, clipped) for a single channel sample.

to_manifest_row()

Return the durable manifest row for this channel.

NormalisedDiagnosticSample(channel_names, features, clip_mask, out_of_range_channels, sample_period_ns=None) dataclass

Read-only normalised diagnostic vector plus clipping metadata.

__post_init__()

Freeze the normalised features and validate masks and channel metadata.

to_aer_features()

Return the bounded feature vector consumed by the AER front-end.

DiagnosticNormalisationState(calibrations, *, sample_period_ns=None)

Deterministic ordered normalisation state for a diagnostic vector.

calibrations property

Ordered immutable channel calibrations.

channel_names property

Ordered channel names matching feature-vector order.

sample_period_ns property

Nominal sample period associated with the diagnostic frame.

normalise_sample(sample)

Normalise a mapping of physical channel samples into [-1, 1].

normalise_vector(values)

Normalise a positional vector in calibration order.

normalise_batch(samples)

Return a read-only (n_samples, n_channels) matrix of bounded features.

calibration_manifest()

Return the explicit calibration manifest required by MIF-016.

fit_diagnostic_calibrations(observations, *, units, provenance, clip_policy='clip', aer_addresses=None)

Fit min/max calibrations from observed physical samples.

Channel order follows the order of units. Every observation must contain every declared channel, and each channel must span a non-zero physical range.

Manifest Contract

DiagnosticNormalisationState.calibration_manifest() records:

  • schema_version, kernel, sample_period_ns, and output range;
  • one row per channel with physical range, offset, scale, clip policy, provenance, and AER address;
  • deterministic_mapping = true so downstream AER replay can reproduce the exact transform.

Dispatch

Use scpn_mif_core.diagnostics.dispatched_normalisation_state(...) for the fastest available measured backend:

"diagnostics.normalisation" = ["rust", "python", "julia"]

The Python reference remains the canonical manifest surface. Rust mirrors the affine kernel through PyO3, and Julia mirrors the reference behaviour for calibration/scaling audit scripts.

Validation

The committed tests verify:

  • exact affine mapping and manifest fields;
  • deterministic clipping and bounded AER features;
  • reject-policy failure semantics;
  • invalid range, non-finite endpoint, non-finite affine-span, subnormal-scale, missing-channel, and zero-span fit guards;
  • Python/Rust parity across 16 seeded random vectors;
  • Julia reference behaviour in julia/SCPNMIFCore/test/runtests.jl.

End-to-end ControlObservation cosimulation remains downstream of MIF-015. This surface supplies the bounded feature vector and manifest required by that later integration.

Benchmarks

The benchmark harness ships at bench/kernels/bench_diagnostic_normalisation.py. It measures one four-channel frame and a 4 096-frame batch for the allocated Python, Rust, and Julia surfaces. The committed benchmark is local comparison evidence, not CPU-isolated production latency evidence; host load, governor, and runtime versions are recorded in bench/results/diagnostic_normalisation.json.