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.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