143 lines
4.3 KiB
Python
143 lines
4.3 KiB
Python
"""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
|
|
from py_dvt_ate.instruments.interfaces import IThermalChamber
|
|
|
|
|
|
class ThermalChamberDriver(BaseDriver, IThermalChamber):
|
|
"""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?")
|