22Photodiode storage class.
25__all__ = [
"PhotodiodeCalib"]
28from astropy.table
import Table
34 """Independent current measurements from photodiode for linearity
39 timeSamples : `list` or `numpy.ndarray`
40 List of samples the photodiode was measured at.
41 currentSamples : `list`
or `numpy.ndarray`
42 List of current measurements at each time sample.
44 Log to write messages to.
46 Additional parameters. These will be passed to the parent
47 constructor
with the exception of:
49 ``
"integrationMethod"``
50 Name of the algorithm to use to integrate the current
51 samples. Allowed values are ``DIRECT_SUM``,
52 ``TRIMMED_SUM``,
and ``CHARGE_SUM`` (`str`).
54 Scale factor to apply to the current samples
for the
55 ``CHARGE_SUM`` integration method. A typical value
56 would be `-1`, to flip the sign of the integrated charge.
59 _OBSTYPE = 'PHOTODIODE'
60 _SCHEMA =
'Photodiode'
63 def __init__(self, timeSamples=None, currentSamples=None, **kwargs):
64 if timeSamples
is not None and currentSamples
is not None:
65 if len(timeSamples) != len(currentSamples):
66 raise RuntimeError(f
"Inconsitent vector lengths: {len(timeSamples)} vs {len(currentSamples)}")
76 if 'integrationMethod' in kwargs:
81 if 'currentScale' in kwargs:
86 if 'day_obs' in kwargs:
88 if 'seq_num' in kwargs:
95 """Construct a PhotodiodeCalib from a dictionary of properties.
100 Dictionary of properties.
105 Constructed photodiode data.
110 Raised if the supplied dictionary
is for a different
115 if calib._OBSTYPE != dictionary[
'metadata'][
'OBSTYPE']:
116 raise RuntimeError(f
"Incorrect photodiode supplied. Expected {calib._OBSTYPE}, "
117 f
"found {dictionary['metadata']['OBSTYPE']}")
119 calib.setMetadata(dictionary[
'metadata'])
121 calib.timeSamples = np.array(dictionary[
'timeSamples']).ravel()
122 calib.currentSamples = np.array(dictionary[
'currentSamples']).ravel()
123 calib.integrationMethod = dictionary.get(
'integrationMethod',
"DIRECT_SUM")
125 calib.updateMetadata()
129 """Return a dictionary containing the photodiode properties.
131 The dictionary should be able to be round-tripped through.
137 Dictionary of properties.
153 """Construct calibration from a list of tables.
155 This method uses the `fromDict` method to create the
156 calibration after constructing an appropriate dictionary from
161 tableList : `list` [`astropy.table.Table`]
162 List of tables to use to construct the crosstalk
168 The calibration defined
in the tables.
170 dataTable = tableList[0]
172 metadata = dataTable.meta
174 inDict['metadata'] = metadata
175 inDict[
'integrationMethod'] = metadata.pop(
'INTEGRATION_METHOD',
'DIRECT_SUM')
177 inDict[
'timeSamples'] = dataTable[
'TIME']
178 inDict[
'currentSamples'] = dataTable[
'CURRENT']
183 """Construct a list of tables containing the information in this
186 The list of tables should create an identical calibration
187 after being passed to this class's fromTable method.
191 tableList : `list` [`astropy.table.Table`]
192 List of tables containing the photodiode calibration
199 outMeta = {k: v
for k, v
in inMeta.items()
if v
is not None}
200 outMeta.update({k:
"" for k, v
in inMeta.items()
if v
is None})
202 catalog.meta = outMeta
208 """Construct a PhotodiodeCalib by reading the simple column format.
213 File to read samples from.
218 The calibration defined
in the file.
222 rawData = np.loadtxt(filename, dtype=[(
'time',
'float'), (
'current',
'float')])
224 basename = os.path.basename(filename)
225 cleaned = os.path.splitext(basename)[0]
226 _, _, day_obs, seq_num = cleaned.split(
"_")
228 return cls(timeSamples=rawData[
'time'], currentSamples=rawData[
'current'],
229 day_obs=int(day_obs), seq_num=int(seq_num))
232 """Integrate the current.
237 Raised if the integration method
is not known.
246 raise RuntimeError(f
"Unknown integration method {self.integrationMethod}")
251 This uses numpy's trapezoidal integrator.
256 Total charge measured.
261 """Integrate points with a baseline level subtracted.
263 This uses numpy's trapezoidal integrator.
268 Total charge measured.
272 lsst.eotask.gen3.eoPtc
276 lowValueIndices = np.where(self.currentSamples < currentThreshold)
281 """For this method, the values in .currentSamples are actually the
282 integrated charge values as measured by the ammeter
for each
283 sampling interval. We need to do a baseline subtraction,
284 based on the charge values when the LED
is off, then sum up
285 the corrected signals.
290 Total charge measured.
306 dy = np.max(current) - np.min(current)
307 signal, = np.where(current > dy/20. + np.min(current))
309 imax = signal[-1] + 2
310 bg = np.concatenate([np.arange(0, imin), np.arange(imax, len(current))])
311 bg_current = np.sum(charge[bg])/np.sum(dt[bg])
313 return np.sum(charge - bg_current*dt)
def requiredAttributes(self, value)
def updateMetadata(self, camera=None, detector=None, filterName=None, setCalibId=False, setCalibInfo=False, setDate=False, **kwargs)
def requiredAttributes(self)
def fromTable(cls, tableList)
def integrateTrimmedSum(self)
def integrateChargeSum(self)
def fromDict(cls, dictionary)
def __init__(self, timeSamples=None, currentSamples=None, **kwargs)
def integrateDirectSum(self)
def readTwoColumnPhotodiodeData(cls, filename)