Source code for semi_cr.core.lab.station.routing_v1.conversions

# Contains device-side transformations that wrap routed quantities:

from dataclasses import dataclass
from typing import Any, Callable
import math


[docs] class ConvertedVoltageQuantity: """ Device-side voltage quantity backed by an instrument-side voltage source. Convention: V_device = conversion_factor * V_instrument """ def __init__( self, instrument_voltage, conversion_factor: float, ): if conversion_factor == 0: raise ValueError("conversion_factor cannot be zero.") self.instrument_voltage = instrument_voltage self.conversion_factor = float(conversion_factor)
[docs] def set(self, device_voltage: float) -> None: """ Set the desired voltage at the device. The required instrument voltage is calculated automatically. """ instrument_voltage = ( float(device_voltage) / self.conversion_factor ) self.instrument_voltage.set(instrument_voltage)
[docs] def get(self) -> float: """ Return the instrument readback expressed as device-side voltage. """ instrument_voltage = self.instrument_voltage.get() return ( float(instrument_voltage) * self.conversion_factor )
def __call__(self) -> float: return self.get()
[docs] @dataclass class CurrentFromTransimpedanceVoltage: voltage: Any transimpedance_gain: Callable[[], float]
[docs] def measure(self) -> float: voltage = float(self.voltage.measure()) gain = float(self.transimpedance_gain()) if not math.isfinite(gain): raise ValueError( "Transimpedance gain must be finite; " f"received {gain!r}." ) if gain == 0.0: raise ValueError( "Transimpedance gain cannot be zero." ) return voltage / gain
[docs] def attach_converted_voltage_quantity( device, source_pin_name: str = "source", voltage_quantity_name: str = "dc_voltage", conversion_module=None, ) -> None: """ Replace the source's public voltage quantity with a device-side, converted voltage quantity while preserving the original routed instrument voltage. """ if conversion_module is None: return source = getattr(device, source_pin_name) instrument_voltage = getattr(source, voltage_quantity_name) conversion_factor = float(conversion_module.voltage_conversion_factor()) # Expose dc_voltage in device-side units. setattr( source, voltage_quantity_name, ConvertedVoltageQuantity( instrument_voltage=instrument_voltage, conversion_factor=conversion_factor, ), )
[docs] def attach_transimpedance_current_quantity( device, drain_pin_name: str = "drain", voltage_quantity_name: str = "dc_voltage", transimpedance_module= None, ): if transimpedance_module is None: raise ValueError( "A transimpedance module is required." ) drain = getattr(device, drain_pin_name) voltage = getattr(drain, voltage_quantity_name) drain.dc_current = CurrentFromTransimpedanceVoltage( voltage=voltage, transimpedance_gain=transimpedance_module.gain_v_per_a, )