Add PSU and DMM drivers

This commit is contained in:
2025-07-08 09:45:40 +00:00
parent 8c10979581
commit b4c21fa54d
3 changed files with 317 additions and 1 deletions

View File

@@ -6,5 +6,12 @@ and handles responses from instruments.
from py_dvt_ate.instruments.drivers.base import BaseDriver from py_dvt_ate.instruments.drivers.base import BaseDriver
from py_dvt_ate.instruments.drivers.chamber import ThermalChamberDriver from py_dvt_ate.instruments.drivers.chamber import ThermalChamberDriver
from py_dvt_ate.instruments.drivers.multimeter import MultimeterDriver
from py_dvt_ate.instruments.drivers.power_supply import PowerSupplyDriver
__all__ = ["BaseDriver", "ThermalChamberDriver"] __all__ = [
"BaseDriver",
"ThermalChamberDriver",
"PowerSupplyDriver",
"MultimeterDriver",
]

View File

@@ -0,0 +1,157 @@
"""Multimeter SCPI driver.
This module implements a client-side driver for digital multimeters
that communicate via SCPI commands.
"""
from py_dvt_ate.instruments.drivers.base import BaseDriver
class MultimeterDriver(BaseDriver):
"""SCPI driver for digital multimeters.
Provides high-level Python API for making measurements with DMMs via
SCPI commands. Implements the IMultimeter interface.
SCPI Commands Used:
MEAS:VOLT:DC? - Measure DC voltage
MEAS:CURR:DC? - Measure DC current
CONF:VOLT:DC - Configure for DC voltage measurement
CONF:CURR:DC - Configure for DC current measurement
CONF? - Query current configuration
READ? - Take measurement with current configuration
Example:
>>> transport = TCPTransport("localhost", 5003)
>>> dmm = MultimeterDriver(transport)
>>> dmm.connect()
>>> voltage = dmm.measure_dc_voltage()
>>> current = dmm.measure_dc_current()
"""
def measure_dc_voltage(self, range: str = "AUTO") -> float:
"""Measure DC voltage.
Configures the meter for DC voltage and takes a measurement.
Args:
range: Measurement range. Default "AUTO" for auto-ranging.
Note: Range parameter currently not supported by simulator.
Returns:
Measured voltage in volts.
Raises:
ConnectionError: If not connected.
IOError: If query fails.
"""
# Note: Range parameter not yet implemented in virtual instrument
return self.query_float("MEAS:VOLT:DC?")
def measure_dc_current(self, range: str = "AUTO") -> float:
"""Measure DC current.
Configures the meter for DC current and takes a measurement.
Args:
range: Measurement range. Default "AUTO" for auto-ranging.
Note: Range parameter currently not supported by simulator.
Returns:
Measured current in amps.
Raises:
ConnectionError: If not connected.
IOError: If query fails.
"""
# Note: Range parameter not yet implemented in virtual instrument
return self.query_float("MEAS:CURR:DC?")
def measure_resistance(self, range: str = "AUTO") -> float:
"""Measure resistance.
Configures the meter for resistance and takes a measurement.
Args:
range: Measurement range. Default "AUTO" for auto-ranging.
Returns:
Measured resistance in ohms.
Raises:
ConnectionError: If not connected.
IOError: If query fails.
NotImplementedError: If instrument does not support resistance.
"""
# Note: Resistance measurement not yet implemented in virtual instrument
raise NotImplementedError(
"Resistance measurement not yet supported by virtual instrument"
)
def set_integration_time(self, nplc: float) -> None:
"""Set the integration time.
Args:
nplc: Integration time in number of power line cycles (NPLC).
Typical values: 0.02, 0.2, 1, 10, 100.
Raises:
ConnectionError: If not connected.
IOError: If command fails.
NotImplementedError: If instrument does not support integration time.
"""
# Note: Integration time not yet implemented in virtual instrument
raise NotImplementedError(
"Integration time setting not yet supported by virtual instrument"
)
def configure_dc_voltage(self) -> None:
"""Configure meter for DC voltage measurement.
Sets the measurement function without taking a measurement.
Use read() to take a measurement after configuring.
Raises:
ConnectionError: If not connected.
IOError: If command fails.
"""
self.write("CONF:VOLT:DC")
def configure_dc_current(self) -> None:
"""Configure meter for DC current measurement.
Sets the measurement function without taking a measurement.
Use read() to take a measurement after configuring.
Raises:
ConnectionError: If not connected.
IOError: If command fails.
"""
self.write("CONF:CURR:DC")
def get_configuration(self) -> str:
"""Get the current measurement configuration.
Returns:
Configuration string (e.g., "VOLT:DC", "CURR:DC").
Raises:
ConnectionError: If not connected.
IOError: If query fails.
"""
return self.query("CONF?").strip('"')
def read(self) -> float:
"""Take a measurement using the current configuration.
Must call configure_dc_voltage() or configure_dc_current() first
to set the measurement function.
Returns:
Measured value (voltage in V or current in A).
Raises:
ConnectionError: If not connected.
IOError: If query fails.
"""
return self.query_float("READ?")

