Source code for edges.cal.thermistor

"""Functions for working with data from a thermistor."""

from collections.abc import Sequence
from typing import Self

import attrs
import numpy as np
from astropy import units as un
from astropy.table import QTable
from astropy.time import Time, TimeDelta

from .. import types as tp
from ..io.serialization import hickleable
from ..io.thermistor import read_thermistor_csv

IgnoreTimesType = int | un.Quantity[un.percent] | un.Quantity[un.s]


[docs] def ignore_ntimes(times: Time, ignore_times: IgnoreTimesType) -> int: """Number of time integrations to ignore from the start of the observation.""" if isinstance(ignore_times, int): n = ignore_times elif ignore_times.unit.is_equivalent(un.second): time_since_start = (times - times[0]).to("second") n = np.where(time_since_start > ignore_times)[0][0] elif ignore_times.unit.is_equivalent(un.percent): n = int(len(times) * ignore_times.to(un.dimensionless_unscaled)) else: raise TypeError("ignore_times is not a valid type!") return n
[docs] def get_temperature_thermistor( resistance: tp.OhmType, coeffs: str | Sequence[float] = "oven_industries_TR136_170", ) -> tp.TemperatureType: """ Convert resistance of a thermistor to temperature. Uses a pre-defined set of standard coefficients. Parameters ---------- resistance coeffs : str or len-3 iterable of floats, optional If str, should be an identifier of a standard set of coefficients, otherwise, should specify the coefficients. Returns ------- temperature The temperature for each `resistance` given. """ if isinstance(coeffs, str): # Steinhart-Hart coefficients coeffs = { "oven_industries_TR136_170": [1.03514e-3, 2.33825e-4, 7.92467e-8], "omega_ON_930_44006": [ 0.001296751267466723, 0.00019737361897609893, 3.0403175473012516e-7, ], }[coeffs] assert len(coeffs) == 3 # TK in Kelvin return ( 1 * un.K / ( coeffs[0] + coeffs[1] * np.log(resistance.to_value("ohm")) + coeffs[2] * (np.log(resistance.to_value("ohm"))) ** 3 ) )
[docs] def voltage_to_resistance( voltage: tp.VoltageType, load_resistance: tp.OhmType, ) -> tp.OhmType: """ Convert thermistor voltage reading to resistance. Parameters ---------- voltage The voltage reading from the thermistor circuit. load_resistance The resistance of the load resistor in series with the thermistor. Returns ------- resistance The resistance of the thermistor. """ return load_resistance * voltage / (5 * un.V - voltage)
[docs] @hickleable @attrs.define class ThermistorReadings: """ Object containing thermistor readings. Parameters ---------- data The data array containing the readings. """ data: QTable = attrs.field() @data.validator def _data_vld(self, att, val): if "times" not in val.colnames: raise ValueError("'times' must be in the data for ThermistorReadings") if "load_resistance" not in val.colnames: raise ValueError("'load_resistance' must be in data for THermistorReadings")
[docs] def ignore_times(self, ignore_times: IgnoreTimesType): """Number of time integrations to ignore from the start of the observation.""" n = ignore_ntimes(self.data["times"], ignore_times=ignore_times) return attrs.evolve(self, data=self.data[n:])
[docs] @classmethod def from_csv( cls, path: tp.PathLike, ignore_times: IgnoreTimesType = 0, ) -> Self: """Generate the object from an io.Resistance object.""" return ThermistorReadings(data=read_thermistor_csv(path)).ignore_times( ignore_times )
[docs] def get_physical_temperature(self) -> tp.TemperatureType: """The associated thermistor temperature in K.""" return get_temperature_thermistor(self.data["load_resistance"])
[docs] def get_thermistor_indices(self, timestamps: Time) -> list[int | None]: """Get the index of the closest therm measurement for each spectrum.""" closest = [] indx = 0 thermistor_timestamps = self.data["times"] deltat = thermistor_timestamps[1] - thermistor_timestamps[0] for d in timestamps: if indx >= len(thermistor_timestamps): closest.append(np.nan) continue for i, td in enumerate(thermistor_timestamps[indx:], start=indx): if d - td >= TimeDelta(0 * un.s): if d - td <= deltat: closest.append(i) break indx += 1 else: closest.append(np.nan) return closest