nirs4all.data.synthetic.instruments module

Instrument archetype simulation for synthetic NIRS data generation.

This module provides realistic simulation of different NIR instrument types, including their optical characteristics, noise models, and measurement configurations. It also supports multi-sensor systems that stitch together signal chunks from different wavelength ranges, and multi-scan averaging.

Key Features:
  • 20+ instrument archetypes covering benchtop, handheld, process, and embedded

  • Multi-sensor stitching simulation (combining multiple detector ranges)

  • Multi-scan averaging with realistic noise reduction

  • Detector-specific noise models (shot, thermal, 1/f)

  • Wavelength calibration effects

  • Stray light and etalon interference

References

  • Workman Jr, J., & Weyer, L. (2012). Practical Guide and Spectral Atlas for Interpretive Near-Infrared Spectroscopy. CRC Press.

  • Siesler, H. W., Ozaki, Y., Kawata, S., & Heise, H. M. (2002). Near-Infrared Spectroscopy: Principles, Instruments, Applications. Wiley-VCH.

  • ASTM E1944-98(2017): Standard Practice for Describing and Measuring Performance of NIR Instruments.

class nirs4all.data.synthetic.instruments.DetectorType(value)[source]

Bases: str, Enum

Types of NIR detectors.

INGAAS = 'ingaas'
INGAAS_EXTENDED = 'ingaas_ext'
MCT = 'mct'
MEMS = 'mems'
PBS = 'pbs'
PBSE = 'pbse'
SI = 'si'
class nirs4all.data.synthetic.instruments.InstrumentArchetype(name: str, category: ~nirs4all.data.synthetic.instruments.InstrumentCategory, detector_type: ~nirs4all.data.synthetic.instruments.DetectorType, monochromator_type: ~nirs4all.data.synthetic.instruments.MonochromatorType, wavelength_range: ~typing.Tuple[float, float], spectral_resolution: float = 8.0, wavelength_accuracy: float = 0.5, photometric_noise: float = 0.0001, photometric_range: ~typing.Tuple[float, float] = (0.0, 3.0), snr: float = 10000.0, stray_light: float = 0.0001, warm_up_drift: float = 0.1, temperature_sensitivity: float = 0.01, scan_speed: float = 1.0, integration_time_ms: float = 100.0, optical_path: str = 'transmission', multi_sensor: ~nirs4all.data.synthetic.instruments.MultiSensorConfig = <factory>, multi_scan: ~nirs4all.data.synthetic.instruments.MultiScanConfig = <factory>, description: str = '')[source]

Bases: object

Parameterized NIR instrument simulation.

Represents a complete instrument model with optical, electronic, and measurement characteristics. Can be used to generate realistic synthetic spectra that match specific instrument types.

name

Instrument archetype name.

Type:

str

category

Instrument category (benchtop, handheld, etc.).

Type:

nirs4all.data.synthetic.instruments.InstrumentCategory

detector_type

Primary detector type.

Type:

nirs4all.data.synthetic.instruments.DetectorType

monochromator_type

Wavelength selection mechanism.

Type:

nirs4all.data.synthetic.instruments.MonochromatorType

wavelength_range

Nominal wavelength range (nm).

Type:

Tuple[float, float]

spectral_resolution

Spectral resolution (FWHM in nm).

Type:

float

wavelength_accuracy

Wavelength accuracy (nm).

Type:

float

photometric_noise

Photometric noise level (AU).

Type:

float

photometric_range

Photometric range (min, max AU).

Type:

Tuple[float, float]

snr

Signal-to-noise ratio at 1 AU.

Type:

float

stray_light

Stray light level (fraction).

Type:

float

warm_up_drift

Intensity drift during warm-up (%/hour).

Type:

float

temperature_sensitivity

Wavelength shift per °C.

Type:

float

scan_speed

Scans per second.

Type:

float

integration_time_ms

Integration time in milliseconds.

Type:

float

optical_path

Optical path type (‘transmission’, ‘reflection’, etc.).

Type:

str