View File

@@ -0,0 +1,152 @@
"""Power supply SCPI driver.
This module implements a client-side driver for programmable power supplies
that communicate via SCPI commands.
"""
from py_dvt_ate.instruments.drivers.base import BaseDriver
class PowerSupplyDriver(BaseDriver):
"""SCPI driver for programmable power supplies.
Provides high-level Python API for controlling power supplies via
SCPI commands. Implements the IPowerSupply interface.
Note: This driver assumes a single-channel instrument. The channel
parameter is accepted for interface compatibility but currently ignored.
SCPI Commands Used:
VOLT <value> - Set output voltage (V)
VOLT? - Query voltage setpoint
CURR <value> - Set current limit (A)
CURR? - Query current limit
OUTP <ON|OFF|1|0> - Enable/disable output
OUTP? - Query output state (1=on, 0=off)
MEAS:VOLT? - Measure actual output voltage
MEAS:CURR? - Measure actual output current
Example:
>>> transport = TCPTransport("localhost", 5002)
>>> psu = PowerSupplyDriver(transport)
>>> psu.connect()
>>> psu.set_voltage(1, 3.3)
>>> psu.set_current_limit(1, 0.5)
>>> psu.enable_output(1, True)
>>> voltage = psu.measure_voltage(1)
"""
def set_voltage(self, channel: int, voltage: float) -> None:
"""Set the output voltage setpoint.
Args:
channel: Channel number (currently ignored, single channel assumed).
voltage: Target voltage in volts.
Raises:
ConnectionError: If not connected.
IOError: If command fails.
"""
self.write(f"VOLT {voltage:.3f}")
def get_voltage(self, channel: int) -> float:
"""Get the voltage setpoint.
Args:
channel: Channel number (currently ignored, single channel assumed).
Returns:
Current voltage setpoint in volts.
Raises:
ConnectionError: If not connected.
IOError: If query fails.
"""
return self.query_float("VOLT?")
def set_current_limit(self, channel: int, current: float) -> None:
"""Set the current limit.
Args:
channel: Channel number (currently ignored, single channel assumed).
current: Current limit in amps.
Raises:
ConnectionError: If not connected.
IOError: If command fails.
"""
self.write(f"CURR {current:.3f}")
def get_current_limit(self, channel: int) -> float:
"""Get the current limit.
Args:
channel: Channel number (currently ignored, single channel assumed).
Returns:
Current limit in amps.
Raises:
ConnectionError: If not connected.
IOError: If query fails.
"""
return self.query_float("CURR?")
def measure_voltage(self, channel: int) -> float:
"""Measure the actual output voltage.
Args:
channel: Channel number (currently ignored, single channel assumed).
Returns:
Measured voltage in volts.
Raises:
ConnectionError: If not connected.
IOError: If query fails.
"""
return self.query_float("MEAS:VOLT?")
def measure_current(self, channel: int) -> float:
"""Measure the actual output current.
Args:
channel: Channel number (currently ignored, single channel assumed).
Returns:
Measured current in amps.
Raises:
ConnectionError: If not connected.
IOError: If query fails.
"""
return self.query_float("MEAS:CURR?")
def enable_output(self, channel: int, enable: bool) -> None:
"""Enable or disable the output.
Args:
channel: Channel number (currently ignored, single channel assumed).
enable: True to enable output, False to disable.
Raises:
ConnectionError: If not connected.
IOError: If command fails.
"""
state = "ON" if enable else "OFF"
self.write(f"OUTP {state}")
def is_output_enabled(self, channel: int) -> bool:
"""Check if output is enabled.
Args:
channel: Channel number (currently ignored, single channel assumed).
Returns:
True if output is enabled, False if disabled.
Raises:
ConnectionError: If not connected.
IOError: If query fails.
"""
return self.query_bool("OUTP?")