Mezurit 2

Online documentation

This manual is also available in PDF format for offline viewing.

Warning: Both this page and the offline manual are quite . . . incomplete.

Table of Contents


Special formatting

Font type and color is used in this documentation to clarify and highlight some elements:

Keywords* associated with recurring concepts (defined below) compute function
Names of virtual instruments (called "tools" herein) or other sections of the GUI scope
Function names, function definitions, and filenames ADC(0,2)*1e-5
Terminal and Unix shell commands set_dac(1, 0.0)
Notes, tips, and technical details Note: ...
Warnings or important information Warning: ...
* These are a bit generic as jargon goes, so the highlighting is used to indicate the specific definition. Neal Stephenson's writing notwithstanding, this approach seems preferable to making up words like wafflesnorker or spweeble mode to describe various aspects of the software.


Mezurit 2 starts in setup mode, which allows the user to configure DAQ and GPIB hardware and define virtual channels to be acquired and recorded. The terminal is works in setup mode, but is limited to certain functions. When switching to panel mode Mezurit 2 completes the parsing phase, during which it parses the channel definitions and generates a list of physical channels and gpib slots to be measured. The parsing phase occurs each time Mezurit 2 switches from setup mode to panel mode or between panels.

The terminal is implemented as an instance of the Python interpreter running in a separate process from Mezurit 2 proper. Therefore, functions and variables defined in the terminal cannot be accessed by compute functions and vice versa. One advantage of this approach is that the terminal can hang, crash, or restart without affecting the time-sensitive data acquisition process.


Mezurit 2 runs three threads in panel mode, not counting the terminal process:

ThreadLoop rateJob
GUI~120 Hz Handles mouse clicks, key presses and updates the graphical interface. The only running thread in setup mode.
DAQ0.1-10 kHz Runs data acquisition, sweeps, triggers, and records data.
GPIB50 Hz Sends GPIB commands, waits, receives and scans replies.

Keyword definitions

Hardware and virtual channel setup

DAQ Hardware

Coming soon . . .

GPIB Hardware

Coming soon . . .

Virtual Channels

The standard channel functions are defined in /usr/lib/mezurit2/ This script imports low-level built-in channel functions as well as the standard Python math module, which includes sin(), cos(), etc. All of the standard channel functions are documented here.

Since version 0.81 user-defined functions can be added to ~/.config/mezurit2/ (or equivalent, see Installed files). This allows the user to add specific convenience functions, or to quickly add GPIB support for a new instrument, as described here.

Technical detail: All relevant channel functions must be evaluated at least once during the parsing phase to generate a complete set of physical channels and gpib slots. Thus, it is best not to use conditional statements e.g. "ADC(0,2) if time() > 10 else ADC(0,3)" in channel definitions.

Even more technical detail: Actually, Mezurit 2 can dynamically add physical channels and gpib slots after the parsing phase as they become relevant. However, such physical channels and gpib slots will not be reflected in the sanity check strings shown in the GUI. In addition, dynamically adding gpib slots has not been tested and may cause instability.

Panel tools


Coming soon . . .

DAC Controls

Coming soon . . .

More than one output can be set at the same time using followers (see set_follower()). When one channel is set to follow another channel, they are both updated on the same "tick" of the DAQ loop so there is minimal time delay. Followers work no matter what method is used to set the leader channel - sweeping, the "SET" button, or set_dac(). The user may supply a (possibly complicated) expression to tell Mezurit 2 how to compute the follower's target value. More than two channels can be linked by setting a third channel to "follow the follower," although care should taking to avoid any circular arrangements which could lead to undefined behavior (i.e. an infinite loop).

Example: Dual gates with differing efficiencies

virtual channel A quantity defined by an arbitrary function of zero or more physical channels or other parameters, often corresponding to a physical quantity present in the device under test or elsewhere in the experiment.
X1 = DAC(0, 0)
X2 = DAC(0, 1)
Command: set_follower(1, 2, '-3.0 * x')
Status: X2 = f(X1), f(x) = -3.0 * x, Valid? Y
Result: When gate voltage X1 is set to, e.g. 2.5 V, gate voltage X2 will be automatically set to -7.5V. For certain device geometries, this setup could be used to vary the lateral electric field while maintaining constant doping.


Coming soon . . .


Triggers are used to promptly preform actions, defined by calls to trigger functions, in response to an arbitrary event, defined by a trigger test. For example, one could automatically start a scope scan when a +5V TTL sync signal is received.

Triggers must be "armed" before they become active, either by clicking the "ARM" button or calling the arm_trigger() terminal function or the arm_trigger() trigger function. (The last method is useful for multi-stage events or to simply self-rearm.)

To set up a trigger, first define a trigger test in an "IF:" entry box. A trigger test must be a boolean expression constructed from a subset of the channel functions (typically time() or ch()). Next, define one or more (max 8) trigger functions in the entry boxes immediately below (next to the force button). Additional boxes can be made visible by clicking the "+" button. When the trigger is armed, this test expression will be evaluated every on every iteration of the DAQ loop. If and when it evaluates as True, Mezurit 2 will execute the trigger functions in order until one returns False or it reaches the end of the list.

Note: To define a trigger which executes immediately upon arming, simply supply True as the test.

