Calkit user manual


Over the last few years we were getting multiple requests about automating measurements and running experiments with precision multimeters and instruments, include remote control. There are multiple ways to achieve the task and get simple script to configure single DMM and datalog samples into text file or CSV file. And whole different thing is to have more or less versatile application, that can do essentially most of things than user can do in front the instruments.

Also different instruments have own language/command sets, even often when instrument made by same manufacturer. SCPI language is the step in right direction to unify command sets, but there are still differences.

One aspect that really can benefit from automating is calibration procedures. Most of modern multimeter have lot of functions and multiple ranges within each function. And calibration of each range usually consist of two points, near zero and near full-scale. As result even with all equipment available, calibration and adjustment of typical bench-top meter, such as 6½-digit Keithley 2000 or Agilent 34401A will take hours or more, and require careful entering of many numbers using often non-convinient front panel. Remote automated script to perform performance test and calibration adjustment can be a big time saver in such case.

Professional calibration labs are very commonly have one of the commercial calibration software systems integrated to their work-flow. Fluke MET/CAL service is perhaps one of the most known. However cost of this software (thousands USD/year) and it’s support license is out of reach of occasional enthusiast, who just need calibrate few meters for own use.

So we saw this as an opportunity to develop some piece of software, which will run on Linux machine, such as popular Raspberry Pi 3 + linux-gpib to perform the communication and remote control of calibrator source and DUT meter to do performance verification and then optional calibration adjustment. Software is written in python programming language, and supports only limited number of instruments which we own. But before we dig in into the thing, it’s important to refresh some terms used across this article:

Terms glossary

Calibrator – Source that provide stable reference signal with known uncertainty, used as a reference for tests/adjustments

Calibration – Verification of unknown unit under test measurement reading against reference signal with known uncertainty. Calibration does NOT include adjustment or altering of stored calibration offset/gain correction constants in DUT.

Adjustment – Adjust UUT to reduce measurement errors, by running manufacturer recommended procedures to update DUT’s correction constants, often stored in instrument’s non-volatile RAM.

Calibrated range/function – Range/Function of the DUT that have known and verified error. True measurement can be mathematically determined by application of correction factor to account for error.

Transfer – Process of establishing error on DUT range/function by using known signal and known error in verified range/function. For example 3.0000 V measurement accuracy can be transferred to 10V range, if reference error is verified on calibrated 3V range.

Calkit minimum requirements

Software control system requirements are rather simple:

  • Raspberry Pi 3 or another similar Linux-based SBC that have USB interface for linux-gpib.
  • NI GPIB-USB-HS or Agilent 83527B dongle for interfacing GPIB instrumentation network
  • Internet connection for data synchronization and procedures update
  • Reference source / calibrator
  • DUT device

Well, no intro required
You have calkit on your pi in folder /root/xdevs_calkit

Calkit supported devices

Sources for signals

  • Fluke 5700A multifunction calibrator
  • Fluke 5700A/EP multifunction calibrator
  • Fluke 5720A multifunction calibrator
  • Fluke 5730A multifunction calibrator
  • Datron 4808 multifunction calibrator
  • Time Electronics 9823 multifunction calibrator
  • Fluke 5450A resistance calibrator
  • HP 3245A universal source

DUT devices and multimeters

  • HP/Agilent/Keysight 34401A
  • HP/Agilent/Keysight 34420A
  • HP/Agilent/Keysight 3456A
  • HP/Agilent/Keysight 3457A
  • HP/Agilent/Keysight 3458A
  • Keithley 2002
  • Keithley 2001
  • Keithley 2001/1801
  • Keithley 2000
  • Keithley 2182 and 2182A
  • Keithley 182
  • Datron/Wavetek 1281
  • Datron/Wavetek 4920
  • Datron/Wavetek 4920M
  • Fluke 5790A
  • Fluke 8508A
  • Fluke 8588A
  • Advantest R6581T

GPIB interfaces

  • NI USB-GPIB-HS or USB-GPIB-HS+ dongle
  • Agilent 82357B dongle
  • HP/Agilent/Keysight E5810A or E5810B
  • VXI/LXI interfaces

Environment sensors

  • BME280 THP sensor
  • Fluke 1620 THP logger

Software tree

