''' The energy table for VEX/ELS.
The simplest way of getting energy table is using :func:`get_table_128` and :func:`get_table_32`.
They return a numpy array with element of (*nstep*, 16), where *nstep* is the number of energy step
(128 and 32 respectively).
>>> etbl128 = get_table_128()
>>> print(etbl128.shape)
(128, 16)
>>> etbl32 = get_table_32()
>>> print(etbl32.shape)
(32, 16)
'''
import numpy as np
from . import kfactor
[docs]def tm2ref_l(tm):
''' Function converting TM raw value to reference voltage (low).
See equation (3) in :ref:`vexelsbible`.
'''
return tm * (21.8 / 4095.)
[docs]def tm2ref_h(tm):
''' Function converting TM raw value to reference voltage (low).
See equation (3) in :ref:`vexelsbible`.
'''
return tm * (2777. / 4095.)
[docs]def tm2ref(tm):
''' Convert TM raw value to reference voltage.
To accompany both low and high power supply, a trick is used:
For negative tm, low power supply is used and
for positive tm, high power supply is used.
Thus, simple logic is used like::
if tm < 0:
return tm2ref_low(-tm)
else:
return tm2ref_high(tm)
See also :func:`tm2ref_l` and :func:`tm2ref_h`.
>>> tm2ref(-100) == tm2ref_l(100)
True
>>> tm2ref(100) == tm2ref_h(100)
True
'''
if tm < 0:
return tm2ref_l(-tm)
else:
return tm2ref_h(tm)
[docs]class EnergyTable:
''' Base class of energy table.
This class is an implementation of section 7 of :ref:`vexelsbible`.
.. note::
There is a little bit difference in the table and the calculated value.
However the difference is very small, so I do not think it matters our science.
This class is considered as a base class for each implemented ELS energy table.
To make the child class, following method should be implemented.
* self.tmidx(self)
* self.nstep(self)
'''
def __init__(self):
self.kfact = kfactor.kfactors() # 16 element array
self.n = self.nstep()
self.tm = self.tmidx() # self.n tm array
self.hv = np.array([tm2ref(tm) for tm in self.tm])
[docs] def energy(self, estep, anode, fill_flyback=np.nan):
''' Return the energy for the specified energy step and anode.
'''
e = self.kfact[anode] * self.hv[estep]
if e == 0:
e = fill_flyback
return e
[docs] def energy_table(self, fill_flyback=np.nan):
''' Return the energy table.
:keyword fill_flyback: Value to fill the flyback energy step.
:returns: The energy table.
:rtype: ``np.array`` with ``nstep`` x16 elements.
'''
etbl = np.zeros([self.n, 16])
for ie in range(self.n):
for id in range(16):
etbl[ie, id] = self.energy(ie, id, fill_flyback=fill_flyback)
return etbl
[docs] def nstep(self):
''' Return the number of the energy step.
'''
raise NotImplementedError("The function nstep() should be overrided.")
[docs] def tmidx(self):
''' Return a ``nstep`` element nparray of TM value.
Negative for low power suppy is employed to use :func:`tm2ref`.
'''
raise NotImplementedError("The function tmidx() should be overrided.")
[docs]class EnergyTable128(EnergyTable):
''' Energy table class for 128 energy step mode.
This class is an implementation of section 7 of :ref:`vexelsbible`.
Flyback energy step looks step-0.
.. todo::
Check the flyback energy step.
A simple usage is
>>> tbl = EnergyTable128()
>>> print("%.3f" % tbl.energy(15, 5))
3.158
>>> print("%.3f" % tbl.energy(100, 10))
3299.235
>>> print(tbl.energy(0, 5))
nan
'''
def __init__(self):
EnergyTable.__init__(self)
[docs] def nstep(self):
''' Return the number of the energy step.
'''
return 128
[docs] def tmidx(self):
''' Return a 128 element nparray of TM value.
Negative for low power suppy is employed to use :func:`tm2ref`.
'''
return np.array([0, -16, -18, -19, -21, -23, -25, -27, -29, -32, -35, -38, -41, -45, -49, -53,
-57, -62, -68, -74, -80, -87, -95, -103, -112, -121, -132, -143, -155, -169, -183, -199,
-216, -235, -255, -277, -301, -327, -355, -385, -419, -455, -494, -536, -582, -632,
-687, -746, -810, -880, -955, -1037, -1127, -1223, -1329, -1443, -1567, -1702, -1848,
-2007, -2179, -2366, -2570, -2791, -3031, -3291, -3574, -3881, 31, 34, 37, 40,
43, 47, 51, 56, 61, 66, 72, 78, 84, 92, 100, 108, 118, 128, 139, 151,
164, 178, 193, 210, 228, 248, 269, 292, 317, 345, 374, 407, 442, 480,
521, 566, 614, 667, 724, 787, 854, 928, 1008, 1094, 1188, 1291, 1402,
1522, 1653, 1795, 1949, 2117, 2299, 2496, 2711, 2944, 3197, 3472, 3770,
4095])
[docs]class EnergyTable32(EnergyTable):
''' Energy table class for 32 energy step mode.
See :class:`EnergyTable128` for details.
>>> tbl = EnergyTable32()
>>> print(tbl.energy_table().shape)
(32, 16)
>>> print('%.2f' % tbl.energy(0, 5))
nan
>>> print('%.2f' % tbl.energy(10, 15))
22.40
'''
def __init__(self):
EnergyTable.__init__(self)
[docs] def nstep(self):
return 32
[docs] def tmidx(self):
''' Return a TM reference values for 32 step mode
'''
return -np.array([0, 151, 168, 188, 209, 234, 261, 291, 325, 363, 406, 453, 505, 564,
630, 703, 785, 877, 979, 1092, 1220, 1362, 1520, 1697, 1895, 2115, 2361,
2636, 2943, 3286, 3668, 4095])
[docs]def get_table_128(fill_flyback=np.nan):
''' Get the energy table for 128 energy step mode.
:keyword fill_flyback: Value to fill the flyback energy step.
>>> tbl = get_table_128()
>>> print(tbl.shape)
(128, 16)
>>> print('%.3f' % tbl[66, 6]) # Return the energy of anode 6, energy step 66.
215.189
'''
return EnergyTable128().energy_table(fill_flyback=fill_flyback)
[docs]def get_table_32(fill_flyback=np.nan):
''' Get the energy table for 128 energy step mode.
:keyword fill_flyback: Value to fill the flyback energy step.
>>> tbl = get_table_32()
>>> print(tbl.shape)
(32, 16)
>>> print('%.3f' % tbl[26, 7]) # Return the energy of anode 6, energy step 66.
143.248
'''
return EnergyTable32().energy_table(fill_flyback=fill_flyback)
import unittest,doctest
[docs]def doctests():
return unittest.TestSuite((
doctest.DocTestSuite(),
))
if __name__=='__main__':
unittest.main(defaultTest='doctests')