Configuration

Configuration Models

This section details the Pydantic models used for instrument and bench configuration in PyTestLab. These models define the schema for instrument profiles, bench descriptors, and related configuration files.


Bench Configuration

pytestlab.config.bench_config.BenchConfigExtended

Bases: BaseModel

Attributes

automation = None class-attribute instance-attribute

backend_defaults = None class-attribute instance-attribute

bench_name instance-attribute

changelog = None class-attribute instance-attribute

continue_on_automation_error = False class-attribute instance-attribute

continue_on_instrument_error = False class-attribute instance-attribute

custom_validations = None class-attribute instance-attribute

description = None class-attribute instance-attribute

experiment = None class-attribute instance-attribute

instruments instance-attribute

last_modified = None class-attribute instance-attribute

measurement_plan = None class-attribute instance-attribute

model_config = ConfigDict(extra='forbid') class-attribute instance-attribute

simulate = False class-attribute instance-attribute

traceability = None class-attribute instance-attribute

version = None class-attribute instance-attribute

Functions

check_instruments()

Source code in pytestlab/config/bench_config.py
@model_validator(mode="after")
def check_instruments(self) -> BenchConfigExtended:
    if not self.instruments:
        raise ValueError("At least one instrument must be defined in 'instruments'.")
    return self

Instrument Configuration Models

Each instrument profile YAML must specify a device_type that matches one of the following configuration models. These models define the required and optional fields for each instrument type.

Base Instrument Model

pytestlab.config.instrument_config.InstrumentConfig

Bases: BaseModel

Attributes

address = Field(None, description='Instrument connection address (e.g., VISA resource string)') class-attribute instance-attribute

device_type = Field(..., description="Type of the device (e.g., 'PSU', 'Oscilloscope')") class-attribute instance-attribute

manufacturer = Field(..., description='Manufacturer of the instrument') class-attribute instance-attribute

measurement_accuracy = Field(default_factory=dict, description='Measurement accuracy specifications') class-attribute instance-attribute

model = Field(..., description='Model number of the instrument') class-attribute instance-attribute

model_config = ConfigDict(validate_assignment=True, extra='ignore') class-attribute instance-attribute

scpi = Field(None, description="SCPI section with command specifications, aliases, and feature mappings. Must contain 'commands:' and/or 'queries:' or a 'variants:' block.") class-attribute instance-attribute

scpi_variant = Field(None, description='Name of the variant inside scpi.variants to be used with this instrument. Leave empty if not using the multi-variant feature.') class-attribute instance-attribute

serial_number = Field(None, description='Serial number of the instrument') class-attribute instance-attribute


Power Supply

pytestlab.config.power_supply_config.PowerSupplyConfig

Bases: InstrumentConfig

Configuration for Power Supply instruments.

Attributes

channels = Field(..., description='Channel specifications') class-attribute instance-attribute

communication = Field(None, description='Communication features') class-attribute instance-attribute

core_scpi_commands = Field(default_factory=list, description="Required SCPI command aliases for core functionality (e.g., ['set_output', 'set_display', 'reset'])") class-attribute instance-attribute

device_type = 'power_supply' class-attribute instance-attribute

measurement = Field(None, description='Measurement capabilities') class-attribute instance-attribute

model_config = {'arbitrary_types_allowed': True} class-attribute instance-attribute

output_scpi_commands = Field(default_factory=list, description="Required SCPI command aliases for output functionality (e.g., ['set_output_state', 'get_output_state'])") class-attribute instance-attribute

protection = Field(None, description='Protection features') class-attribute instance-attribute

safety_scpi_commands = Field(default_factory=list, description="Required SCPI command aliases for safety functionality (e.g., ['set_voltage_limit', 'set_current_limit'])") class-attribute instance-attribute


Oscilloscope

pytestlab.config.oscilloscope_config.OscilloscopeConfig

Bases: InstrumentConfig

Attributes

acquisition_scpi_commands = Field(default_factory=list, description="Required SCPI command aliases for acquisition operations (e.g., ['acq_set_type', 'digitize'])") class-attribute instance-attribute

bandwidth = Field(..., gt=0, description='Analog bandwidth of the oscilloscope in Hz') class-attribute instance-attribute

channel_scpi_commands = Field(default_factory=list, description="Required SCPI command aliases for channel operations (e.g., ['channel_display', 'probe_set'])") class-attribute instance-attribute

channels = Field(..., min_length=1, description='List of channel configurations') class-attribute instance-attribute

core_scpi_commands = Field(default_factory=list, description="Required SCPI command aliases for core oscilloscope functionality (e.g., ['acquire_points', 'set_channel_axis'])") class-attribute instance-attribute

device_type = Field('oscilloscope', description='Type of the device (oscilloscope)') class-attribute instance-attribute

fft = Field(None, description='FFT capabilities, if available') class-attribute instance-attribute

franalysis = Field(None, description='Frequency Response Analysis capabilities, if available') class-attribute instance-attribute

function_generator = Field(None, description='Integrated function generator capabilities, if available') class-attribute instance-attribute

memory = Field(..., gt=0, description='Maximum memory depth (e.g., in points or seconds)') class-attribute instance-attribute

model_config = ConfigDict(validate_assignment=True, extra='forbid') class-attribute instance-attribute

sampling_rate = Field(..., gt=0, description='Maximum sampling rate in Samples/sec') class-attribute instance-attribute

timebase_settings = Field(None, description='Global timebase settings, if applicable beyond per-channel') class-attribute instance-attribute

trigger = Field(..., description='Trigger system configuration') class-attribute instance-attribute

trigger_scpi_commands = Field(default_factory=list, description="Required SCPI command aliases for trigger operations (e.g., ['configure_trigger', 'trigger_level'])") class-attribute instance-attribute

waveform_scpi_commands = Field(default_factory=list, description="Required SCPI command aliases for waveform operations (e.g., ['wave_data', 'wave_preamble'])") class-attribute instance-attribute

waveform_update_rate = Field(..., gt=0, description='Waveform update rate in waveforms/sec') class-attribute instance-attribute


Waveform Generator

pytestlab.config.waveform_generator_config.WaveformGeneratorConfig

Bases: InstrumentConfig

Configuration for Waveform Generator instruments.

Attributes

burst = Field(None, description='Burst mode capabilities') class-attribute instance-attribute

channels = Field(..., description='Channel specifications') class-attribute instance-attribute

core_scpi_commands = Field(default_factory=list, description="Required SCPI command aliases for core functionality (e.g., ['set_output_state', 'set_voltage_unit', 'set_load_impedance'])") class-attribute instance-attribute

device_type = Field('waveform_generator', description='Type of the device (waveform_generator)') class-attribute instance-attribute

memory_scpi_commands = Field(default_factory=list, description="Required SCPI command aliases for memory management (e.g., ['list_directory', 'delete_file_or_folder'])") class-attribute instance-attribute

model_config = {'arbitrary_types_allowed': True} class-attribute instance-attribute

modulation = Field(None, description='Modulation capabilities') class-attribute instance-attribute

output_scpi_commands = Field(default_factory=list, description="Required SCPI command aliases for output functionality (e.g., ['set_output_polarity', 'set_sync_output_state'])") class-attribute instance-attribute

sweep = Field(None, description='Frequency sweep capabilities') class-attribute instance-attribute

sync_scpi_commands = Field(default_factory=list, description="Required SCPI command aliases for synchronization functionality (e.g., ['set_sync_output_mode', 'set_sync_output_polarity'])") class-attribute instance-attribute

trigger = Field(None, description='Trigger capabilities') class-attribute instance-attribute

waveforms = Field(..., description='Waveform generation capabilities') class-attribute instance-attribute


Multimeter

pytestlab.config.multimeter_config.MultimeterConfig

Bases: InstrumentConfig

Configuration for Multimeter instruments.

Attributes

calibration = Field(None, description='Calibration capabilities') class-attribute instance-attribute

configuration_scpi_commands = Field(default_factory=list, description="Required SCPI command aliases for configuration functionality (e.g., ['set_range', 'set_resolution', 'set_integration_time'])") class-attribute instance-attribute

