Setup

In [14]:
from importlib import reload
import sys
from textwrap import dedent

from IPython.display import display_markdown

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

# Reload already loaded modules
for m in ("AD5522_pi", "AD7685_pi", "AD5522dev_pi"):
    try:
        mod = sys.modules[m]
    except KeyError:
        pass
    else:
        reload(mod)
from AD5522dev_pi import AD5522dev
from AD5522_pi import MeasMode
In [15]:
board = AD5522dev(vref=5.0)
currentranges = ("5µA", "20µA", "200µA", "2mA", "extres")

Calibration

There are three metrics to calibrate. The force offset, the force gain and the measurement offset. The calibration is to be done in the following order:

  1. gain error
  2. force offset
  3. measurement offset

For some calibration the channels have to be open, for other the channels have to be shorted:

  • open: current force offset, voltage gain, voltage measurement offset
  • shorted: voltage force offset, current gain error, current measurement offset

So the following procedure can be used to calibrate all these metrics:

  1. open all the channels
  2. calibrate voltage gain
  3. close all the channels
  4. calibrate voltage force offset
  5. calibrate current gain
  6. open all the channels
  7. calibrate current force offset
  8. calibrate voltage measurement offset
  9. close all the channels
  10. calibrate current measurement offset

Voltage gain

Open all the channels to run the voltage gain calibration.

In [3]:
voltagegain_out = tuple(
    board.calibrate_voltagegain(channel=channel) for channel in range(len(board.channels))
)
In [4]:
s = """
| Channel  | Gain error [V/V] | Offset [V] |
|----------|------------------|------------|
"""
for i, chout in enumerate(voltagegain_out):
    s += "| {} | {} | {} |\n".format(i, round(chout[0], 5), round(chout[1], 4))
display_markdown(s, raw=True)
Channel Gain error [V/V] Offset [V]
0 0.99995 -0.0001
1 1.0004 -0.0003
2 1.00082 0.0001
3 1.00048 0.0007

Voltage force offset

Short the channels to run the volage offset calibration.

In [5]:
voltageoffset_out = tuple(board.calibrate_voltageoffset(channel=channel) for channel in range(len(board.channels)))
In [6]:
s = """
| Channel | Offset [lsbV] | Verif. |
|---------|---------------|--------|
"""
for i, chout in enumerate(voltageoffset_out):
    s += "| {} | {} | {} |\n".format(i, chout[0], "OK" if chout[1] else "**NOK**")
display_markdown(s, raw=True)
Channel Offset [lsbV] Verif.
0 349 OK
1 318 OK
2 340 OK
3 318 OK

Current gain

Keep the channels shorted to run the current gain calibration.

In [7]:
currentgain_out = tuple(
    tuple(
        (currentrange, *board.calibrate_currentgain(channel=channel, currentrange=currentrange))
        for currentrange in currentranges
    )
    
    for channel in range(len(board.channels))
)
In [8]:
s = ""
for i, chout in enumerate(currentgain_out):
    s += dedent("""
    ### Channel {}
    | Range | Gain error [A/A] | Offset [µA] |
    |-------|------------------|-------------|
    """.format(i))
    for irange, gain, offset in chout:
        s += "| {} | {} | {} |\n".format(irange, round(gain, 5), round(1e6*offset, 4))
display_markdown(s, raw=True)

Channel 0

Range Gain error [A/A] Offset [µA]
5µA 0.99996 0.0001
20µA 0.99997 0.0004
200µA 1.0 0.0085
2mA 0.99997 0.145
extres 0.99998 0.5

Channel 1

Range Gain error [A/A] Offset [µA]
5µA 0.99979 0.0001
20µA 0.99982 0.0014
200µA 0.99978 0.015
2mA 0.99979 0.06
extres 0.99979 0.4

Channel 2

Range Gain error [A/A] Offset [µA]
5µA 0.99969 0.0002
20µA 0.99968 0.0016
200µA 0.9997 0.0035
2mA 0.99969 0.09
extres 0.9997 0.5

Channel 3

Range Gain error [A/A] Offset [µA]
5µA 0.99992 0.0007
20µA 0.99991 0.0013
200µA 0.99993 0.0215
2mA 0.9999 0.175
extres 0.99989 0.9

Current force offset

Open all the channels before running the current offset calibration procedure.

In [9]:
currentoffset_out = tuple(
    board.calibrate_currentoffset(channel=channel)
    for channel in range(len(board.channels))
)
In [10]:
ranges = tuple(rangeverif[0] for rangeverif in currentoffset_out[0][1])
s = "| Channel | Offset [lsbA] | " + " | ".join(range for range in ranges) + " |\n"
s += "|" + (len(ranges) + 2)*"-|" + "\n"
for i, (offset, verif) in enumerate(currentoffset_out):
    s += (
        "| {} | {} | ".format(i, offset)
        + " | ".join("OK" if v[1] else "**NOK**" for v in verif)
        + " |\n"
    )
