From dd4527f06554f795d96c6d00ea4ee49de12de124 Mon Sep 17 00:00:00 2001
From: "remi.clement" <remi.clement @inrae.fr>
Date: Sun, 5 Sep 2021 14:25:13 +0200
Subject: [PATCH] add 4 electrodes measurement

---
 Ohmpi_4elec.py   | 278 +++++++++++++++++++++++++++++++++++++++++++++++
 measurement.csv  |  77 +++++++++++++
 ohmpi_param.json |   8 +-
 3 files changed, 359 insertions(+), 4 deletions(-)
 create mode 100644 Ohmpi_4elec.py

diff --git a/Ohmpi_4elec.py b/Ohmpi_4elec.py
new file mode 100644
index 00000000..760d26b4
--- /dev/null
+++ b/Ohmpi_4elec.py
@@ -0,0 +1,278 @@
+"""
+created on september , 202
+Update april 2021
+Ohmpi.py is a program to control a low-cost and open hardward resistivity meter OhmPi that has been developed by Rémi CLEMENT(INRAE),Vivien DUBOIS(INRAE),Hélène GUYARD(IGE), Nicolas FORQUET (INRAE), Oliver KAUFMANN (UMONS) and Yannick FARGIER (IFSTTAR).
+"""
+
+print('\033[1m'+'\033[31m'+' ________________________________')
+print('|  _  | | | ||  \/  || ___ \_   _|')
+print('| | | | |_| || .  . || |_/ / | |' ) 
+print('| | | |  _  || |\/| ||  __/  | |')  
+print('\ \_/ / | | || |  | || |    _| |_') 
+print(' \___/\_| |_/\_|  |_/\_|    \___/ ')
+print('\033[0m')
+print('OhmPi 4 elec  start' )
+print('Vers: 1.00')
+print('Import library')
+
+
+
+import time , board, busio, numpy, os, sys, json, glob,os.path,adafruit_tca9548a
+import adafruit_ads1x15.ads1115 as ADS
+from adafruit_ads1x15.analog_in import AnalogIn
+from pandas import DataFrame
+from datetime import datetime
+from adafruit_mcp230xx.mcp23008 import MCP23008
+from adafruit_mcp230xx.mcp23017 import MCP23017
+import digitalio
+from digitalio import Direction
+from gpiozero import CPUTemperature
+current_time = datetime.now()
+print(current_time.strftime("%Y-%m-%d %H:%M:%S"))
+"""
+hardware parameters
+"""
+R_shunt = 0.2# reference resistance value in ohm
+coef_p2 = 2.50# slope for current conversion for ADS.P2, measurement in V/V
+coef_p3 = 2.50 # slope for current conversion for ADS.P3, measurement in V/V
+offset_p2= 0
+offset_p3= 0
+integer=1
+meas=numpy.zeros((3,integer))
+
+"""
+import parameters
+"""
+
+with open('ohmpi_param.json') as json_file:
+    pardict = json.load(json_file)
+
+
+i2c = busio.I2C(board.SCL, board.SDA) #activation du protocle I2C
+mcp = MCP23008(i2c, address=0x20) #connexion I2C MCP23008, injection de courant
+ads_current = ADS.ADS1115(i2c, gain=2/3,data_rate=860, address=0X48)# connexion ADS1115, pour la mesure de courant
+ads_voltage = ADS.ADS1115(i2c, gain=2/3,data_rate=860, address=0X49)# connexion ADS1115, pour la mesure de voltage
+#initialisation desvoie pour la polarité
+pin0 = mcp.get_pin(0)
+pin0.direction = Direction.OUTPUT
+pin1 = mcp.get_pin(1)
+pin1.direction = Direction.OUTPUT
+pin0.value = False
+pin1.value = False
+
+
+  
+
+
+"""
+functions
+"""
+# function swtich_mux select the right channels for the multiplexer cascade for electrodes A, B, M and N.
+def switch_mux_on(quadripole):
+    elec_adress=[0x76,0X71,0x74,0x70]
+      
+    for i in range(0,4):
+        tca= adafruit_tca9548a.TCA9548A(i2c, elec_adress[i]) #choose MUX A B M or N
+        
+        if quadripole[i] < 17:
+            nb_i2C=7
+            a=quadripole[i]
+        elif quadripole[i] > 16 and quadripole[i] < 33:    
+            nb_i2C=6
+            a=quadripole[i]-16
+        elif quadripole[i] > 32 and quadripole[i] < 49:    
+            nb_i2C=5
+            a=quadripole[i]-32
+        elif quadripole[i] > 48 and quadripole[i] < 65:    
+            nb_i2C=4
+            a=quadripole[i]-48
+              
+        mcp2 = MCP23017(tca[nb_i2C])     
+        mcp2.get_pin(a-1).direction=digitalio.Direction.OUTPUT
+        mcp2.get_pin(a-1).value=True
+ 
+def switch_mux_off(quadripole):
+    elec_adress=[0x76,0X71,0x74,0x70]
+      
+    for i in range(0,4):
+        tca= adafruit_tca9548a.TCA9548A(i2c, elec_adress[i]) #choose MUX A B M or N
+        
+        if quadripole[i] < 17:
+            nb_i2C=7
+            a=quadripole[i]
+        elif quadripole[i] > 16 and quadripole[i] < 33:    
+            nb_i2C=6
+            a=quadripole[i]-16
+        elif quadripole[i] > 32 and quadripole[i] < 49:    
+            nb_i2C=5
+            a=quadripole[i]-32
+        elif quadripole[i] > 48 and quadripole[i] < 65:    
+            nb_i2C=4
+            a=quadripole[i]-48
+              
+        mcp2 = MCP23017(tca[nb_i2C])     
+        mcp2.get_pin(a-1).direction=digitalio.Direction.OUTPUT
+        mcp2.get_pin(a-1).value=False
+       
+
+#function to switch  off mux
+def ZERO_mux(nb_elec):
+    elec_adress=[0x76,0X71,0x74,0x70]
+    for i in range(0,4):
+        tca= adafruit_tca9548a.TCA9548A(i2c, elec_adress[i]) #choose MUX A B M or N
+        for y in range(0,nb_elec):
+            qd=y+1
+            if qd < 17:
+                nb_i2C=7
+                a=qd
+            elif qd > 16 and qd < 33:    
+                nb_i2C=6
+                a=qd-16
+            elif qd > 32 and qd < 49:    
+                nb_i2C=5
+                a=qd-32
+            elif qd > 48 and qd < 65:    
+                nb_i2C=4
+                a=qd-48
+                  
+            mcp2 = MCP23017(tca[nb_i2C])     
+            mcp2.get_pin(a-1).direction=digitalio.Direction.OUTPUT
+            mcp2.get_pin(a-1).value= False
+
+# function to find rows with identical values in different columns
+def find_identical_in_line(array_object):
+    output = []
+    if array_object.ndim == 1:
+        temp = numpy.zeros(4)
+        for i in range(len(array_object)):
+            temp[i] = numpy.count_nonzero(array_object == array_object[i])
+        if any(temp > 1):
+            output.append(0)
+    else:
+        for i in range(len(array_object[:,1])):
+            temp = numpy.zeros(len(array_object[1,:]))
+            for j in range(len(array_object[1,:])):
+                temp[j] = numpy.count_nonzero(array_object[i,:] == array_object[i,j])
+            if any(temp > 1):
+                output.append(i)
+    return output
+# 
+# read quadripole file and apply tests
+def read_quad(filename, nb_elec):
+    output = numpy.loadtxt(filename, delimiter=" ",dtype=int) # load quadripole file
+    # locate lines where the electrode index exceeds the maximum number of electrodes
+    test_index_elec = numpy.array(numpy.where(output > nb_elec))
+    # locate lines where an electrode is referred twice
+    test_same_elec = find_identical_in_line(output)
+    # if statement with exit cases (rajouter un else if pour le deuxième cas du ticket #2)
+    if test_index_elec.size != 0:
+        for i in range(len(test_index_elec[0,:])):
+            print("Error: An electrode index at line "+ str(test_index_elec[0,i]+1)+" exceeds the maximum number of electrodes")
+        sys.exit(1)
+    elif len(test_same_elec) != 0:
+        for i in range(len(test_same_elec)):
+            print("Error: An electrode index is used twice at line " + str(test_same_elec[i]+1))
+        sys.exit(1)
+    else:
+        return output
+
+def run_measurement(nb_stack, injection_deltat, R_shunt, coefp2, coefp3):
+    start_time=time.time()
+    # inner variable initialization
+    sum_I=0
+    sum_Vmn=0
+    sum_Ps=0
+    # injection courant and measure
+    mcp = MCP23008(i2c, address=0x20)
+    pin0 = mcp.get_pin(0)
+    pin0.direction = Direction.OUTPUT
+    pin1 = mcp.get_pin(1)
+    pin1.direction = Direction.OUTPUT
+    pin0.value = False
+    pin1.value = False
+    for n in range(0,3+2*nb_stack-1) :        
+        # current injection
+        
+        if (n % 2) == 0:
+            
+            pin1.value = True
+            pin0.value = False # current injection polarity n°1        
+        else:
+            pin0.value = True
+            pin1.value = False# injection de courant polarity n°2
+        start_delay=time.time()
+        time.sleep(injection_deltat) # delay depending on current injection duration
+
+       
+        for k in range(0,integer):
+          meas[0,k] = ((AnalogIn(ads_current,ADS.P0).voltage/50)/R_shunt)*1000 # reading current value on ADS channel A0
+          meas[1,k] = AnalogIn(ads_voltage,ADS.P0).voltage * coefp2*1000
+          meas[2,k] = AnalogIn(ads_voltage,ADS.P1).voltage * coefp3*1000 # reading voltage value on ADS channel A2
+        pin1.value = False; pin0.value = False# stop current injection
+        end_delay=time.time()
+        sum_I=sum_I+(numpy.mean(meas[0,:]))
+        Vmn1=((numpy.mean(meas[1,:]))-(numpy.mean(meas[2,:])))
+        if (n % 2) == 0:
+              sum_Vmn=sum_Vmn-Vmn1
+              sum_Ps=sum_Ps+Vmn1
+        else:
+              sum_Vmn=sum_Vmn+Vmn1
+              sum_Ps=sum_Ps+Vmn1
+        end_calc=time.time()
+        cpu = CPUTemperature()
+        time.sleep((end_delay-start_delay)-(end_calc-end_delay)) 
+    # return averaged values
+#     cpu= CPUTemperature()
+    output = DataFrame({
+        "time":[datetime.now()],
+        "A":[(1)],
+        "B":[(2)],
+        "M":[(3)],
+        "N":[(4)],
+        "Vmn [mV]":[(sum_Vmn/(3+2*nb_stack-1))],
+        "I [mA]":[(sum_I/(3+2*nb_stack-1))],
+        "R [ohm]":[( (sum_Vmn/(3+2*nb_stack-1)/(sum_I/(3+2*nb_stack-1))))],
+              
+        "Ps [mV]":[(sum_Ps/(3+2*nb_stack-1))],
+        "nbStack":[nb_stack],
+        "CPU temp [°C]":[cpu.temperature],
+
+        "Time [S]":[(-start_time+time.time())]
+
+     
+     
+      # Dead time equivalent to the duration of the current injection pulse   
+    })
+    output=output.round(2)
+    print(output.to_string())
+    time.sleep(1)
+    return output
+
+# save data
+def append_and_save(path, last_measurement):
+    
+    if os.path.isfile(path):
+        # Load data file and append data to it
+        with open(path, 'a') as f:
+             last_measurement.to_csv(f, header=False)
+    else:
+        # create data file and add headers
+        with open(path, 'a') as f:
+             last_measurement.to_csv(f, header=True)
+
+
+"""
+Main loop
+"""
+for g in range(0,pardict.get("nbr_meas")): # for time-lapse monitoring
+
+            
+        
+        
+    current_measurement = run_measurement(pardict.get("stack"), pardict.get("injection_duration"), R_shunt, coef_p2, coef_p3)
+        
+    append_and_save(pardict.get("export_path"), current_measurement)
+    
+    
+    
+    time.sleep(pardict.get("sequence_delay")) #waiting next measurement (time-lapse)
diff --git a/measurement.csv b/measurement.csv
index f8aeb9cf..11f2d536 100644
--- a/measurement.csv
+++ b/measurement.csv
@@ -10580,3 +10580,80 @@
 0,2021-04-13 16:45:56.802663,27,28,29,30,-101.71,4.38,-23.2,-11.82,1,47.24,5.03
 0,2021-04-13 16:46:03.082127,28,29,30,31,-116.35,5.12,-22.72,11.09,1,47.24,5.03
 0,2021-04-13 16:46:09.381786,29,30,31,32,-129.14,4.98,-25.94,44.35,1,47.24,5.03
