From a12d41956940ff113205a8ad698e822a628e72d4 Mon Sep 17 00:00:00 2001 From: awatlet <arnaud.watlet@umons.ac.be> Date: Sun, 15 Oct 2023 21:10:59 +0200 Subject: [PATCH] Adds pwr_state in pwr module and refactors turn_on turn_off --- .../abstract_hardware_components.py | 44 +++++++++++++------ ohmpi/hardware_components/mb_2023_0_X.py | 12 ++--- ohmpi/hardware_components/pwr_batt.py | 14 +++--- ohmpi/hardware_components/pwr_dps5005.py | 40 +++++++++++++---- ohmpi/hardware_system.py | 29 ++++++++++-- ohmpi/ohmpi.py | 3 +- 6 files changed, 102 insertions(+), 40 deletions(-) diff --git a/ohmpi/hardware_components/abstract_hardware_components.py b/ohmpi/hardware_components/abstract_hardware_components.py index a3644e47..eb854748 100644 --- a/ohmpi/hardware_components/abstract_hardware_components.py +++ b/ohmpi/hardware_components/abstract_hardware_components.py @@ -50,7 +50,7 @@ class PwrAbstract(ABC): self._voltage = np.nan self.current_adjustable = kwargs.pop('current_adjustable', False) self._current = np.nan - self._state = 'off' + self._pwr_state = 'off' self._current_min = kwargs.pop('current_min', 0.) self._current_max = kwargs.pop('current_max', 0.) self._voltage_min = kwargs.pop('voltage_min', 0.) @@ -69,16 +69,30 @@ class PwrAbstract(ABC): def current(self, value, **kwargs): # add actions to set the DPS current pass + # + # @abstractmethod + # def turn_off(self): + # self.exec_logger.debug(f'Switching {self.model} off') + # self._state = 'off' + # + # @abstractmethod + # def turn_on(self): + # self.exec_logger.debug(f'Switching {self.model} on') + # self._state = 'on' - @abstractmethod - def turn_off(self): - self.exec_logger.debug(f'Switching {self.model} off') - self._state = 'off' + @property + def pwr_state(self): + return self._pwr_state + + @pwr_state.setter + def pwr_state(self, state): + if state == 'on': + self._pwr_state = 'on' + self.exec_logger.debug(f'{self.model} cannot be switched on') + elif state == 'off': + self._pwr_state = 'off' + self.exec_logger.debug(f'{self.model} cannot be switched off') - @abstractmethod - def turn_on(self): - self.exec_logger.debug(f'Switching {self.model} on') - self._state = 'on' @property @abstractmethod @@ -292,7 +306,7 @@ class TxAbstract(ABC): pass @abstractmethod - def current_pulse(self, **kwargs): + def current_pulse(self, **kurwargs): pass @abstractmethod @@ -313,16 +327,16 @@ class TxAbstract(ABC): injection_duration = self._injection_duration if np.abs(polarity) > 0: if switch_pwr: - self.pwr.turn_on() + self.pwr.pwr_state('on') self.tx_sync.set() time.sleep(injection_duration) self.tx_sync.clear() if switch_pwr: - self.pwr.turn_off() + self.pwr.pwr_state('off') else: self.tx_sync.set() if switch_pwr: - self.pwr.turn_off() + self.pwr.pwr_state('off') time.sleep(injection_duration) self.tx_sync.clear() @@ -382,11 +396,13 @@ class TxAbstract(ABC): @pwr_state.setter def pwr_state(self, state): - self.exec_logger.debug(f'Power source cannot be switched on or off on {self.model}') + if state == 'on': self._pwr_state = 'on' + self.exec_logger.debug(f'{self.model} cannot switch on power source') elif state == 'off': self._pwr_state = 'off' + self.exec_logger.debug(f'{self.model} cannot switch off power source') class RxAbstract(ABC): def __init__(self, **kwargs): diff --git a/ohmpi/hardware_components/mb_2023_0_X.py b/ohmpi/hardware_components/mb_2023_0_X.py index 43446c31..dd193360 100644 --- a/ohmpi/hardware_components/mb_2023_0_X.py +++ b/ohmpi/hardware_components/mb_2023_0_X.py @@ -173,12 +173,12 @@ class Tx(TxAbstract): self.pin0.value = False self.pin1.value = False time.sleep(self._release_delay) - - def turn_off(self): - self.pwr.turn_off(self) - - def turn_on(self): - self.pwr.turn_on(self) + # + # def turn_off(self): + # self.pwr.turn_off(self) + # + # def turn_on(self): + # self.pwr.turn_on(self) @property def tx_bat(self): diff --git a/ohmpi/hardware_components/pwr_batt.py b/ohmpi/hardware_components/pwr_batt.py index c392c38a..650b5dcd 100644 --- a/ohmpi/hardware_components/pwr_batt.py +++ b/ohmpi/hardware_components/pwr_batt.py @@ -25,7 +25,7 @@ class Pwr(PwrAbstract): self.exec_logger.event(f'{self.model}\tpwr_init\tbegin\t{datetime.datetime.utcnow()}') self._voltage = kwargs['voltage'] self._current = np.nan - self._state = 'on' + # self._state = 'on' if not subclass_init: self.exec_logger.event(f'{self.model}\tpwr_init\tend\t{datetime.datetime.utcnow()}') @@ -36,12 +36,12 @@ class Pwr(PwrAbstract): @current.setter def current(self, value, **kwargs): self.exec_logger.debug(f'Current cannot be set on {self.model}') - - def turn_off(self): - self.exec_logger.debug(f'{self.model} cannot be turned off') - - def turn_on(self): - self.exec_logger.debug(f'{self.model} is always on') + # + # def turn_off(self): + # self.exec_logger.debug(f'{self.model} cannot be turned off') + # + # def turn_on(self): + # self.exec_logger.debug(f'{self.model} is always on') @property def voltage(self): diff --git a/ohmpi/hardware_components/pwr_dps5005.py b/ohmpi/hardware_components/pwr_dps5005.py index 140924bd..c6e3a600 100644 --- a/ohmpi/hardware_components/pwr_dps5005.py +++ b/ohmpi/hardware_components/pwr_dps5005.py @@ -40,6 +40,7 @@ class Pwr(PwrAbstract): self.voltage_adjustable = True self.current_adjustable = False self._current = np.nan + self._pwr_state = 'off' if not subclass_init: self.exec_logger.event(f'{self.model}\tpwr_init\tend\t{datetime.datetime.utcnow()}') @@ -51,14 +52,14 @@ class Pwr(PwrAbstract): def current(self, value, **kwargs): self.exec_logger.debug(f'Current cannot be set on {self.model}') - def turn_off(self): - self.connection.write_register(0x09, 0) - self.exec_logger.debug(f'{self.model} is off') - - def turn_on(self): - self.connection.write_register(0x09, 1) - self.exec_logger.debug(f'{self.model} is on') - time.sleep(.3) + # def turn_off(self): + # self.connection.write_register(0x09, 0) + # self.exec_logger.debug(f'{self.model} is off') + # + # def turn_on(self): + # self.connection.write_register(0x09, 1) + # self.exec_logger.debug(f'{self.model} is on') + # time.sleep(.3) @property def voltage(self): @@ -76,3 +77,26 @@ class Pwr(PwrAbstract): def current_max(self, value): self.connection.write_register(0x0001, value * 10, 0) + + def pwr_state(self): + return self._pwr_state + + @pwr_state.setter + def pwr_state(self, state, latency=.3): + """Switches pwr on or off. + + Parameters + ---------- + state : str + 'on', 'off' + """ + if state == 'on': + self.connection.write_register(0x09, 1) + self._pwr_state = 'on' + self.exec_logger.debug(f'{self.model} is on') + time.sleep(latency) # from pwr specs + + elif state == 'off': + self.connection.write_register(0x09, 0) + self._pwr_state = 'off' + self.exec_logger.debug(f'{self.model} is off') diff --git a/ohmpi/hardware_system.py b/ohmpi/hardware_system.py index edb8f8b1..377e624a 100644 --- a/ohmpi/hardware_system.py +++ b/ohmpi/hardware_system.py @@ -340,7 +340,14 @@ class OhmPiHardware: vab_max = np.abs(vab_max) vmn_min = np.abs(vmn_min) vab = np.min([np.abs(tx_volt), vab_max]) - self.tx.turn_on() + # self.tx.turn_on() + switch_pwr_off, switch_tx_pwr_off = False, False #TODO: check if these should be moved in kwargs + if self.tx.pwr_state == 'off': + self.tx.pwr_state = 'on' + switch_tx_pwr_off = True + if self.tx.pwr.pwr_state == 'off': + self.tx.pwr.pwr_state = 'on' + switch_pwr_off = True if 1. / self.rx.sampling_rate > pulse_duration: sampling_rate = 1. / pulse_duration # TODO: check this... else: @@ -362,7 +369,11 @@ class OhmPiHardware: self.tx.exec_logger.warning(f'Unknown strategy {strategy} for setting VAB! Using {vab} V') else: self.tx.exec_logger.debug(f'Constant strategy for setting VAB, using {vab} V') - self.tx.turn_off() + # self.tx.turn_off() + if switch_pwr_off: + self.tx.pwr.pwr_state = 'off' + if switch_tx_pwr_off: + self.tx.pwr_state = 'off' rab = (np.abs(vab) * 1000.) / iab self.exec_logger.debug(f'RAB = {rab:.2f} Ohms') if vmn < 0: @@ -401,9 +412,12 @@ class OhmPiHardware: def vab_square_wave(self, vab, cycle_duration, sampling_rate=None, cycles=3, polarity=1, duty_cycle=1., append=False): self.exec_logger.event(f'OhmPiHardware\tvab_square_wave\tbegin\t{datetime.datetime.utcnow()}') - switch_pwr_off = False + switch_pwr_off, switch_tx_pwr_off = False, False if self.tx.pwr_state == 'off': self.tx.pwr_state = 'on' + switch_tx_pwr_off = True + if self.tx.pwr.pwr_state == 'off': + self.tx.pwr.pwr_state = 'on' switch_pwr_off = True self._gain_auto() assert 0. <= duty_cycle <= 1. @@ -419,6 +433,8 @@ class OhmPiHardware: self._vab_pulses(vab, durations, sampling_rate, polarities=polarities, append=append) self.exec_logger.event(f'OhmPiHardware\tvab_square_wave\tend\t{datetime.datetime.utcnow()}') if switch_pwr_off: + self.tx.pwr.pwr_state = 'off' + if switch_tx_pwr_off: self.tx.pwr_state = 'off' def _vab_pulse(self, vab=None, duration=1., sampling_rate=None, polarity=1, append=False): """ Gets VMN and IAB from a single voltage pulse @@ -442,10 +458,13 @@ class OhmPiHardware: self.tx.polarity = 0 #TODO: is this necessary? def _vab_pulses(self, vab, durations, sampling_rate, polarities=None, append=False): - switch_pwr_off = False + switch_pwr_off, switch_tx_pwr_off = False, False if self.tx.pwr_state == 'off': self.tx.pwr_state = 'on' switch_pwr_off = True + if self.tx.pwr.pwr_state == 'off': + self.tx.pwr.pwr_state = 'on' + switch_pwr_off = True n_pulses = len(durations) self.exec_logger.debug(f'n_pulses: {n_pulses}') if self.tx.pwr.voltage_adjustable: @@ -464,6 +483,8 @@ class OhmPiHardware: self._vab_pulse(vab=vab, duration=durations[i], sampling_rate=sampling_rate, polarity=polarities[i], append=True) if switch_pwr_off: + self.tx.pwr.pwr_state = 'off' + if switch_tx_pwr_off: self.tx.pwr_state = 'off' def switch_mux(self, electrodes, roles=None, state='off', **kwargs): """Switches on multiplexer relays for given quadrupole. diff --git a/ohmpi/ohmpi.py b/ohmpi/ohmpi.py index e4724a51..135cf0cb 100644 --- a/ohmpi/ohmpi.py +++ b/ohmpi/ohmpi.py @@ -423,7 +423,7 @@ class OhmPi(object): # TODO: add sampling_interval -> impact on _hw.rx.sampling_rate (store the current value, change the _hw.rx.sampling_rate, do the measurement, reset the sampling_rate to the previous value) # TODO: default value of tx_volt and other parameters set to None should be given in config.py and used in function definition # TODO: add rs_check option (or propose an other way to do this) - # TODO: better way of handling default settings + # TODO: implement compute_tx_volt for injection strategies """Measures on a quadrupole and returns transfer resistance. Parameters @@ -871,6 +871,7 @@ class OhmPi(object): - export_path (path where to export the data, timestamp will be added to filename ; if export_path is given, it goes over export_dir and export_name) + Parameters ---------- settings : str, dict -- GitLab