Source code for nqontrol.general.helpers

import logging as log
from typing import List, Union

import numpy as np

from . import settings


[docs]def setBit(x, offset): mask = 1 << offset return x | mask
[docs]def clearBit(x, offset): mask = ~(1 << offset) return x & mask
[docs]def testBit(x, offset): mask = 1 << offset if x & mask: return 1 return 0
[docs]def changeBit(x, offset, enabled): if enabled: return setBit(x, offset) return clearBit(x, offset)
[docs]def readBit(x, offset): if testBit(x, offset): return True return False
[docs]def convertVolt2Float( value: Union[list, np.number, np.ndarray], mode: int = 0, signed=False ) -> Union[float, np.ndarray]: """Converts a volt scala value (in case of ADwin e.g. volt range from -10 to 10, because the outputs are limited) to a Float value. The supported range is divided onto the whole 16-bit float, so -10 Volt would e.g. correspond with 0, 10 V with 65535 for unsigned or -32768 to 32767 when signed. Parameters ---------- value: :obj:`list`, :obj:`numpy.number`, :obj:`numpy.ndarray` The value(s) to be converted. mode: :obj:`int` Integer from 0 to 3, sensitivity mode. Decides how the bins are divided. See :obj:`nqontrol.servo.inputSensitivity` or `auxSensitivity` for more info. signed: :obj:`bool` Whether the Integer is supposed to have a sign or not, see above. Returns ------- :obj:`list`, :obj:`numpy.number`, :obj:`numpy.ndarray` Converted value. Exact type depends on input type. """ if isinstance(value, list): value = np.array(value) result = 0.1 * value * 0x8000 * pow(2, mode) upper_limit = 0x7FFF lower_limit = -0x8000 if isinstance(result, (float, np.float64, np.float32)): result = min(result, upper_limit) result = max(result, lower_limit) elif isinstance(result, np.ndarray): result[result > upper_limit] = upper_limit result[result < lower_limit] = lower_limit else: raise TypeError("The type {} is not supported.".format(type(value))) if not signed: result += 32768 return result
[docs]def convertVolt2Int( value: Union[list, np.number, np.ndarray], mode: int = 0, signed=False ) -> Union[int, np.ndarray]: """[DEPRECATED] Converts a volt scala value (in case of ADwin e.g. volt range from -10 to 10, because the outputs are limited) to an Integer value. There is an equivalent function for Floats. The supported range is divided onto the whole 16-bit integer, so -10 Volt would e.g. correspond with 0, 10 V with 65535 for unsigned or -32768 to 32767 when signed. Parameters ---------- value: :obj:`list`, :obj:`numpy.number`, :obj:`numpy.ndarray` The value(s) to be converted. mode: :obj:`int` Integer from 0 to 3, sensitivity mode. Decides how the bins are divided. See :obj:`nqontrol.servo.inputSensitivity` or `auxSensitivity` for more info. signed: :obj:`bool` Whether the Integer is supposed to have a sign or not, see above. Returns ------- :obj:`list`, :obj:`numpy.number`, :obj:`numpy.ndarray` Converted value. Exact type depends on input type. """ log.warning( DeprecationWarning( "This method is deprecated, please use `convertVolt2Float` for higher accuracy." ) ) result = convertVolt2Float(value, mode, signed) if isinstance(result, (float, np.float64, np.float32)): return int(round(result, 0)) if isinstance(result, np.ndarray): return result.astype(int) return result
[docs]def convertFloat2Volt( value: Union[List[float], np.array, float], mode: int = 0, signed=False ) -> Union[float, np.ndarray]: """Convert float to volt. For details see :obj:`convertVolt2Float`. Parameters ---------- value : Union[List[float], np.array, float] value is a 16 bit number mode : int mode is the input amplification mode signed : Returns ------- returnVar : Union[float, np.ndarray] """ if isinstance(value, list): value = np.array(value) if signed: value += 32768 return 10.0 * (value / 0x8000 - 1) / pow(2, mode)
[docs]def rearrange_filter_coeffs(inputFilter: List[float]) -> List[float]: """Rearrage coefficients from `a, b` to `c`.""" b = inputFilter[0:3] a = inputFilter[3:6] return [b[0], a[1], a[2], b[1] / b[0], b[2] / b[0]]
[docs]def convertStepsize2Frequency(stepsize: float) -> float: """Convert stepsize to frequency for the autolock ramp. The stepsize is a float and has the following relation to the ramp. Internally, ADwin uses a normalized ramp from -1 to 1 Volts, which is then multiplied by an amplitude and added to some offset value. Thus, we get a fixed ratio of frequency to stepsize, given by f = s * 200kHz / 4 where the 200kHz is the ADwin sampling rate. The 4 derives from the fact, that the total steps needed for a given stepsize of one ramp cycle is 4 / s, when 1 is the amplitude, since we want to go from minimum to maximum and back. It makes sense to introduce some minimum frequency, e.g. {0} Hz, which correlates with a minimum stepsize of 2e-05. For UI purposes it also makes sense to have a reasonable maximum frequency, which can be found in `settings.py` under RAMP_FREQUENCY_MAX (currently {1}). As these are supposed to be general conversion methods, we do not enforce the given boundaries here, but on the `servo.py` level. Parameters ---------- stepsize : float stepsize of the ramp Returns ------- returnVar : float frequency in Hz """.format( settings.RAMP_FREQUENCY_MIN, settings.RAMP_FREQUENCY_MAX ) if ( not convertFrequency2Stepsize(settings.RAMP_FREQUENCY_MIN) <= stepsize <= convertFrequency2Stepsize(settings.RAMP_FREQUENCY_MAX) ): log.warning( f"We recommend using stepsizes between {convertFrequency2Stepsize(settings.RAMP_FREQUENCY_MIN)} Hz and {convertFrequency2Stepsize(settings.RAMP_FREQUENCY_MAX)} Hz. Input was {stepsize}." ) return stepsize * settings.SAMPLING_RATE / 4
[docs]def convertFrequency2Stepsize(frequency: float) -> float: """Convert frequency to stepsize for the autolock ramp. The stepsize is a float and has the following relation to the ramp. Internally, ADwin uses a normalized ramp from -1 to 1 Volts, which is then multiplied by an amplitude and added to some offset value. Thus, we get a fixed ratio of frequency to stepsize, given by f = s * 200kHz / 4 where the 200kHz is the ADwin sampling rate. The 4 derives from the fact, that the total steps needed for a given stepsize of one ramp cycle is 4 / s, when 1 is the amplitude, since we want to go from minimum to maximum and back. It makes sense to introduce some minimum frequency, e.g. {0} Hz, which correlates with a minimum stepsize of 2e-05. For UI purposes it also makes sense to have a reasonable maximum frequency, which can be found in `settings.py` under RAMP_FREQUENCY_MAX (currently {1}). As these are supposed to be general conversion methods, we do not enforce the given boundaries here, but on the `servo.py` level. Parameters ---------- frequency : float frequency in Hz Returns ------- returnVar : float stepsize """.format( settings.RAMP_FREQUENCY_MIN, settings.RAMP_FREQUENCY_MAX ) if not settings.RAMP_FREQUENCY_MIN <= frequency <= settings.RAMP_FREQUENCY_MAX: log.warning( f"We recommend using frequencies between {settings.RAMP_FREQUENCY_MIN} Hz and {settings.RAMP_FREQUENCY_MAX} Hz. Input was {frequency}." ) stepsize = frequency * 4 / settings.SAMPLING_RATE return stepsize