+0,2021-09-04 21:24:25.798333,1,2,3,4,-3.4,1.05,-3.24,-8.48,1,58.91,5.13
+0,2021-09-04 21:24:54.080792,1,2,3,4,2.32,1.05,2.22,-10.71,1,59.4,5.29
+0,2021-09-04 21:25:23.478770,1,2,3,4,-3.15,1.04,-3.02,-10.47,1,61.35,5.25
+0,2021-09-04 21:25:39.837089,1,2,3,4,-0.97,1.04,-0.93,-8.64,1,58.43,5.27
+0,2021-09-04 21:25:56.179383,1,2,3,4,4.51,1.05,4.31,-10.25,1,58.91,5.27
+0,2021-09-04 21:26:12.500129,1,2,3,4,-1.35,1.04,-1.29,-11.54,1,57.94,5.26
+0,2021-09-04 21:26:28.852915,1,2,3,4,0.47,1.05,0.45,-9.42,1,57.45,5.29
+0,2021-09-04 21:26:45.192773,1,2,3,4,-2.46,1.05,-2.35,-7.92,1,57.94,5.27
+0,2021-09-05 13:54:49.818846,1,2,3,4,345.69,25.6,13.5,-0.28,1,47.22,4.9
+0,2021-09-05 13:55:06.073880,1,2,3,4,344.53,25.6,13.46,-0.46,1,45.28,5.15
+0,2021-09-05 13:55:22.438843,1,2,3,4,345.03,25.6,13.48,-0.66,1,46.25,5.29
+0,2021-09-05 13:55:38.782330,1,2,3,4,646.03,25.6,25.24,0.07,1,45.28,5.27
+0,2021-09-05 13:55:55.149366,1,2,3,4,646.37,25.6,25.25,-0.79,1,45.28,5.3
+0,2021-09-05 13:56:11.545465,1,2,3,4,646.91,25.6,25.27,-0.9,1,45.28,5.33
+0,2021-09-05 13:56:27.885765,1,2,3,4,1188.46,25.6,46.42,-1.36,1,45.28,5.27
+0,2021-09-05 13:56:44.265390,1,2,3,4,1186.67,25.6,46.35,-0.18,1,45.28,5.31
+0,2021-09-05 13:57:00.343476,1,2,3,4,1187.59,25.6,46.39,-0.61,1,47.22,5.01
+0,2021-09-05 13:57:16.533995,1,2,3,4,1189.16,25.6,46.45,-1.36,1,46.25,5.15
+0,2021-09-05 13:58:28.711572,1,2,3,4,893.09,25.6,34.89,-299.02,1,45.76,33.34
+0,2021-09-05 13:59:13.118004,1,2,3,4,1188.53,25.6,46.43,-1.22,1,46.25,33.34
+0,2021-09-05 13:59:57.504174,1,2,3,4,1188.12,25.6,46.41,-0.76,1,45.76,33.31
+0,2021-09-05 14:00:41.863064,1,2,3,4,1188.25,25.6,46.42,-1.66,1,46.25,33.29
+0,2021-09-05 14:01:26.297905,1,2,3,4,1188.42,25.6,46.42,-1.14,1,45.28,33.36
+0,2021-09-05 14:02:10.396245,1,2,3,4,1188.51,25.6,46.43,-1.69,1,46.74,33.03
+0,2021-09-05 14:02:49.592434,1,2,3,4,1189.04,118.1,10.07,-1.15,1,46.74,33.3
+0,2021-09-05 14:03:33.981750,1,2,3,4,1188.8,118.12,10.06,-1.82,1,47.22,33.3
+0,2021-09-05 14:04:18.428129,1,2,3,4,1188.94,118.14,10.06,-1.68,1,46.25,33.37
+0,2021-09-05 14:05:02.843816,1,2,3,4,1188.51,118.13,10.06,-2.16,1,47.22,33.34
+0,2021-09-05 14:05:47.218115,1,2,3,4,1188.34,118.13,10.06,-1.99,1,46.25,33.31
+0,2021-09-05 14:06:31.623388,1,2,3,4,1187.9,118.14,10.05,-1.29,1,46.25,33.34
+0,2021-09-05 14:07:16.064673,1,2,3,4,1187.99,118.14,10.06,-2.13,1,46.25,33.37
+0,2021-09-05 14:08:00.465196,1,2,3,4,1188.87,118.14,10.06,-1.72,1,46.74,33.33
+0,2021-09-05 14:08:44.872794,1,2,3,4,1188.17,118.13,10.06,-1.51,1,46.74,33.33
+0,2021-09-05 14:09:29.303609,1,2,3,4,1188.17,118.17,10.05,-1.25,1,47.22,33.36
+0,2021-09-05 14:10:13.688134,1,2,3,4,1187.32,118.16,10.05,-0.22,1,46.74,33.31
+0,2021-09-05 14:10:58.084536,1,2,3,4,1188.05,118.16,10.05,-1.7,1,47.71,33.33
+0,2021-09-05 14:11:42.441436,1,2,3,4,1189.18,118.16,10.06,-1.22,1,46.74,33.29
+0,2021-09-05 14:12:26.862036,1,2,3,4,1187.77,118.17,10.05,-1.42,1,47.22,33.35
+0,2021-09-05 14:13:11.278051,1,2,3,4,1187.95,118.16,10.05,0.04,1,46.74,33.35
+0,2021-09-05 14:13:55.653221,1,2,3,4,1188.61,118.14,10.06,-0.53,1,47.22,33.3
+0,2021-09-05 14:14:40.039248,1,2,3,4,1188.4,118.15,10.06,-0.81,1,47.22,33.32
+0,2021-09-05 14:15:24.447997,1,2,3,4,1188.73,118.15,10.06,-0.39,1,47.71,33.34
+0,2021-09-05 14:16:43.642970,1,2,3,4,1187.73,118.21,10.05,-0.82,1,49.17,32.22
+0,2021-09-05 14:16:54.908079,1,2,3,4,1189.61,118.2,10.06,-1.52,1,48.69,4.18
+0,2021-09-05 14:17:01.193367,1,2,3,4,1189.26,118.22,10.06,0.47,1,47.22,4.21
+0,2021-09-05 14:17:07.478115,1,2,3,4,1187.03,118.22,10.04,-0.12,1,47.71,4.21
+0,2021-09-05 14:17:13.752349,1,2,3,4,1189.26,118.2,10.06,-1.17,1,48.2,4.21
+0,2021-09-05 14:17:20.026657,1,2,3,4,1185.27,118.21,10.03,0.47,1,48.2,4.21
+0,2021-09-05 14:17:26.289025,1,2,3,4,1185.97,118.15,10.04,-0.7,1,48.2,4.21
+0,2021-09-05 14:17:32.531004,1,2,3,4,1188.43,118.16,10.06,-2.7,1,48.69,4.19
+0,2021-09-05 14:17:38.772677,1,2,3,4,1185.5,118.26,10.02,-2.81,1,48.69,4.21
+0,2021-09-05 14:17:45.045351,1,2,3,4,1191.01,118.19,10.08,-1.05,1,47.71,4.21
+0,2021-09-05 14:17:51.274943,1,2,3,4,1188.55,118.14,10.06,0.94,1,49.66,4.16
+0,2021-09-05 14:17:57.508361,1,2,3,4,1187.26,118.15,10.05,2.7,1,49.17,4.18
+0,2021-09-05 14:18:03.762569,1,2,3,4,1189.96,118.15,10.07,2.11,1,49.17,4.19
+0,2021-09-05 14:18:09.963089,1,2,3,4,1189.14,118.18,10.06,-1.05,1,50.15,4.15
+0,2021-09-05 14:18:16.155346,1,2,3,4,1186.91,118.17,10.04,-4.69,1,50.15,4.14
+0,2021-09-05 14:18:22.361288,1,2,3,4,1190.31,118.14,10.08,-2.46,1,48.69,4.17
+0,2021-09-05 14:18:28.632581,1,2,3,4,1188.67,118.11,10.06,-0.82,1,48.2,4.21
+0,2021-09-05 14:18:34.882905,1,2,3,4,1185.74,118.11,10.04,-3.28,1,49.66,4.18
+0,2021-09-05 14:18:41.133238,1,2,3,4,1188.79,118.23,10.06,-0.23,1,48.2,4.2
+0,2021-09-05 14:18:47.400405,1,2,3,4,1189.61,118.2,10.06,-2.46,1,47.71,4.2
+0,2021-09-05 14:18:53.589049,1,2,3,4,1183.63,118.17,10.02,1.88,1,50.63,4.13
+0,2021-09-05 14:18:59.826156,1,2,3,4,1191.72,118.16,10.09,-5.98,1,49.17,4.18
+0,2021-09-05 14:19:06.093483,1,2,3,4,1185.62,118.18,10.03,0.59,1,49.17,4.21
+0,2021-09-05 14:19:12.362784,1,2,3,4,1187.73,118.16,10.05,-2.46,1,47.71,4.21
+0,2021-09-05 14:19:18.640894,1,2,3,4,1185.27,118.2,10.03,-1.17,1,48.69,4.21
+0,2021-09-05 14:19:24.882028,1,2,3,4,1187.73,118.18,10.05,-4.8,1,48.2,4.18
+0,2021-09-05 14:20:05.093011,1,2,3,4,1189.14,118.2,10.06,-1.76,1,48.69,32.24
+0,2021-09-05 14:20:39.419790,1,2,3,4,1191.25,118.24,10.07,-3.4,1,47.22,32.25
+0,2021-09-05 14:21:13.736040,1,2,3,4,1189.37,118.25,10.06,-1.05,1,47.22,32.25
+0,2021-09-05 14:21:48.045285,1,2,3,4,1186.56,118.23,10.04,1.05,1,47.22,32.25
+0,2021-09-05 14:22:22.354497,1,2,3,4,1187.61,118.21,10.05,-2.58,1,47.71,32.25
+0,2021-09-05 14:22:56.623952,1,2,3,4,1189.96,118.2,10.07,0.47,1,48.2,32.2
+0,2021-09-05 14:23:30.874439,1,2,3,4,1188.67,118.18,10.06,-1.52,1,52.58,32.19
+0,2021-09-05 14:24:05.075833,1,2,3,4,1191.36,118.1,10.09,0.7,1,54.53,32.17
+0,2021-09-05 14:24:39.308030,1,2,3,4,1184.1,118.24,10.01,4.69,1,52.1,32.17
diff --git a/ohmpi_param.json b/ohmpi_param.json
index b4b02832..e6f80b32 100644
--- a/ohmpi_param.json
+++ b/ohmpi_param.json
@@ -1,8 +1,8 @@
 {
     "nb_electrodes": 64,
-    "injection_duration": 0.5,
-    "nbr_meas": 1,
-    "sequence_delay": 10,
+    "injection_duration": 4,
+    "nbr_meas": 100,
+    "sequence_delay": 1,
     "stack": 1,
-    "export_path": "/home/pi/ohmpi1_5/measurement.csv" 
+    "export_path": "/home/pi/ohmpi/ohmpi/master/measurement.csv" 
 }
-- 
GitLab