\.hg – Mercurial repository storage
\css – Styles for report HTML
\sensors – Module for sensors, currently just Adafruit BME280 I2C
\.hgignore – Repository file to ignore local temporary files
\ – This is main entry root programm. Contains menu prompts and help placeholders
\ – This is main high level procedure to run on DUT and standards
\ – AC-related copy of, currently only for 5700+4920M. To be merged in future
\ – This is wrapper to specific low-level DUT functions
\ – This is wrapper to specific low-level AC DUT functions
\ – Low-level support module for Fluke 5700A MFC
\ – Low-level support module for Fluke 5720A MFC
\ – Low-level support module for Fluke 5790A AVMS, broken
\ – Low-level support module for HP 3458
\ – Low-level support module for BME280 sensor
\ – Low-level inteface simulate, to dump commands into debug log file
\ – Low-level inteface to linux-gpib
\ – Low-level support module for Keithley 2001
\ – Low-level support module for Keithley 2002
\ – Markup module for HTML generator
\ – This is wrapper to specific low-level MFC source functions
\ – Low-level support module for signal generator
\ – Low-level support module for Time Electronics 9823 MFC
\ – Low-level support module for Wavetek Datron 4920 AVMS
\ – Low-level support module for Wavetek Datron 4920M AVMS


CK depends on few packages in system:

  • Python 2.7
  • Working linux-gpib with python binding
  • BME280 sensor at I2C port

Only GPIB instruments are supported now. Specific instruments GPIB addresses are hardcoded in low-level files.
For example we want to run HP3458A tests with Fluke 5700A MFC as source.

GPIB address 1 for calibrator is set on line 101.

intf = gpib(1,"F5700")

Similar setting for GPIB address 3 is for DMM DUT, line 103:

intf = gpib(3,"3458A")

Now we can run program:
root@de1soclinux:/repo/calkit# python ./ calibration toolkit CLI
  Using NI GPIB adapter and linux-gpib library
 /!\ Do not swap terminals during calibration/tests, LETHAL voltage may be present !
[0] - Help guide
[1] - Detect instruments
[2] - Initialize instruments
[3] - Select DUT
[4] - Run performance verification procedure on DUT
[5] - Run user calibration procedure on DUT
[6] - Run manufacturer calibration procedure on DUT
[7] - Generate HTML report
[8] - Check on calibrator F5700
[9] - Check on AVMS F5790
[10] - Performance test W4920M
[11] - User calibration W4920M
[12] - Run calibration check procedure w/reports (CAL CHK) on F5700/5720
[13] - Generate just calibration reports
[14] - Low-level manufacturing calibration W4920M
[15] - Program HP 3325 to output 3V 100kHz sine, GPIB 14
[X] - Quit

Item number 12 will talk with Fluke 5700A to collect all reports into local file:


Then it will run CAL ZERO and CAL CHK procedures which takes about an hour to complete. Program have timer to wait and will show you remaining time to finish.
After calibrator completes it’s test new set of reports is readback and appended to files:


This allow to monitor all values before and after self-check and zero self-calibration.

If only report required without actual running CAL CHK for 1 hour, one can just run Item 13.

Now let’s preconfigure HP 3458A run item 3 – it resets meter and prepares it for use.
Programm will run commands and show them on screen with WRG messages:

Initialize HP 3458A
-WRG- NPLC 100

Main entry to run performance test procedure on the HP 3458A to execute Menu item 7.
This will collect status and information about MFC and DMM and proceed with testing.
To do so will enter cal_report() function in file, which will in turn look onto and to access lower-level device-specific code.

In current we see binding to Fluke 5700A MFC:

from f5700a import *
import time

# Module-wide definitions
mfc_mfg       = f5700_mfg_id
mfc_date      = time.strftime("%d %B %Y")
mfc_model     = f5700_model_id
mfc_ambient_t = "+27.3 °C"
mfc_serno     = "0"
mfc_rh        = "31 %"
mfc_idno      = "XC1"
mfc_testmode  = 0

Function names redefined accordingly here as well:

def mfc_out_dci():

def mfc_dormant():

def mfc_selfcal():

def mfc_report_aftercal():

mfc_uncert          = f5700_uncert
mfc_measout         = f5700_measout
mfc_selfcal         = f5700_selfcal
mfc_report_aftercal = f5700_report_aftercal
mfc_dormant         = f5700_dormant

Similar is for UUT, which is wrapped in

from hp3458a import *