core_scpi_commands = Field(default_factory=list, description="Required SCPI command aliases for core functionality (e.g., ['identify', 'reset', 'clear'])") class-attribute instance-attribute

device_type = 'multimeter' class-attribute instance-attribute

measurement_functions = Field(None, description='Measurement function specifications') class-attribute instance-attribute

measurement_scpi_commands = Field(default_factory=list, description="Required SCPI command aliases for measurement functionality (e.g., ['configure', 'initiate', 'fetch', 'read'])") class-attribute instance-attribute

model_config = {'arbitrary_types_allowed': True} class-attribute instance-attribute

sampling = Field(None, description='Sampling capabilities') class-attribute instance-attribute

status_scpi_commands = Field(default_factory=list, description="Required SCPI command aliases for status functionality (e.g., ['get_status', 'get_errors', 'get_operation_complete'])") class-attribute instance-attribute

trigger = Field(None, description='Trigger capabilities') class-attribute instance-attribute


DC Active Load

pytestlab.config.dc_active_load_config.DCActiveLoadConfig

Bases: InstrumentConfig

Configuration for DC Active Load instruments.

Attributes

battery_test = Field(None, description='Battery testing capabilities') class-attribute instance-attribute

core_scpi_commands = Field(default_factory=list, description="Required SCPI command aliases for core functionality (e.g., ['set_input_state', 'get_input_state'])") class-attribute instance-attribute

data_acquisition = Field(None, description='Data acquisition capabilities') class-attribute instance-attribute

input_scpi_commands = Field(default_factory=list, description="Required SCPI command aliases for input functionality (e.g., ['set_input_state', 'input_short_state'])") class-attribute instance-attribute

measurement_scpi_commands = Field(default_factory=list, description="Required SCPI command aliases for measurement functionality (e.g., ['measure', 'mode_get_range'])") class-attribute instance-attribute

model_config = {'arbitrary_types_allowed': True} class-attribute instance-attribute

operating_modes = Field(..., description='Operating mode specifications') class-attribute instance-attribute

slew_rate_scpi_commands = Field(default_factory=list, description="Required SCPI command aliases for slew rate functionality (e.g., ['mode_set_slew', 'mode_set_range'])") class-attribute instance-attribute

transient = Field(None, description='Transient capabilities') class-attribute instance-attribute


Vector Network Analyzer (VNA)

pytestlab.config.vna_config.VNAConfig

Bases: InstrumentConfig

Attributes

device_type = 'vna' class-attribute instance-attribute

if_bandwidth = Field(None, description='IF bandwidth in Hz') class-attribute instance-attribute

model_config = ConfigDict(validate_assignment=True, extra='forbid') class-attribute instance-attribute

num_points = Field(None, description='Number of points in the sweep') class-attribute instance-attribute

power_level = Field(None, description='Source power level in dBm') class-attribute instance-attribute

s_parameters = Field(default_factory=(lambda: ['S11', 'S21']), description="List of S-parameters to measure (e.g., ['S11', 'S21'])") class-attribute instance-attribute

start_frequency = Field(None, description='Start frequency for the sweep in Hz') class-attribute instance-attribute

stop_frequency = Field(None, description='Stop frequency for the sweep in Hz') class-attribute instance-attribute


Spectrum Analyzer

pytestlab.config.spectrum_analyzer_config.SpectrumAnalyzerConfig

Bases: InstrumentConfig

Attributes

attenuation = Field(None, description='Input attenuation in dB') class-attribute instance-attribute

device_type = 'spectrum_analyzer' class-attribute instance-attribute

frequency_center = Field(None, description='Center frequency in Hz') class-attribute instance-attribute

frequency_span = Field(None, description='Frequency span in Hz') class-attribute instance-attribute

model_config = ConfigDict(validate_assignment=True, extra='forbid') class-attribute instance-attribute

reference_level = Field(None, description='Reference level in dBm') class-attribute instance-attribute

