Data Model

The Rust core emits SpectralRecord values. Bindings may expose equivalent language-native shapes, but the Rust model is canonical.

SpectralAxis

One axis belongs to one dimension of one signal. This avoids assuming that every channel in a file shares the same x-axis.

Fields:

  • values: native axis values as f64 (must be finite);

  • unit: nm, cm-1, um, thz, index, etc.;

  • kind: wavelength, wavenumber, frequency, energy, time or index;

  • order: ascending, descending or non-monotonic.

SpectralAxis::index(n) builds a 0-based ascending index-kind axis for an uncalibrated dimension (e.g. a spatial pixel row).

SpectralArray

One named signal channel. The canonical layout is N-dimensional and lossless: values is a flat, C-order (row-major) buffer of product(shape) elements. Exactly one dimension is the spectral axis (named x); its coordinate is exposed directly as axis so a plain 1-D spectrum stays ergonomic, while non-spectral dimensions keep their coordinate in coords.

Fields:

  • axis: coordinate of the spectral (x) dimension;

  • values: flat C-order buffer, values.len() == product(shape);

  • shape: per-dimension extent, shape.len() == dims.len(), all > 0;

  • dims: dimension names — unique, non-empty, exactly one is x;

  • coords: one SpectralAxis per non-x dimension, keyed by dim name (omitted from JSON when empty);

  • signal_type;

  • optional physical unit;

  • role, such as raw_dn, white_ref, absorbance, reflectance;

  • source, usually file or derived.

Construction:

  • SpectralArray::new(axis, values, dims, …) — the 1-D constructor; requires dims == ["x"] and values.len() == axis.values.len().

  • SpectralArray::new_nd(shape, dims, axis, coords, values, …) — the only path for multi-dimensional signals (e.g. an image cube slice dims = ["y","x"], or a [row, col, x] hyperspectral cube). Enforces the invariants above plus coords[d].values.len() == shape[index_of(d)].

A 1-D spectrum is just the trivial case: shape == [n], dims == ["x"], coords empty.

JSON note: values and axis coordinates are serialized as plain JSON numbers. Non-finite signal values (NaN/Inf, which real spectra may carry as gaps) survive the native PyO3 path but are not representable in strict JSON; use the native/binary transport when values may be non-finite. Axis coordinates are always required to be finite.

SpectralRecord

One normalized sample or acquisition unit.

Fields:

  • signals: named signal channels;

  • signal_type: dominant signal type for convenience;

  • targets: lab reference values for modelling;

  • metadata: JSON-serializable acquisition/instrument/sample metadata;

  • provenance: reader, format, source hashes and warnings;

  • quality_flags: explicit caveats.

Binding Exports

Python exports should include:

  • raw record access;

  • numpy matrix and axis helpers;

  • pandas DataFrame conversion;

  • sklearn dataset/provider classes;

  • torch dataset adapters.

R exports should include:

  • raw record access;

  • matrix plus wavelength vector;

  • data.frame/tibble conversion;

  • target extraction helpers.