57 lines
1.9 KiB
Python
57 lines
1.9 KiB
Python
"""Physical unit conversions for the laser control module.
|
|
|
|
Converts between physical quantities (°C, mA, V) and the raw ADC/DAC integer
|
|
values used by the device firmware, using the hardware's bridge/divider formulas.
|
|
"""
|
|
|
|
import math
|
|
from .constants import ADC_BITS_16, BETA_INTERNAL, R0, R1, R3, R4, R5, R6, RREF, T0_K, VREF
|
|
|
|
|
|
def temp_c_to_n(temp_c: float) -> int:
|
|
"""
|
|
Convert temperature (°C) to 16-bit DAC integer (Wheatstone bridge setpoint).
|
|
|
|
Args:
|
|
temp_c: Temperature in degrees Celsius.
|
|
|
|
Returns:
|
|
Integer in [0, 65535] for the DAC.
|
|
"""
|
|
rt = R0 * math.exp(BETA_INTERNAL / (temp_c + 273) - BETA_INTERNAL / T0_K)
|
|
u = VREF / (R5 * (R3 + R4)) * (
|
|
R1 * R4 * (R5 + R6) - rt * (R3 * R6 - R4 * R5)
|
|
) / (rt + R1)
|
|
n = int(u * ADC_BITS_16 / VREF)
|
|
n = max(0, min(ADC_BITS_16, n))
|
|
return n
|
|
|
|
|
|
|
|
|
|
def current_ma_to_n(current_ma: float) -> int:
|
|
"""
|
|
Convert laser drive current (mA) to 16-bit DAC integer.
|
|
|
|
Args:
|
|
current_ma: Current in milliamps.
|
|
|
|
Returns:
|
|
Integer in [0, 65535] for the DAC.
|
|
"""
|
|
# Rounded like the lab GUI (_device_main.py), so both send identical DAC codes.
|
|
return max(0, min(ADC_BITS_16, round(ADC_BITS_16 / 2000 * RREF * current_ma)))
|
|
|
|
|
|
def variation_codes(min_value: float, max_value: float, step: float) -> tuple[int, int, int]:
|
|
low, high, delta = (current_ma_to_n(value) for value in (min_value, max_value, step))
|
|
if delta == 0 or low >= high:
|
|
raise ValueError("Current variation range and step must be representable by the DAC")
|
|
return low, high, delta
|
|
|
|
|
|
def variation_step_count(min_value: float, max_value: float, step: float) -> int:
|
|
"""SWEEP_STEP edges per sweep: firmware loops ``while (current < max) current += delta`` on these codes."""
|
|
low, high, delta = variation_codes(min_value, max_value, step)
|
|
return math.ceil((high - low) / delta)
|