diff --git a/configs/config_mb_2024_0_2__8_mux_2023_dps5005.py b/configs/config_mb_2024_0_2__8_mux_2023_dps5005.py index 4565d6d2896bec9d3a4ef8550e595578b4d34707..c88c3bcde37de0285136007b88a30b3d2e982f05 100644 --- a/configs/config_mb_2024_0_2__8_mux_2023_dps5005.py +++ b/configs/config_mb_2024_0_2__8_mux_2023_dps5005.py @@ -61,25 +61,25 @@ HARDWARE_CONFIG = { {'model': 'mux_2023_0_X', 'mux_tca_address': 0x74, 'roles': {'A': 'X'}, - 'cabling': {(i, j): ('mux_A2', i) for j in ['A'] for i in range(65, 129)}, + 'cabling': {(i+64, j): ('mux_A2', i) for j in ['A'] for i in range(1, 65)}, 'voltage_max': 12.}, 'mux_B2': {'model': 'mux_2023_0_X', 'mux_tca_address': 0x75, 'roles': {'B': 'X'}, - 'cabling': {(i, j): ('mux_B2', i) for j in ['B'] for i in range(65, 129)}, + 'cabling': {(i+64, j): ('mux_B2', i) for j in ['B'] for i in range(1, 65)}, 'voltage_max': 12.}, 'mux_M2': {'model': 'mux_2023_0_X', 'mux_tca_address': 0x76, 'roles': {'M': 'X'}, - 'cabling': {(i, j): ('mux_M2', i) for j in ['M'] for i in range(65, 129)}, + 'cabling': {(i+64, j): ('mux_M2', i) for j in ['M'] for i in range(1, 65)}, 'voltage_max': 12.}, 'mux_N2': {'model': 'mux_2023_0_X', 'mux_tca_address': 0x77, 'roles': {'N': 'X'}, - 'cabling': {(i, j): ('mux_N2', i) for j in ['N'] for i in range(65, 129)}, + 'cabling': {(i+64, j): ('mux_N2', i) for j in ['N'] for i in range(1, 65)}, 'voltage_max': 12.}, }, 'default': {'interface_name': 'i2c_ext', diff --git a/dev/start_mqtt_html.py b/dev/start_mqtt_html.py index 4c88810bbadc1b2f9fcf73a9f079bf7d6345b38b..0e7dd6cf67694ad0de19c613bd235af4b055fbce 100644 --- a/dev/start_mqtt_html.py +++ b/dev/start_mqtt_html.py @@ -3,15 +3,25 @@ # to message from the MQTT broker from ohmpi.utils import change_config -change_config('../configs/config_mb_2023.py', verbose=False) -#change_config('../configs/config_mb_2023_4_mux_2023.py', verbose=False) +# change_config('../configs/config_mb_2023.py', verbose=False) +change_config('../configs/config_mb_2023_4_mux_2023.py', verbose=False) #change_config('../configs/config_mb_2024_0_2__4_mux_2023_dps5005.py', verbose=False) +# start html interface +import subprocess +subprocess.Popen(['python', '-m', 'http.server']) + +# start ohmpi listener from ohmpi.ohmpi import OhmPi from ohmpi.config import OHMPI_CONFIG -ohmpi = OhmPi(settings=OHMPI_CONFIG['settings']) -if ohmpi.controller is not None: - ohmpi.controller.loop_forever() +k = OhmPi(settings=OHMPI_CONFIG['settings']) +import os +k.load_sequence(os.path.join(os.path.dirname(__file__), '../sequences/wenner16.txt')) +k.reset_mux() +#k.run_multiple_sequences(sequence_delay=20, nb_meas=3) + +if k.controller is not None: + k.controller.loop_forever() # restore default config change_config('../configs/config_default.py', verbose=False) diff --git a/dev/test_mb_2023_4_mux_2023.py b/dev/test_mb_2023_4_mux_2023.py index ca9c9c669028d077929a075488e37c40f928fb04..9dd195d0bfaa893fa836770444651d26431d5b0a 100644 --- a/dev/test_mb_2023_4_mux_2023.py +++ b/dev/test_mb_2023_4_mux_2023.py @@ -85,10 +85,10 @@ if within_ohmpi: print('Starting test with OhmPi.') k = OhmPi() # k.get_data() - k.load_sequence(os.path.join(os.path.dirname(__file__), '../sequences/wenner.txt')) - k.reset_mux() + # k.load_sequence(os.path.join(os.path.dirname(__file__), '../sequences/wenner16.txt')) + # k.reset_mux() # k.run_multiple_sequences(sequence_delay=20, nb_meas=3) - k.run_sequence(injection_duration=0.2) + # k.run_sequence(injection_duration=0.2) # k.rs_check(tx_volt=4) # k.test_mux(mux_id=None, activation_time=0.2) # k._hw.switch_mux([A, B, M, N], state='on') @@ -103,11 +103,11 @@ if within_ohmpi: # k._hw.switch_mux([A, B, M, N], state='off') # print(f'OhmPiHardware Resistance: {k._hw.last_rho :.2f} ohm, dev. {k._hw.last_dev:.2f} %, rx bias: {k._hw.rx._bias:.2f} mV') # k._hw._plot_readings() - # A, B, M, N = (16, 13, 15, 14) + A, B, M, N = (17, 20, 18, 19) # A, B, M, N = (1, 4, 2, 3) - # d = k.run_measurement([A, B, M, N], injection_duration=0.5, nb_stack=2, duty_cycle=0.5) - # print(d) - # k._hw._plot_readings() + d = k.run_measurement([A, B, M, N], injection_duration=0.5, nb_stack=2, duty_cycle=0.5) + print(d) + k._hw._plot_readings() # print(f'OhmPiHardware: Resistance: {k._hw.last_resistance() :.2f} ohm, dev. {k._hw.last_dev():.2f} %, sp: {k._hw.sp:.2f} mV, rx bias: {k._hw.rx._bias:.2f} mV') # print(f'OhmPi: Resistance: {d["R [ohm]"] :.2f} ohm, dev. {d["R_std [%]"]:.2f} %, rx bias: {k._hw.rx._bias:.2f} mV') # k._hw._plot_readings(save_fig=False) diff --git a/index.html b/index.html index 88914ca66ea3ce37f1ac43f43d8eb224504ba276..99805072828a1187878bb6a598d9143ccec8105f 100755 --- a/index.html +++ b/index.html @@ -220,6 +220,12 @@ mosquitto_sub -h raspberrypi.local -t ohmpi_0001/ctrl // process data msg = payload // for accessing the variable from the console console.log('DATA LOG:', payload) + + // replace NaN values by null to make them acceptable for json parser + payload = payload.replace(/\bNaN\b/g, "null"); + payload = payload.replace(/\bnan\b/g, "null"); + + // parse to json let ddic = JSON.parse(payload.split('INFO:')[1]) // RS check data @@ -516,7 +522,6 @@ mosquitto_sub -h raspberrypi.local -t ohmpi_0001/ctrl // xpos.push((Math.min(ab, mn) + dist/2)*elec_spacing) // ypos.push(- (Math.sqrt(2)/2*dist)*elec_spacing) } - console.log('========', app, xpos, ypos) // update the trace and redraw the figure trace['x'] = xpos trace['y'] = ypos @@ -825,6 +830,10 @@ mosquitto_sub -h raspberrypi.local -t ohmpi_0001/ctrl output.innerHTML = 'Status: ' + x['status'] + ' (all data cleared)' console.log('all data removed') }) + data = {} + quads = [] + getData() + document.getElementById('quadSelect').innerHTML = '' } let removeDataBtn = document.getElementById('removeDataBtn') removeDataBtn.addEventListener('click', removeDataBtnFunc) diff --git a/ohmpi/config.py b/ohmpi/config.py index f3f566ba70a9fb3bf7797821b95578b28d48a232..0763f48ca2240311e01b281a1eea9571c324defd 100644 --- a/ohmpi/config.py +++ b/ohmpi/config.py @@ -1,7 +1,7 @@ import logging from ohmpi.utils import get_platform -from paho.mqtt.client import MQTTv31 # noqa +from paho.mqtt.client import MQTTv31 _, on_pi = get_platform() # DEFINE THE ID OF YOUR OhmPi @@ -17,36 +17,26 @@ OHMPI_CONFIG = { 'settings': 'ohmpi_settings.json', # INSERT YOUR FAVORITE SETTINGS FILE HERE } -r_shunt = 2. HARDWARE_CONFIG = { - 'ctl': {'model': 'raspberry_pi'}, - 'pwr': {'model': 'pwr_batt', 'voltage': 12., 'interface_name': 'none'}, - 'tx': {'model': 'mb_2023_0_X', - 'voltage_max': 50., # Maximum voltage supported by the TX board [V] - 'current_max': 4.80/(50*r_shunt), # Maximum voltage read by the current ADC on the TX board [A] - 'r_shunt': r_shunt, # Shunt resistance in Ohms - 'interface_name': 'i2c' + 'ctl': {'model' : 'dummy_ctl' + }, + 'tx' : {'model' : 'dummy_tx', + 'current_max': 4800 / 50 / 2, # Maximum current mA + 'r_shunt': 2, # Shunt resistance in Ohms + 'low_battery': 12. # Volts }, - 'rx': {'model': 'mb_2023_0_X', - 'coef_p2': 2.50, # slope for conversion for ADS, measurement in V/V - 'sampling_rate': 50., # number of samples per second - 'interface_name': 'i2c', + 'rx' : {'model': 'dummy_rx', }, - 'mux': # default properties given in config are system properties that will be - # overwritten by properties defined in each the board dict below. - # if defined in board specs, values out of specs will be bounded to remain in specs - # omitted properties in config will be set to board specs default values if they exist - {'boards': {}, - 'default': {'interface_name': 'i2c', - 'voltage_max': 100., - 'current_max': 3.} - } + 'mux': {'model' : 'dummy_mux', + 'max_elec': 64, + 'voltage_max' : 100, + 'current_max' : 3 + } } - # SET THE LOGGING LEVELS, MQTT BROKERS AND MQTT OPTIONS ACCORDING TO YOUR NEEDS # Execution logging configuration EXEC_LOGGING_CONFIG = { - 'logging_level': logging.DEBUG, # TODO: set logging level back to INFO + 'logging_level': logging.INFO, 'log_file_logging_level': logging.DEBUG, 'logging_to_console': True, 'file_name': f'exec{logging_suffix}.log', @@ -70,8 +60,8 @@ DATA_LOGGING_CONFIG = { # State of Health logging configuration (For a future release) SOH_LOGGING_CONFIG = { 'logging_level': logging.INFO, - 'logging_to_console': True, 'log_file_logging_level': logging.DEBUG, + 'logging_to_console': True, 'file_name': f'soh{logging_suffix}.log', 'max_bytes': 16777216, 'backup_count': 1024, diff --git a/ohmpi/hardware_system.py b/ohmpi/hardware_system.py index c4252becf37c353e9c97987c264af2758a1a18e7..03a5e220d19ec4efb8967026853e600c25a0bd81 100644 --- a/ohmpi/hardware_system.py +++ b/ohmpi/hardware_system.py @@ -317,7 +317,7 @@ class OhmPiHardware: def last_vmn_dev(self, delay=0.): # TODO: should compute std per stack because this does not account for SP... v = np.where((self.readings[:, 0] >= delay) & (self.readings[:, 2] != 0))[0] if len(v) > 1: - return 100. * np.std(self.readings[v, 2] * (self.readings[v, 4])) / self.last_vmn(delay=delay) + return 100. * np.std(self.readings[v, 2] * (self.readings[v, 4] - self.sp)) / self.last_vmn(delay=delay) else: return np.nan @@ -331,7 +331,7 @@ class OhmPiHardware: def last_iab_dev(self, delay=0.): v = np.where((self.readings[:, 0] >= delay) & (self.readings[:, 2] != 0))[0] if len(v) > 1: - return 100. * np.std(self.readings[v, 3]) / / self.last_iab(delay=delay) + return 100. * np.std(self.readings[v, 3]) / self.last_iab(delay=delay) else: return np.nan @@ -587,6 +587,7 @@ class OhmPiHardware: """ self.exec_logger.event(f'OhmPiHardware\tvab_square_wave\tbegin\t{datetime.datetime.utcnow()}') switch_pwr_off, switch_tx_pwr_off = False, False + # switches tx pwr on if needed (relays switching dps on and off) if self.pwr_state == 'off': self.pwr_state = 'on' switch_tx_pwr_off = True @@ -623,6 +624,12 @@ class OhmPiHardware: self.tx.voltage = vab else: vab = self.tx.voltage + + # switches dps pwr on if needed + switch_pwr_off = False + if self.tx.pwr.pwr_state == 'off': + self.tx.pwr.pwr_state = 'on' + switch_pwr_off = True # reads current and voltage during the pulse injection = Thread(target=self._inject, kwargs={'injection_duration': duration, 'polarity': polarity}) readings = Thread(target=self._read_values, kwargs={'sampling_rate': sampling_rate, 'append': append}) @@ -631,9 +638,12 @@ class OhmPiHardware: readings.join() injection.join() self.tx.polarity = 0 #TODO: is this necessary? - + if switch_pwr_off: + self.tx.pwr.pwr_state = 'off' def _vab_pulses(self, vab, durations, sampling_rate, polarities=None, append=False): switch_pwr_off, switch_tx_pwr_off = False, False + + # switches tx pwr on if needed (relays switching dps on and off) if self.pwr_state == 'off': self.pwr_state = 'on' switch_pwr_off = True @@ -643,9 +653,12 @@ class OhmPiHardware: self.tx.voltage = vab else: vab = self.tx.voltage + + # switches dps pwr on if needed if self.tx.pwr.pwr_state == 'off': self.tx.pwr.pwr_state = 'on' switch_pwr_off = True + if sampling_rate is None: sampling_rate = RX_CONFIG['sampling_rate'] if polarities is not None: diff --git a/ohmpi/ohmpi.py b/ohmpi/ohmpi.py index 969261c6a360b7cc8d19d717690b3be5114aba11..6e5dda19ef65635f80d695bfca302705dee170d4 100644 --- a/ohmpi/ohmpi.py +++ b/ohmpi/ohmpi.py @@ -784,8 +784,13 @@ class OhmPi(object): cmd_id : str, optional Unique command identifier """ + # check pwr is on, if not, let's turn it on + switch_tx_pwr_off = False + if self._hw.pwr_state == 'off': + self._hw.pwr_state = 'on' + switch_tx_pwr_off = True - self._hw.tx.pwr.voltage = float(tx_volt) + # self._hw.tx.pwr.voltage = float(tx_volt) # create custom sequence where MN == AB # we only check the electrodes which are in the sequence (not all might be connected) @@ -812,13 +817,20 @@ class OhmPi(object): self.reset_mux() + # turn dps_pwr_on if needed + switch_pwr_off = False + if self._hw.pwr.pwr_state == 'off': + self._hw.pwr.pwr_state = 'on' + switch_pwr_off = True + # measure all quad of the RS sequence for i in range(0, quads.shape[0]): quad = quads[i, :] # quadrupole self._hw.switch_mux(electrodes=list(quads[i, :2]), roles=['A', 'B'], state='on') - self._hw._vab_pulse(duration=0.2) + self._hw._vab_pulse(duration=0.2, vab=tx_volt) current = self._hw.readings[-1, 3] - voltage = self._hw.tx.pwr.voltage * 1000 + vab = self._hw.tx.pwr.voltage + print(vab, current) time.sleep(0.2) # self.switch_mux_on(quad, bypass_check=True) # put before raising the pins (otherwise conflict i2c) @@ -834,7 +846,7 @@ class OhmPi(object): # current = self._hw.tx.current # compute resistance measured (= contact resistance) - resist = abs(voltage / current) / 1000 # kOhm + rab = abs(vab*1000 / current) / 1000 # kOhm # print(str(quad) + '> I: {:>10.3f} mA, V: {:>10.3f} mV, R: {:>10.3f} kOhm'.format( # current, voltage, resist)) # msg = f'Contact resistance {str(quad):s}: I: {current :>10.3f} mA, ' \ @@ -845,28 +857,32 @@ class OhmPi(object): 'rsdata': { 'A': int(quad[0]), 'B': int(quad[1]), - 'rs': resist, # in kOhm + 'rs': np.round(rab,3), # in kOhm } } self.data_logger.info(json.dumps(msg)) # if contact resistance = 0 -> we have a short circuit!! - if resist < 1e-5: - msg = f'!!!SHORT CIRCUIT!!! {str(quad):s}: {resist:.3f} kOhm' + if rab < 1e-5: + msg = f'!!!SHORT CIRCUIT!!! {str(quad):s}: {rab:.3f} kOhm' self.exec_logger.warning(msg) # save data in a text file self.append_and_save(export_path_rs, { 'A': quad[0], 'B': quad[1], - 'RS [kOhm]': resist, + 'RS [kOhm]': np.round(rab,3), }) # close mux path and put pin back to GND self.switch_mux_off(quad) self.status = 'idle' - + if switch_pwr_off: + self._hw.pwr.pwr_state = 'off' + # if power was off before measurement, let's turn if off + if switch_tx_pwr_off: + self._hw.pwr_state = 'off' # # # TODO if interrupted, we would need to restore the values # # TODO or we offer the possibility in 'run_measurement' to have rs_check each time? diff --git a/ohmpi/utils.py b/ohmpi/utils.py index 142d4fb40fa4627bebaeb5f84e578adb52291cfa..8458e6743f84634951f7f24d70412eff119453fb 100644 --- a/ohmpi/utils.py +++ b/ohmpi/utils.py @@ -112,3 +112,8 @@ def parse_log(log): msg = np.array(msg) session = np.array(session) return time, process_id, tag, msg, session + +def mux_2024_to_mux_2023_takeouts(sequence): + mapper = {1: 16, 2: 1, 3: 15, 4: 2, 5: 14, 6: 3, 7: 13, 8: 4, 9: 12, 10: 5, 11: 11, + 12: 6, 13: 10, 14: 7, 15: 9, 16: 8} + remapped_sequence = mapper[sequence] \ No newline at end of file diff --git a/run_http_interface.sh b/run_http_interface.sh index faa4924d61a7f83f76439c26130c3bdcd560a416..f80be4e3f91b765dd3b625978c37c0777f21cea0 100755 --- a/run_http_interface.sh +++ b/run_http_interface.sh @@ -1,5 +1,3 @@ export PYTHONPATH=`pwd` source $PYTHONPATH/ohmpy/bin/activate -python dev/start_mqtt_html.py & # run ohmpi.py to capture the commands -python -m http.server # run web GUI - +python dev/start_mqtt_html.py