multi_sensor

Multi-sensor configuration.

Type:

nirs4all.data.synthetic.instruments.MultiSensorConfig

multi_scan

Multi-scan averaging configuration.

Type:

nirs4all.data.synthetic.instruments.MultiScanConfig

description

Human-readable description.

Type:

str

category: InstrumentCategory
description: str = ''
detector_type: DetectorType
get_noise_model_params() Dict[str, float][source]

Get noise model parameters based on detector type.

integration_time_ms: float = 100.0
monochromator_type: MonochromatorType
multi_scan: MultiScanConfig
multi_sensor: MultiSensorConfig
name: str
optical_path: str = 'transmission'
photometric_noise: float = 0.0001
photometric_range: Tuple[float, float] = (0.0, 3.0)
scan_speed: float = 1.0
snr: float = 10000.0
spectral_resolution: float = 8.0
stray_light: float = 0.0001
temperature_sensitivity: float = 0.01
warm_up_drift: float = 0.1
wavelength_accuracy: float = 0.5
wavelength_range: Tuple[float, float]
class nirs4all.data.synthetic.instruments.InstrumentCategory(value)[source]

Bases: str, Enum

Categories of NIR instruments.

BENCHTOP = 'benchtop'
DIODE_ARRAY = 'diode_array'
EMBEDDED = 'embedded'
FILTER = 'filter'
FT_NIR = 'ft_nir'
HANDHELD = 'handheld'
PROCESS = 'process'
class nirs4all.data.synthetic.instruments.InstrumentSimulator(archetype: InstrumentArchetype, random_state: int | None = None)[source]

Bases: object

Apply instrument-specific effects to synthetic spectra.

Simulates the complete instrument response including: - Spectral resolution (instrumental broadening) - Multi-sensor stitching - Multi-scan averaging - Detector noise (shot, thermal, 1/f) - Wavelength calibration errors - Stray light effects - Etalon/fringing interference

archetype

The instrument archetype being simulated.

rng

Random number generator for reproducibility.

Example

>>> archetype = get_instrument_archetype("viavi_micronir")
>>> simulator = InstrumentSimulator(archetype, random_state=42)
>>> spectra_out = simulator.apply(spectra, wavelengths)
apply(spectra: ndarray, wavelengths: ndarray, temperature_offset: float = 0.0) Tuple[ndarray, ndarray][source]

Apply all instrument effects to spectra.

Parameters:
  • spectra – Input spectra array (n_samples, n_wavelengths).

  • wavelengths – Wavelength array in nm.

  • temperature_offset – Temperature deviation from calibration (°C).

Returns:

Tuple of (modified_spectra, output_wavelengths). Output wavelengths may differ if resampled to instrument grid.

class nirs4all.data.synthetic.instruments.MonochromatorType(value)[source]

Bases: str, Enum

Types of wavelength selection mechanisms.

AOTF = 'aotf'
DMD = 'dmd'
FABRY_PEROT = 'fabry_perot'
FILTER_WHEEL = 'filter_wheel'
FT = 'fourier_transform'
GRATING = 'grating'
LVF = 'lvf'
class nirs4all.data.synthetic.instruments.MultiScanConfig(enabled: bool = False, n_scans: int = 16, averaging_method: str = 'mean', scan_to_scan_noise: float = 0.001, wavelength_jitter: float = 0.05, discard_outliers: bool = False, outlier_threshold: float = 3.0)[source]

Bases: object

Configuration for multi-scan averaging/accumulation.

Real instruments often acquire multiple scans per sample and average them to improve signal-to-noise ratio. This config simulates that process.

enabled

Whether multi-scan mode is enabled.

Type:

bool

n_scans

Number of scans to simulate and average.

Type:

int

averaging_method

How to combine scans. Options: ‘mean’, ‘median’, ‘weighted’, ‘savgol’

Type:

str

scan_to_scan_noise

Additional noise between scans (simulates drift).

Type:

float

wavelength_jitter

Random wavelength shift between scans (nm).

Type:

float

discard_outliers

Whether to discard outlier scans.

Type:

bool

outlier_threshold

Z-score threshold for outlier detection.

Type:

float

averaging_method: str = 'mean'
discard_outliers: bool = False
enabled: bool = False
n_scans: int = 16
outlier_threshold: float = 3.0
scan_to_scan_noise: float = 0.001
wavelength_jitter: float = 0.05
class nirs4all.data.synthetic.instruments.MultiSensorConfig(enabled: bool = False, sensors: ~typing.List[~nirs4all.data.synthetic.instruments.SensorConfig] = <factory>, stitch_method: str = 'weighted', stitch_smoothing: float = 10.0, add_stitch_artifacts: bool = True, artifact_intensity: float = 0.02)[source]

Bases: object

Configuration for multi-sensor spectral stitching.

Modern NIR instruments often use multiple sensors/detectors to cover wide wavelength ranges. This config controls how the signals are combined.

enabled

Whether multi-sensor mode is enabled.

Type:

bool

sensors

List of SensorConfig for each sensor.

Type:

List[nirs4all.data.synthetic.instruments.SensorConfig]

stitch_method

Method for combining overlapping regions. Options: ‘weighted’, ‘average’, ‘first’, ‘last’, ‘optimal’

Type:

str

stitch_smoothing

Smoothing window (nm) at stitch boundaries.

Type:

float

add_stitch_artifacts

Whether to simulate stitching artifacts.

Type:

bool

artifact_intensity

Intensity of stitching artifacts (0-1).

Type:

float

add_stitch_artifacts: bool = True
artifact_intensity: float = 0.02
enabled: bool = False
sensors: List[SensorConfig]
stitch_method: str = 'weighted'
stitch_smoothing: float = 10.0
class nirs4all.data.synthetic.instruments.SensorConfig(detector_type: DetectorType, wavelength_range: Tuple[float, float], spectral_resolution: float = 8.0, noise_level: float = 1.0, gain: float = 1.0, overlap_range: float = 20.0)[source]

Bases: object

Configuration for a single sensor/detector in a multi-sensor system.

Multi-sensor instruments use multiple detectors with different wavelength ranges, then stitch the signals together. This is common in extended-range instruments (e.g., 400-2500 nm coverage using Si + InGaAs detectors).

detector_type

Type of detector for this sensor.

Type:

nirs4all.data.synthetic.instruments.DetectorType

wavelength_range

(start, end) wavelength range in nm.

Type:

Tuple[float, float]

spectral_resolution

Resolution in nm (FWHM).

Type:

float

noise_level

Relative noise level (1.0 = standard).

Type:

float

gain

Detector gain multiplier.

Type:

float

overlap_range

Wavelength overlap with adjacent sensor for stitching (nm).

Type:

float

detector_type: DetectorType
gain: float = 1.0
noise_level: float = 1.0
overlap_range: float = 20.0
spectral_resolution: float = 8.0
wavelength_range: Tuple[float, float]
nirs4all.data.synthetic.instruments.get_instrument_archetype(name: str) InstrumentArchetype[source]

Get a predefined instrument archetype by name.

Parameters:

name – Instrument archetype name.

Returns:

InstrumentArchetype instance.

Raises:

KeyError – If archetype name not found.

Example

>>> archetype = get_instrument_archetype("foss_xds")
>>> print(archetype.wavelength_range)
(400, 2500)
nirs4all.data.synthetic.instruments.get_instruments_by_category() Dict[str, List[str]][source]

Get all instruments organized by category.

Returns:

Dictionary mapping category name to list of instrument names.

nirs4all.data.synthetic.instruments.list_instrument_archetypes(category: InstrumentCategory | None = None) List[str][source]

List available instrument archetype names.

Parameters:

category – Optional filter by category.

Returns:

List of archetype names.

Example

>>> list_instrument_archetypes(InstrumentCategory.HANDHELD)
['viavi_micronir', 'scio', 'tellspec', 'linksquare', 'siware_neoscanner']