display_markdown(s, raw=True)
Channel Offset [lsbA] 5µA 20µA 200µA 2mA extres
0 312 OK OK OK OK OK
1 277 OK OK OK OK OK
2 277 OK OK OK OK OK
3 260 OK OK OK OK OK

Forced voltage measurement offset

Keep all the channels open for running the voltage measurment offset calibration procedure.

In [19]:
voltagemeasoffset_out = tuple(
    {
        currentrange: board.calibrate_measoffset_fv(channel=channel, currentrange=currentrange)
        for currentrange in currentranges
    }
    for channel in range(len(board.channels))
)
In [24]:
s = "**Voltage offset**\n\n"
s += "| Channel | " + " | ".join(currentranges) + " |\n"
s += "|" + (len(currentranges) + 1)*"-|" + "\n"
for i, offsets in enumerate(voltagemeasoffset_out):
    s += "| {} | {} |\n".format(
        i, " | ".join(str(offsets[currentrange][0]) for currentrange in currentranges),
    )
s += "\n**Current offset**\n\n"
s += "| Channel | " + " | ".join(currentranges) + " |\n"
s += "|" + (len(currentranges) + 1)*"-|" + "\n"
for i, offsets in enumerate(voltagemeasoffset_out):
    s += "| {} | {} |\n".format(
        i, " | ".join(str(offsets[currentrange][1]) for currentrange in currentranges),
    )
display_markdown(s, raw=True)

Voltage offset

Channel 5µA 20µA 200µA 2mA extres
0 0.0232 0.0231 0.0231 0.0232 0.0231
1 0.0238 0.0238 0.0238 0.0239 0.0238
2 0.0194 0.0194 0.0194 0.0195 0.0194
3 0.0218 0.0217 0.0218 0.0218 0.0218

Current offset

Channel 5µA 20µA 200µA 2mA extres
0 9.53e-09 3.97e-08 3.97e-07 3.72e-06 1.83e-05
1 1.624e-08 6.51e-08 6.36e-07 6.11e-06 3.05e-05
2 9.98e-09 4.24e-08 4.26e-07 3.87e-06 1.88e-05
3 7.66e-09 3.13e-08 3.06e-07 2.8e-06 1.39e-05

Forced current measurement offset

Finally close all the channels to run the current measurement offset calibration procedure.

In [37]:
currentmeasoffset_out = tuple(
    {
        currentrange: board.calibrate_measoffset_fi(channel=channel, currentrange=currentrange)
        for currentrange in currentranges
    }
    for channel in range(len(board.channels))
)
In [38]:
s = "**Voltage offset**\n\n"
s += "| Channel | " + " | ".join(currentranges) + " |\n"
s += "|" + (len(currentranges) + 1)*"-|" + "\n"
for i, offsets in enumerate(currentmeasoffset_out):
    s += "| {} | ".format(i) + " | ".join(
        str(offsets[currentrange][0]) for currentrange in currentranges
    ) + " |\n"
s += "\n**Current offset**\n\n"
s += "| Channel | " + " | ".join(currentranges) + " |\n"
s += "|" + (len(currentranges) + 1)*"-|" + "\n"
for i, offsets in enumerate(currentmeasoffset_out):
    s += "| {} | ".format(i) + " | ".join(
        "{:.4e}".format(offsets[currentrange][1]) for currentrange in currentranges
    ) + " |\n"
display_markdown(s, raw=True)

Voltage offset

Channel 5µA 20µA 200µA 2mA extres
0 0.0224 0.0223 0.0223 0.0224 0.0223
1 0.0229 0.0229 0.0229 0.0229 0.023
2 0.0187 0.0188 0.0188 0.0188 0.0188
3 0.021 0.021 0.021 0.021 0.021

Current offset

Channel 5µA 20µA 200µA 2mA extres
0 9.7100e-09 3.8700e-08 3.7400e-07 3.8900e-06 1.9500e-05
1 1.6220e-08 6.3500e-08 6.4800e-07 6.4800e-06 3.2400e-05
2 9.6900e-09 3.8800e-08 3.8800e-07 3.8900e-06 1.9500e-05
3 7.0400e-09 2.8200e-08 2.6800e-07 2.8200e-06 1.4800e-05

Debug

In [18]:
# print(board.calibrate_currentoffset(channel=0, debug=True))
# print(board.calibrate_voltageoffset(channel=1, debug=True))
# print(board.calibrate_voltagegain(channel=1, debug=True))
# print(board.calibrate_currentgain(channel=1, currentrange="20µA", debug=True))
# for currentrange in ("5µA", "extres"):
#     print(currentrange)
#     print(board.calibrate_measoffset_fv(channel=0, currentrange=currentrange, debug=True))
# for currentrange in ("5µA", "2mA", "extres"):
#     print(currentrange)
#     print(board.calibrate_measoffset_fi(channel=0, currentrange="5µA", debug=True))