resolution_bandwidth = Field(None, description='Resolution bandwidth in Hz (RBW)') class-attribute instance-attribute


Power Meter

pytestlab.config.power_meter_config.PowerMeterConfig

Bases: InstrumentConfig

Attributes

averaging_count = Field(None, description='Number of readings to average for a measurement') class-attribute instance-attribute

device_type = 'power_meter' class-attribute instance-attribute

frequency_compensation_value = Field(None, description='Frequency for sensor compensation in Hz') class-attribute instance-attribute

model_config = ConfigDict(validate_assignment=True, extra='forbid') class-attribute instance-attribute

power_units = Field('dBm', description='Units for power measurement') class-attribute instance-attribute


Virtual Instrument

pytestlab.config.virtual_instrument_config.VirtualInstrumentConfig

Bases: InstrumentConfig

Pydantic model for the Virtual Instrument configuration.

Attributes

device_type = 'virtual_instrument' class-attribute instance-attribute


Accuracy Specification

Many instrument models include an accuracy field or section. This is typically defined using the AccuracySpec model.

pytestlab.config.accuracy.AccuracySpec

Bases: BaseModel

Represents a single accuracy specification for a measurement mode. The standard deviation (sigma) is typically calculated as: sqrt((percent_reading * reading)^2 + (offset_value)^2) or other forms depending on how specs are given (e.g., % of range).

Attributes

model_config = ConfigDict(validate_assignment=True, extra='forbid') class-attribute instance-attribute

offset_value = Field(None, ge=0, description='Fixed offset accuracy in units of the measurement (e.g., 0.005 V)') class-attribute instance-attribute

percent_range = Field(None, ge=0, description='Accuracy as a percentage of the range (e.g., 0.0001 for 0.01%)') class-attribute instance-attribute

percent_reading = Field(None, ge=0, description='Accuracy as a percentage of the reading (e.g., 0.0001 for 0.01%)') class-attribute instance-attribute

Functions

calculate_std_dev(reading_value, range_value=None)

Calculates the standard deviation (sigma) for a given reading. This is a simplified example; real datasheets can be more complex. Assumes reading_value is positive for typical instrument readings.

Source code in pytestlab/config/accuracy.py
def calculate_std_dev(self, reading_value: float, range_value: float | None = None) -> float:
    """
    Calculates the standard deviation (sigma) for a given reading.
    This is a simplified example; real datasheets can be more complex.
    Assumes reading_value is positive for typical instrument readings.
    """
    if reading_value < 0:
        # Or handle as per specific instrument/measurement context
        # For now, using absolute value for calculation if negative readings are possible and meaningful
        # reading_value = abs(reading_value)
        pass  # Assuming reading_value is typically positive or magnitude.

    variance = 0.0
    if self.percent_reading is not None:
        if self.percent_reading < 0:
            raise ValueError("percent_reading must be non-negative.")
        variance += (self.percent_reading * reading_value) ** 2

    if self.offset_value is not None:
        if self.offset_value < 0:
            raise ValueError("offset_value must be non-negative.")
        variance += self.offset_value**2

    if self.percent_range is not None and range_value is not None:
        if self.percent_range < 0:
            raise ValueError("percent_range must be non-negative.")
        if range_value <= 0:  # Range should be positive
            raise ValueError("range_value must be positive for percent_range calculation.")
        variance += (self.percent_range * range_value) ** 2

    if variance < 0.0:  # Should not happen with non-negative inputs and squaring
        raise ValueError("Calculated variance is negative, check inputs and logic.")
    if variance == 0.0:  # No spec provided, or spec results in zero uncertainty
        return 0.0  # Or raise an error, or return a very small number if appropriate

    return math.sqrt(variance)

Configuration Loader

For advanced users, PyTestLab provides a configuration loader utility for validating and loading profiles.

pytestlab.config.loader.ConfigLoader

Dummy ConfigLoader class for documentation compatibility. This is not used in runtime code, but allows mkdocstrings to resolve 'pytestlab.config.ConfigLoader' for API docs.


For more information on creating and validating instrument profiles, see the Creating Profiles Guide.