Fix TempCo integration tests with thread-based async server

Redesign integration test architecture to eliminate async/sync deadlock:
- Run SimulationServer in dedicated background thread with own event loop
- Rewrite TempCo tests as fully synchronous (no @pytest.mark.asyncio)
- Add ServerThread fixture in tests/integration/conftest.py
- Fix Unicode encoding errors (replace deg, mu, +/- with ASCII)
- Optimize temperature points for faster settling (23C, 25C, 27C)

All 3 TempCo integration tests now passing in ~5 minutes total.
This commit is contained in:
2025-10-12 17:59:48 +00:00
parent 3fdaba500d
commit 42356efce2
3 changed files with 299 additions and 216 deletions

View File

@@ -3,7 +3,7 @@
This test characterises the output voltage temperature coefficient by
sweeping the chamber temperature and measuring output voltage at each point.
The TempCo is calculated from the linear regression slope and expressed
in parts per million per degree Celsius (ppm/°C).
in parts per million per degree Celsius (ppm/C).
"""
from py_dvt_ate.data.models import TestStatus
@@ -29,12 +29,12 @@ class TempCoTest(BaseDVTTest):
5. Evaluate against specification limits
Configuration:
temperatures: List of temperature points (°C). Default: [-40, -20, 0, 25, 50, 85]
temperatures: List of temperature points (C). Default: [-40, -20, 0, 25, 50, 85]
input_voltage: DUT input voltage (V). Default: 5.0
load_current: DUT load current (A). Default: 0.1
settle_time: Additional settling time at each temp (s). Default: 5.0
num_samples: Number of measurements to average per point. Default: 5
tempco_limit: Maximum allowed TempCo magnitude (ppm/°C). Default: ±50.0
tempco_limit: Maximum allowed TempCo magnitude (ppm/C). Default: +/-50.0
"""
@property
@@ -90,7 +90,7 @@ class TempCoTest(BaseDVTTest):
# Temperature sweep
for temp_setpoint in temperatures:
context.logger.log_event(
f"Temperature point: {temp_setpoint}°C",
f"Temperature point: {temp_setpoint}C",
level="INFO",
)
@@ -102,7 +102,7 @@ class TempCoTest(BaseDVTTest):
)
if not stable:
context.logger.log_event(
f"Warning: Temperature did not stabilise at {temp_setpoint}°C",
f"Warning: Temperature did not stabilise at {temp_setpoint}C",
level="WARNING",
)
@@ -133,8 +133,8 @@ class TempCoTest(BaseDVTTest):
)
context.logger.log_event(
f"Measured Vout = {vout_mean:.6f}V ± {vout_std * 1e6:.1f}μV "
f"at T={actual_temp:.2f}°C",
f"Measured Vout = {vout_mean:.6f}V +/- {vout_std * 1e6:.1f}uV "
f"at T={actual_temp:.2f}C",
level="INFO",
)
@@ -146,7 +146,7 @@ class TempCoTest(BaseDVTTest):
tempco_ppm = self._calculate_tempco(temp_points, vout_points)
context.logger.log_event(
f"Calculated TempCo = {tempco_ppm:.2f} ppm/°C",
f"Calculated TempCo = {tempco_ppm:.2f} ppm/C",
level="INFO",
)
@@ -154,7 +154,7 @@ class TempCoTest(BaseDVTTest):
context.logger.log_result(
parameter="temp_co",
value=tempco_ppm,
unit="ppm/°C",
unit="ppm/C",
lower_limit=-abs(tempco_limit),
upper_limit=abs(tempco_limit),
)
@@ -164,13 +164,13 @@ class TempCoTest(BaseDVTTest):
if passed:
context.logger.log_event(
f"TempCo test PASSED: {tempco_ppm:.2f} ppm/°C within ±{tempco_limit} ppm/°C",
f"TempCo test PASSED: {tempco_ppm:.2f} ppm/C within +/-{tempco_limit} ppm/C",
level="INFO",
)
return TestStatus.PASSED
else:
context.logger.log_event(
f"TempCo test FAILED: {tempco_ppm:.2f} ppm/°C exceeds ±{tempco_limit} ppm/°C",
f"TempCo test FAILED: {tempco_ppm:.2f} ppm/C exceeds +/-{tempco_limit} ppm/C",
level="ERROR",
)
return TestStatus.FAILED
@@ -198,14 +198,14 @@ class TempCoTest(BaseDVTTest):
"""Calculate temperature coefficient from measurements.
Uses linear regression to find the slope (dV/dT), then converts
to ppm/°C relative to the nominal voltage (voltage at median temperature).
to ppm/C relative to the nominal voltage (voltage at median temperature).
Args:
temperatures: Temperature measurements in °C.
temperatures: Temperature measurements in C.
voltages: Output voltage measurements in V.
Returns:
Temperature coefficient in ppm/°C.
Temperature coefficient in ppm/C.
Raises:
ValueError: If insufficient data points.
@@ -230,14 +230,14 @@ class TempCoTest(BaseDVTTest):
if var_t == 0:
raise ValueError("Temperature variance is zero (all temps identical)")
slope = cov / var_t # dV/dT in V/°C
slope = cov / var_t # dV/dT in V/C
# Find nominal voltage (voltage at median temperature)
sorted_pairs = sorted(zip(temperatures, voltages, strict=True))
mid_idx = len(sorted_pairs) // 2
v_nominal = sorted_pairs[mid_idx][1]
# Convert to ppm/°C: (dV/dT) / V_nom * 10^6
# Convert to ppm/C: (dV/dT) / V_nom * 10^6
tempco_ppm = (slope / v_nominal) * 1e6
return tempco_ppm