Trigger functions are defined in /usr/lib/mezurit2/ The standard trigger functions are documented here. While in principle is it possible to define new trigger functions in ~/.config/mezurit2/, this is not recommended because the trigger tool is designed to execute only one function per line. In addition, because trigger functions execute in the DAQ thread, any hangups or errors in a trigger function could negatively affect the data acquisition process. The preferred way to execute more complex operations during a trigger event is to send a signal using emit_signal() to be caught by a terminal script using catch_signal().

Example: Oscilloscope-like operation

If: ch(4) > 2.5
Then: fire_scope()
Result: The scope will begin a scan when a sync signal represented by X4 rises above 2.5 V. The trigger will then rearm itself so that the data is refreshed every 0.1 seconds (assuming the scope is configured to scan for <0.1 seconds).

Triggers can be also be started manually ("forced") by clicking the force button or calling the force_trigger() terminal function or the force_trigger() trigger function.

Plotting and buffer management

Coming soon . . .

File chooser

Coming soon . . .


The terminal provides a Python-based interface to Mezurit 2. Almost all aspects of the GUI can be controlled from the terminal, plus several "hidden" features only accessible from the terminal. In addition, all settings can be queried and modified using the get_var() and set_var() commands. The "key=value" syntax for these two functions matches that used in Mezurit 2's configuration files.

Example: Increase sweep rate by 10%

Commands: val = get_var('panel0_sweep1_rate_up')
set_var('panel0_sweep1_rate_up={0:f}'.format(float(val) * 1.1))
Result: The first command returns the value of rsweep for the second sweep section on Panel 0, e.g. '0.500000' given rsweep = 0.5 V/s. The second line converts the queried string to a floating-point value, increases it by 10%, combines the result with the variable name, and sends the new string (e.g. 'panel0_sweep1_rate_up=0.550000').

In the previous example, the user must know the variable name to be modified a priori, specifically the appropriate panel id and the sweep id. These values can also be queried using get_panel() and get_sweep_id(), and then formatted into a variable name as in the following example.

Example: Easy variable name generation

X2 = DAC(0, 0) / 100
X3 = DAC(0, 1) * 10
Commands: pid = get_panel()
sid = get_sweep_id(3)
set_var('panel{0:d}_sweep{1:d}_scaled_up={2:f}'.format(pid, sid, 24.0))
Result: Assuming panel 0 is the active page, pid = 0 and sid = 1 because X3 is the second invertible channel overall. The full string passed to set_var() is 'panel0_sweep1_scaled_up=24.000000' which will set the upper limit for sweeping X3 to 24.0.

The standard terminal commands are documented here. Additional features can be added to the terminal in two ways: user-defined terminal functions and "one-off" scripts:

User-defined functions

New functions definitions can be placed in ~/.config/mezurit2/ (or equivalent, see Installed files) building on the existing set of commands. Once the changes are made, simply restart the terminal process using either the quit() command or the "Terminal | Restart" menu option. This option works best when there is some degree of generality in the functions to be added so that it can be used for multiple measurements.

Example: Function to repeat a megasweep at multiple temperatures (ver. 0.81+)

Code: def gigasweep_temperature (sweep_ch, step_ch, V0, V1, N, basefile, temps) :
   for T in temps :
      gpib(0, 24, 'T{0:f}'.format(T), eos=0x400|0xd)
      megasweep_up(sweep_ch, step_ch, V0, V1, N, basefile + '_{0:f}K.dat'.format(T))
      clear_buffer(False, False)
Command: gigasweep(1, 2, -10.0, 10.0, 40, 'dev01_run01', (1.4, 2.5, 5.0, 10.0, 20.0))
Result: The megasweep is run five times at the specified temperatures, which are sent to an Oxford Temperature Controller using a GPIB command. Mezurit 2 waits 60 seconds for the temperature to settle before beginning each measurement. The data is saved in five separate files with names like dev01_run01_1.40000K.dat.


Another option is to place the desired commands in a custom script file, then run it via execfile(). The script will run in the current terminal as if a user had typed in each line directly. Note that, on its own, execfile() does not expand shortcuts such as ~ (relative paths are OK).

Example: Parametric megasweep

Code: (save to a known location such as /home/yourusername)
Command: execfile('/home/yourusername/')
Result: The sweep parameters are adjusted between voltage steps to produce a non-rectangular megasweep. See the script for details.

One advantage of this approach is that a copy of the script can be saved along with each datfile as documentation. For example, the script used to record dev02_run03.dat could be saved alongside as Another advantage is that the user does not have to remember what arguments to pass a custom function because every parameter must be mentioned explicitly in the script.


While some scripts may perform a measurement by simply sending a continuous stream of commands, it is often necessary to wait for certain conditions before continuing to the next step. This can be accomplished using the catch_* commands: catch_sweep() for sweeps, catch_scan_start() and catch_scan_finish() for scope scans, and catch_signal() for triggers.

Tip: Explicit synchronization is more reliable and precise than using xleep(). For example, while Mezurit 2 makes every effort to sweep at exactly the specified rate, jitter may creep in when starting and stopping due to synchronization between threads. Thus, waiting 1.0 seconds for a 1.0 second sweep could result in the script continuing on slightly "ahead of schedule."

Warning/Tip: These functions do not return until the specified event has occurred. If that event is never going to happen, i.e. due to user error, simply use the "Terminal | Abort" feature to regain control of the terminal.