Commit 0e59bbe8 authored by Guillaume Blanchy's avatar Guillaume Blanchy
Browse files

add auto doc from API reference

Showing with 74 additions and 337 deletions
+74 -337
......@@ -6,15 +6,16 @@ pages:
script:
- apt-get update
- apt-get install --assume-yes pandoc
- pip install sphinx numpydoc sphinx_rtd_theme sphinx_nbexamples pandoc
- pip install numpy pandas termcolor # top import of Ohmpi.py
- pip install sphinx numpydoc sphinx_rtd_theme pandoc recommonmark
- cd doc
- make html
# also make latex? pdf?
- cd ..
- mv doc/_build_html/ public/
- mv doc/build/html/ public/
- ls public/
artifacts:
paths:
- public/
only:
- master
\ No newline at end of file
- master
# -*- coding: utf-8 -*-
"""
created on January 6, 2020
Update February 2022
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), and Yannick FARGIER (IFSTTAR).
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), Yannick FARGIER (IFSTTAR)
and Guillaume BLANCHY (ILVO).
"""
VERSION = '2.0.0'
......@@ -28,16 +30,6 @@ from datetime import datetime
from termcolor import colored
import threading
if True:
import board, busio, adafruit_tca9548a
import adafruit_ads1x15.ads1115 as ADS
from adafruit_ads1x15.analog_in import AnalogIn
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"))
......@@ -50,22 +42,22 @@ print(current_time.strftime("%Y-%m-%d %H:%M:%S"))
class OhmPi(object):
"""Create the main OhmPi object.
Parameters
----------
config : str, optional
Path to the .json configuration file.
sequence : str, optional
Path to the .txt where the sequence is read. By default, a 1 quadrupole
sequence: 1, 2, 3, 4 is used.
onpi : bool, optional
True if running on the RaspberryPi. False for testing (random data generated).
output : str, optional
Either 'print' for a console output or 'mqtt' for publication onto
MQTT broker.
"""
def __init__(self, config=None, sequence=None, onpi=True, output='print'):
"""Create the main OhmPi object.
Parameters
----------
config : str, optional
Path to the .json configuration file.
sequence : str, optional
Path to the .txt where the sequence is read. By default, a 1 quadrupole
sequence: 1, 2, 3, 4 is used.
onpi : bool, optional
True if running on the RaspberryPi. False for testing (random data generated).
output : str, optional
Either 'print' for a console output or 'mqtt' for publication onto
MQTT broker.
"""
# flags and attributes
self.onpi = onpi # True if run from the RaspberryPi with the hardware, otherwise False for random data
self.output = output # type of output print
......@@ -73,6 +65,18 @@ class OhmPi(object):
self.run = False # flag is True when measuring
self.thread = None # contains the handle for the thread taking the measurement
self.path = 'data/' # wher to save the .csv
# finish import (done only when class is instantiated as some libs are
# only available on arm64 platform)
if self.onpi:
import board, busio, adafruit_tca9548a
import adafruit_ads1x15.ads1115 as ADS
from adafruit_ads1x15.analog_in import AnalogIn
from adafruit_mcp230xx.mcp23008 import MCP23008
from adafruit_mcp230xx.mcp23017 import MCP23017
import digitalio
from digitalio import Direction
from gpiozero import CPUTemperature
# read in hardware parameters (seetings.py)
self._read_hardware_parameters()
......@@ -590,8 +594,8 @@ class OhmPi(object):
self.dump('status = ' + self.status)
# test
ohmpi = OhmPi(config='ohmpi_param.json')
ohmpi.measure()
time.sleep(4)
ohmpi.stop()
#ohmpi = OhmPi(config='ohmpi_param.json')
#ohmpi.measure()
#time.sleep(4)
#ohmpi.stop()
"""
created on september , 2021
Update september 2021
Ohmpi_4elec.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.01')
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
from termcolor import colored
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 = 2# reference resistance value in ohm
Imax=4800/50/2
print(colored(('The maximum current cannot be higher than ',Imax, 'mA'), 'red'))
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=2 #Max value 10
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=128, address=0X48)# connexion ADS1115, pour la mesure de courant
ads_voltage = ADS.ADS1115(i2c, gain=2/3,data_rate=128, 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()#stating measurement time
time.sleep(injection_deltat) # delay depending on current injection duration
# mesureament of i and u
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
cpu = CPUTemperature()
end_calc=time.time()
time.sleep(2*(end_delay-start_delay)-(end_calc-start_delay))
#end_sleep2=time.time()
#print(['sleep=',((end_sleep2-start_delay))])
#print(['true delta=',((end_delay-start_delay)-injection_deltat)])
#print(['time stop=',((2*(end_delay-start_delay)-(end_calc-start_delay)))])
# return averaged values
# cpu= CPUTemperature()
output = DataFrame({
"time":[datetime.now()],
"A":[(1)],
"B":[(2)],
"M":[(3)],
"N":[(4)],
"inj time [ms]" : (end_delay-start_delay)*1000,
"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())],
"Integer [-]": [integer]
# 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)
# to test documentation build using same environemnet as gitlab doc runner
docker run -it -v /media/jkl/data/ilvo/ohmpi/OhmP:/OhmPi python:3.9-bullseye bash
# -*- coding: utf-8 -*-
"""
Created on Mon Jul 13 21:48:00 2020
@author: remi.clement
"""
import shutil
......@@ -13,12 +13,12 @@ OhmPi project
**Authors:**
------------
| Rémi CLEMENT,Vivien DUBOIS,Nicolas Forquet, INRAE, REVERSAAL, Villeurbanne, France.
| Yannick FARGIER, GERS-RRO, Univ Gustave Eiffel, IFSTTAR, Lyon, France.
| Julien GANCE, IRIS Instruments, Orléans, France.
| Hélène GUYARD, IGE Grenoble, Université Grenoble Alpes, Grenoble, France.
| Rémi CLEMENT,Vivien DUBOIS,Nicolas Forquet, INRAE, REVERSAAL, Villeurbanne, France
| Yannick FARGIER, GERS-RRO, Univ Gustave Eiffel, IFSTTAR, Lyon, France
| Julien GANCE, IRIS Instruments, Orléans, France
| Hélène GUYARD, IGE Grenoble, Université Grenoble Alpes, Grenoble, France
| Olivier Kaufmann, Université de Mons, Mons, Belgium
| Guillaume Banchy, ILVO,Merelbeke, Belgium
| Guillaume Banchy, ILVO, Merelbeke, Belgium
|
......@@ -62,4 +62,4 @@ to the near surface scientific community.
.. note::
Everyone willing to get involved is welcome in OhmPi Project!.
\ No newline at end of file
Everyone willing to get involved is welcome in OhmPi Project!.
API reference
=============
.. toctree::
:maxdepth: 2
:caption: Contents:
.. automodule:: Ohmpi
:members:
# -*- coding: utf-8 -*-
# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
......@@ -12,15 +14,16 @@
#
import os
import sys
# sys.path.insert(0, os.path.abspath('.'))
sys.path.append(os.path.abspath('../..'))
import Ohmpi # import Ohmpi module to be documented in api.rst by numpydoc
import sphinx_rtd_theme
from shutil import copyfile
# -- Project information -----------------------------------------------------
project = 'Ohmpi:'
copyright = '2022, INRAE, Team Ohmpi'
project = 'OhmPi'
copyright = '2022, INRAE, Team OhmPi'
author = 'Rémi CLEMENT'
# The full version, including alpha/beta/rc tags
......@@ -30,8 +33,17 @@ release = 'open hardware resistivity-meter'
# -- General configuration ---------------------------------------------------
extensions = ['recommonmark']
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.coverage',
'sphinx.ext.mathjax',
'numpydoc',
'recommonmark'
]
numpydoc_show_class_members = False
# Add any paths that contain templates here, relative to this directory.
......
......@@ -37,6 +37,7 @@ Contents:
V1_01
V1_02
V2_00
api
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment