Add PSU and DMM drivers
This commit is contained in:
@@ -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",
|
||||||
|
]
|
||||||
|
|||||||
157
src/py_dvt_ate/instruments/drivers/multimeter.py
Normal file
157
src/py_dvt_ate/instruments/drivers/multimeter.py
Normal 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?")
|
||||||
152
src/py_dvt_ate/instruments/drivers/power_supply.py
Normal file
152
src/py_dvt_ate/instruments/drivers/power_supply.py
Normal 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?")
|
||||||
Reference in New Issue
Block a user