# Module-wide definitions
dut_mfg       = hp3458_mfg_id
dut_date      = "02 Jan 2017"
dut_model     = hp3458_model_id
dut_ambient_t = "+25.5 °C"
#dut_serno     = "1167961"
dut_serno     = "B"
dut_rh        = "45.6 %"
dut_idno      = "B-test"
dut_testmode  = "PERFVAL"
dut_acv_ranges      = hp3458_acv_ranges
dut_acv_unc         = hp3458_acv_unc

Main code to execute specific performance tests is defined in low-level module of DUT – in our case –
Main function executed from is hp3458_perftest(). Let’s look closer on it:

    dutresult = []
    print ("\033[1;31m HP 3458B verification \033[1;39m")
    hp3458_vfd_on("CALKIT START...")
    dutresult.append(hp3458_reztest()) #0 Here we execute resistance short test
    dutresult.append(hp3458_restest()) #1 Here we execute resistance 4W test
    dutresult.append([1000000000.0])   #2 This is dummy for 1Gohm resistance test (need manual connections of 1G STD)
    dutresult.append(hp3458_dcztest()) #3 Here we execute DCV Zero test and noise check
    dutresult.append(hp3458_dcvtest()) #4 Here we execute DCV positive and negative test
    dutresult.append(hp3458_acztest()) #5 Here we execute AC Zero test (currently dummy)
    dutresult.append(hp3458_ana_acvtest()) #6 Here we execute AC Analog quick check
    dutresult.append(hp3458_sync_acvtest()) #7 Here we execute main AC SYNC test, with high voltage/frequency limits
    dutresult.append(hp3458_dcitest()) #4 Here we execute current test, need swap terminals

    with open("bm2_result.log", 'a') as dile:
        for ival in xrange (0, len(dutresult)):
            dile.write ("%d %s" % (ival, dutresult[ival]))
            dile.write ("\r\n")                   # This is storage for raw test results data
    return dutresult                              # Array of measured results returned to

Execution order of test is important, because data parser expects test data in specific array locations. Order and amount of tests defined in

duttest_item_str= ["DCV","ACV","LOACV","DCI","RES","1G","DCZ","ACZ","REZ"]
      dut_testid_map =  [    4,    6,      7,    8,    1,   2,    3,    5,   0]

As tests proceed, programm will ask you for specific operations, such as change front/rear terminals or swap cables for current measurements.
Be sure to check that calibrator does not source dangerous voltages before

Current HP 3458A test procedure:

Test started by entering Menu item 7. Self-test (75 seconds) and ACAL ALL (835 seconds) procedures will be executed prior to actual performance verification.
First test, using MFC’s zero output. Each test point is measured multiple times and only last sample is taken. There are also delays to allow instruments to settle.

External sense on MFC is ON
Select REAR SHORT 4W terminals and press ENTER

At this stage ohmic zero will be measured as reference point, using two ranges, 10 Ω and 10 KΩ

Configure OHMF range 10 with NPLC 0
OHMF 10.000000
-WRG- OHMF 10.000000
Set resistance to 1.00000000E+01 Ohm

Next step is resistance test, to measure MFC outputs from 1 Ω to 100 MΩ. 100 MΩ is measured without OCOMP.

Configure OHMF range 10000 with NPLC 100
OHMF 10000.000000
NPLC 100.000000
Set resistance to 1.00000000E+04 Ohm

After resistance test uncertainty from calibrator using UNCERT? command is collected. No measurements by 3458A done at this step.
Next test is DCV Zero checks on all ranges and noise check. Noise check is simply collecting multiple samples to check min-max deviation.
Then zero offset is measured and nulled using 3458A’s MATH NULL command. After this actual measurement points on DCV are taken, using both positive and negative voltages from calibrator, from 0.1V to 1000V.


Next is AC voltage test, following standard HP 3458A calibration report. 100 VAC range limited by frequency at 100kHz and for 1000V range is only single frequency point, 1kHz due to safety limitations.


Final test is DC current, from 100nA to 1.0A, both sourcing and sinking with MFC. Before beginning of test cable connections at DMM must be swapped, so prompt to do so will be given and program will wait for user confirmation.


After successful data collection, which takes about 20 minutes, the measurement data will be processed into HTML report page, such as cal_report_3458b2.html

Author: Team
Created: Jan. 2, 2017, 3:50 p.m.
Modified: Jan. 2, 2023, 10:32 p.m.