Add thermal chamber driver
This commit is contained in:
@@ -5,5 +5,6 @@ and handles responses from instruments.
|
||||
"""
|
||||
|
||||
from py_dvt_ate.instruments.drivers.base import BaseDriver
|
||||
from py_dvt_ate.instruments.drivers.chamber import ThermalChamberDriver
|
||||
|
||||
__all__ = ["BaseDriver"]
|
||||
__all__ = ["BaseDriver", "ThermalChamberDriver"]
|
||||
|
||||
141
src/py_dvt_ate/instruments/drivers/chamber.py
Normal file
141
src/py_dvt_ate/instruments/drivers/chamber.py
Normal file
@@ -0,0 +1,141 @@
|
||||
"""Thermal chamber SCPI driver.
|
||||
|
||||
This module implements a client-side driver for thermal chambers that
|
||||
communicate via SCPI commands.
|
||||
"""
|
||||
|
||||
import time
|
||||
|
||||
from py_dvt_ate.instruments.drivers.base import BaseDriver
|
||||
|
||||
|
||||
class ThermalChamberDriver(BaseDriver):
|
||||
"""SCPI driver for thermal chambers.
|
||||
|
||||
Provides high-level Python API for controlling thermal chambers via
|
||||
SCPI commands. Implements the IThermalChamber interface.
|
||||
|
||||
SCPI Commands Used:
|
||||
TEMP:SETPOINT <value> - Set target temperature (°C)
|
||||
TEMP:SETPOINT? - Query current setpoint
|
||||
TEMP:ACTUAL? - Query actual chamber temperature
|
||||
TEMP:STAB? - Query stability (1=stable, 0=settling)
|
||||
TEMP:RAMP <rate> - Set temperature ramp rate (°C/min)
|
||||
TEMP:RAMP? - Query ramp rate
|
||||
|
||||
Example:
|
||||
>>> transport = TCPTransport("localhost", 5001)
|
||||
>>> chamber = ThermalChamberDriver(transport)
|
||||
>>> chamber.connect()
|
||||
>>> chamber.set_temperature(85.0)
|
||||
>>> chamber.wait_until_stable(timeout=600.0)
|
||||
>>> temp = chamber.get_temperature()
|
||||
"""
|
||||
|
||||
def set_temperature(self, setpoint: float) -> None:
|
||||
"""Set the chamber temperature setpoint.
|
||||
|
||||
Args:
|
||||
setpoint: Target temperature in degrees Celsius.
|
||||
|
||||
Raises:
|
||||
ConnectionError: If not connected.
|
||||
IOError: If command fails.
|
||||
"""
|
||||
self.write(f"TEMP:SETPOINT {setpoint:.2f}")
|
||||
|
||||
def get_temperature(self) -> float:
|
||||
"""Get the actual chamber temperature.
|
||||
|
||||
Returns:
|
||||
Current chamber temperature in degrees Celsius.
|
||||
|
||||
Raises:
|
||||
ConnectionError: If not connected.
|
||||
IOError: If query fails.
|
||||
"""
|
||||
return self.query_float("TEMP:ACTUAL?")
|
||||
|
||||
def get_setpoint(self) -> float:
|
||||
"""Get the current temperature setpoint.
|
||||
|
||||
Returns:
|
||||
Current setpoint in degrees Celsius.
|
||||
|
||||
Raises:
|
||||
ConnectionError: If not connected.
|
||||
IOError: If query fails.
|
||||
"""
|
||||
return self.query_float("TEMP:SETPOINT?")
|
||||
|
||||
def is_stable(self) -> bool:
|
||||
"""Check if chamber temperature is stable.
|
||||
|
||||
Temperature is considered stable when it has settled within
|
||||
the instrument's configured stability threshold of the setpoint.
|
||||
|
||||
Returns:
|
||||
True if temperature is stable, False if still settling.
|
||||
|
||||
Raises:
|
||||
ConnectionError: If not connected.
|
||||
IOError: If query fails.
|
||||
"""
|
||||
return self.query_bool("TEMP:STAB?")
|
||||
|
||||
def wait_until_stable(
|
||||
self, timeout: float = 300.0, poll_interval: float = 1.0
|
||||
) -> bool:
|
||||
"""Wait until chamber temperature stabilises.
|
||||
|
||||
Polls the stability status at regular intervals until stable
|
||||
or timeout is reached.
|
||||
|
||||
Args:
|
||||
timeout: Maximum time to wait in seconds. Default 300s (5 minutes).
|
||||
poll_interval: Time between stability checks in seconds. Default 1s.
|
||||
|
||||
Returns:
|
||||
True if temperature stabilised within timeout, False if timed out.
|
||||
|
||||
Raises:
|
||||
ConnectionError: If not connected.
|
||||
IOError: If communication fails.
|
||||
ValueError: If timeout or poll_interval are negative.
|
||||
"""
|
||||
if timeout < 0:
|
||||
raise ValueError("Timeout must be non-negative")
|
||||
if poll_interval <= 0:
|
||||
raise ValueError("Poll interval must be positive")
|
||||
|
||||
start_time = time.time()
|
||||
while time.time() - start_time < timeout:
|
||||
if self.is_stable():
|
||||
return True
|
||||
time.sleep(poll_interval)
|
||||
|
||||
return False
|
||||
|
||||
def set_ramp_rate(self, rate: float) -> None:
|
||||
"""Set the temperature ramp rate.
|
||||
|
||||
Args:
|
||||
rate: Ramp rate in degrees Celsius per minute.
|
||||
|
||||
Raises:
|
||||
ConnectionError: If not connected.
|
||||
IOError: If command fails.
|
||||
"""
|
||||
self.write(f"TEMP:RAMP {rate:.2f}")
|
||||
|
||||
def get_ramp_rate(self) -> float:
|
||||
"""Get the current temperature ramp rate.
|
||||
|
||||
Returns:
|
||||
Ramp rate in degrees Celsius per minute.
|
||||
|
||||
Raises:
|
||||
ConnectionError: If not connected.
|
||||
IOError: If query fails.
|
||||
"""
|
||||
return self.query_float("TEMP:RAMP?")
|
||||
Reference in New Issue
Block a user